* qatar/master: FATE: use updated reference for aac-latm_stereo_to_51 avconv: use libavresample Add libavresample FATE: avoid channel mixing in lavf-dv_fmt Conflicts: Changelog Makefile cmdutils.c configure doc/APIchanges ffmpeg.c tests/lavf-regression.sh tests/ref/lavf/dv_fmt tests/ref/seek/lavf_dv
Unified · Split
| @@ -26,6 +26,7 @@ version next: · 25 unmodified lines | ||
| 26 | 26 | - drawtext video filter: fontconfig support |
| 27 | 27 | - ffmpeg -benchmark_all option |
| 28 | 28 | - super2xsai filter ported from libmpcodecs |
| 29 | +- add libavresample audio conversion library for compatibility | |
| 29 | 30 | |
| 30 | 31 | |
| 31 | 32 | version 0.10: |
| @@ -31,6 +31,7 @@ ALLMANPAGES = $(BASENAMES:%=%.1) · 30 unmodified lines | ||
| 31 | 31 | FFLIBS-$(CONFIG_AVDEVICE) += avdevice |
| 32 | 32 | FFLIBS-$(CONFIG_AVFILTER) += avfilter |
| 33 | 33 | FFLIBS-$(CONFIG_AVFORMAT) += avformat |
| 34 | +FFLIBS-$(CONFIG_AVRESAMPLE) += avresample | |
| 34 | 35 | FFLIBS-$(CONFIG_AVCODEC) += avcodec |
| 35 | 36 | FFLIBS-$(CONFIG_POSTPROC) += postproc |
| 36 | 37 | FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include "libavformat/avformat.h" |
| 33 | 33 | #include "libavfilter/avfilter.h" |
| 34 | 34 | #include "libavdevice/avdevice.h" |
| 35 | +#include "libavresample/avresample.h" | |
| 35 | 36 | #include "libswscale/swscale.h" |
| 36 | 37 | #include "libswresample/swresample.h" |
| 37 | 38 | #if CONFIG_POSTPROC |
| @@ -633,7 +634,8 @@ static int warned_cfg = 0; · 595 unmodified lines | ||
| 633 | 634 | const char *indent = flags & INDENT? " " : ""; \ |
| 634 | 635 | if (flags & SHOW_VERSION) { \ |
| 635 | 636 | unsigned int version = libname##_version(); \ |
| 636 | − av_log(NULL, level, "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n",\ | |
| 637 | + av_log(NULL, level, \ | |
| 638 | + "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n", \ | |
| 637 | 639 | indent, #libname, \ |
| 638 | 640 | LIB##LIBNAME##_VERSION_MAJOR, \ |
| 639 | 641 | LIB##LIBNAME##_VERSION_MINOR, \ |
| @@ -662,6 +664,7 @@ static void print_all_libs_info(int flags, int level) · 22 unmodified lines | ||
| 662 | 664 | PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); |
| 663 | 665 | PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); |
| 664 | 666 | PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); |
| 667 | +// PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level); | |
| 665 | 668 | PRINT_LIB_INFO(swscale, SWSCALE, flags, level); |
| 666 | 669 | PRINT_LIB_INFO(swresample,SWRESAMPLE, flags, level); |
| 667 | 670 | #if CONFIG_POSTPROC |
| @@ -20,7 +20,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR)))) · 19 unmodified lines | ||
| 20 | 20 | $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) |
| 21 | 21 | endif |
| 22 | 22 | |
| 23 | −ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample | |
| 23 | +ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample | |
| 24 | 24 | |
| 25 | 25 | # NASM requires -I path terminated with / |
| 26 | 26 | IFLAGS := -I. -I$(SRC_PATH)/ |
| @@ -112,6 +112,7 @@ Component options: · 111 unmodified lines | ||
| 112 | 112 | --disable-swscale disable libswscale build |
| 113 | 113 | --disable-postproc disable libpostproc build |
| 114 | 114 | --disable-avfilter disable video filter support [no] |
| 115 | + --disable-avresample disable libavresample build [no] | |
| 115 | 116 | --disable-pthreads disable pthreads [auto] |
| 116 | 117 | --disable-w32threads disable Win32 threads [auto] |
| 117 | 118 | --disable-os2threads disable OS/2 threads [auto] |
| @@ -1013,6 +1014,7 @@ CONFIG_LIST=" · 895 unmodified lines | ||
| 1013 | 1014 | avdevice |
| 1014 | 1015 | avfilter |
| 1015 | 1016 | avformat |
| 1017 | + avresample | |
| 1016 | 1018 | avisynth |
| 1017 | 1019 | bzlib |
| 1018 | 1020 | crystalhd |
| @@ -1870,6 +1872,7 @@ enable avcodec · 851 unmodified lines | ||
| 1870 | 1872 | enable avdevice |
| 1871 | 1873 | enable avfilter |
| 1872 | 1874 | enable avformat |
| 1875 | +enable avresample | |
| 1873 | 1876 | enable avutil |
| 1874 | 1877 | enable postproc |
| 1875 | 1878 | enable stripping |
| @@ -3724,6 +3727,7 @@ get_version LIBAVCODEC libavcodec/version.h · 1848 unmodified lines | ||
| 3724 | 3727 | get_version LIBAVDEVICE libavdevice/avdevice.h |
| 3725 | 3728 | get_version LIBAVFILTER libavfilter/version.h |
| 3726 | 3729 | get_version LIBAVFORMAT libavformat/version.h |
| 3730 | +get_version LIBAVRESAMPLE libavresample/version.h | |
| 3727 | 3731 | get_version LIBAVUTIL libavutil/avutil.h |
| 3728 | 3732 | get_version LIBPOSTPROC libpostproc/postprocess.h |
| 3729 | 3733 | get_version LIBSWRESAMPLE libswresample/swresample.h |
| @@ -3869,5 +3873,6 @@ pkgconfig_generate libavformat "FFmpeg container format library" "$LIBAVFORMAT_V · 139 unmodified lines | ||
| 3869 | 3873 | pkgconfig_generate libavdevice "FFmpeg device handling library" "$LIBAVDEVICE_VERSION" "$extralibs" "$libavdevice_pc_deps" |
| 3870 | 3874 | pkgconfig_generate libavfilter "FFmpeg video filtering library" "$LIBAVFILTER_VERSION" "$extralibs" "$libavfilter_pc_deps" |
| 3871 | 3875 | pkgconfig_generate libpostproc "FFmpeg postprocessing library" "$LIBPOSTPROC_VERSION" "" "libavutil = $LIBAVUTIL_VERSION" |
| 3876 | +pkgconfig_generate libavresample "Libav audio resampling library" "$LIBAVRESAMPLE_VERSION" "$extralibs" | |
| 3872 | 3877 | pkgconfig_generate libswscale "FFmpeg image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" |
| 3873 | 3878 | pkgconfig_generate libswresample "FFmpeg audio rescaling library" "$LIBSWRESAMPLE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" |
| @@ -6,6 +6,7 @@ libavcodec: 2012-01-27 · 5 unmodified lines | ||
| 6 | 6 | libavdevice: 2011-04-18 |
| 7 | 7 | libavfilter: 2011-04-18 |
| 8 | 8 | libavformat: 2012-01-27 |
| 9 | +libavresample: 2012-xx-xx | |
| 9 | 10 | libpostproc: 2011-04-18 |
| 10 | 11 | libswscale: 2011-06-20 |
| 11 | 12 | libavutil: 2011-04-18 |
| @@ -22,6 +23,9 @@ API changes, most recent first: · 10 unmodified lines | ||
| 22 | 23 | 2012-03-26 - a67d9cf - lavfi 2.66.100 |
| 23 | 24 | Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions. |
| 24 | 25 | |
| 26 | +2012-xx-xx - xxxxxxx - lavr 0.0.0 | |
| 27 | + Add libavresample audio conversion library | |
| 28 | + | |
| 25 | 29 | 2012-xx-xx - xxxxxxx - lavu 51.28.0 - audio_fifo.h |
| 26 | 30 | Add audio FIFO functions: |
| 27 | 31 | av_audio_fifo_free() |
| @@ -36,7 +36,6 @@ · 35 unmodified lines | ||
| 36 | 36 | #include "libavdevice/avdevice.h" |
| 37 | 37 | #include "libswscale/swscale.h" |
| 38 | 38 | #include "libavutil/opt.h" |
| 39 | −#include "libavcodec/audioconvert.h" | |
| 40 | 39 | #include "libavutil/audioconvert.h" |
| 41 | 40 | #include "libavutil/parseutils.h" |
| 42 | 41 | #include "libavutil/samplefmt.h" |
| @@ -300,6 +299,7 @@ typedef struct OutputStream { · 257 unmodified lines | ||
| 300 | 299 | int audio_channels_mapped; ///< number of channels in audio_channels_map |
| 301 | 300 | int resample_sample_fmt; |
| 302 | 301 | int resample_channels; |
| 302 | + uint64_t resample_channel_layout; | |
| 303 | 303 | int resample_sample_rate; |
| 304 | 304 | float rematrix_volume; |
| 305 | 305 | AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ |
| @@ -1525,7 +1525,7 @@ static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, · 1219 unmodified lines | ||
| 1525 | 1525 | } |
| 1526 | 1526 | |
| 1527 | 1527 | static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, |
| 1528 | − int nb_samples) | |
| 1528 | + int nb_samples, int *buf_linesize) | |
| 1529 | 1529 | { |
| 1530 | 1530 | int64_t audio_buf_samples; |
| 1531 | 1531 | int audio_buf_size; |
| @@ -1538,7 +1538,7 @@ static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, · 6 unmodified lines | ||
| 1538 | 1538 | if (audio_buf_samples > INT_MAX) |
| 1539 | 1539 | return AVERROR(EINVAL); |
| 1540 | 1540 | |
| 1541 | − audio_buf_size = av_samples_get_buffer_size(NULL, enc->channels, | |
| 1541 | + audio_buf_size = av_samples_get_buffer_size(buf_linesize, enc->channels, | |
| 1542 | 1542 | audio_buf_samples, |
| 1543 | 1543 | enc->sample_fmt, 0); |
| 1544 | 1544 | if (audio_buf_size < 0) |
| @@ -1557,7 +1557,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 12 unmodified lines | ||
| 1557 | 1557 | uint8_t *buftmp; |
| 1558 | 1558 | int64_t size_out; |
| 1559 | 1559 | |
| 1560 | − int frame_bytes, resample_changed; | |
| 1560 | + int frame_bytes, resample_changed, ret; | |
| 1561 | 1561 | AVCodecContext *enc = ost->st->codec; |
| 1562 | 1562 | AVCodecContext *dec = ist->st->codec; |
| 1563 | 1563 | int osize = av_get_bytes_per_sample(enc->sample_fmt); |
| @@ -1566,37 +1566,46 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 2 unmodified lines | ||
| 1566 | 1566 | int size = decoded_frame->nb_samples * dec->channels * isize; |
| 1567 | 1567 | int planes = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1; |
| 1568 | 1568 | int i; |
| 1569 | + int out_linesize = 0; | |
| 1570 | + int buf_linesize = decoded_frame->linesize[0]; | |
| 1569 | 1571 | |
| 1570 | 1572 | av_assert0(planes <= AV_NUM_DATA_POINTERS); |
| 1571 | 1573 | |
| 1572 | 1574 | for(i=0; i<planes; i++) |
| 1573 | 1575 | buf[i]= decoded_frame->data[i]; |
| 1574 | 1576 | |
| 1577 | + | |
| 1575 | 1578 | get_default_channel_layouts(ost, ist); |
| 1576 | 1579 | |
| 1577 | − if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples) < 0) { | |
| 1580 | + if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples, &out_linesize) < 0) { | |
| 1578 | 1581 | av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); |
| 1579 | 1582 | exit_program(1); |
| 1580 | 1583 | } |
| 1581 | 1584 | |
| 1582 | − if (enc->channels != dec->channels | |
| 1583 | − || enc->sample_fmt != dec->sample_fmt | |
| 1584 | − || enc->sample_rate!= dec->sample_rate | |
| 1585 | − ) | |
| 1585 | + if (audio_sync_method > 1 || | |
| 1586 | + enc->channels != dec->channels || | |
| 1587 | + enc->channel_layout != dec->channel_layout || | |
| 1588 | + enc->sample_rate != dec->sample_rate || | |
| 1589 | + dec->sample_fmt != enc->sample_fmt) | |
| 1586 | 1590 | ost->audio_resample = 1; |
| 1587 | 1591 | |
| 1588 | 1592 | resample_changed = ost->resample_sample_fmt != dec->sample_fmt || |
| 1589 | 1593 | ost->resample_channels != dec->channels || |
| 1594 | + ost->resample_channel_layout != dec->channel_layout || | |
| 1590 | 1595 | ost->resample_sample_rate != dec->sample_rate; |
| 1591 | 1596 | |
| 1592 | 1597 | if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) { |
| 1598 | + | |
| 1593 | 1599 | if (resample_changed) { |
| 1594 | − av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n", | |
| 1600 | + av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:0x%"PRIx64" to rate:%d fmt:%s ch:%d chl:0x%"PRIx64"\n", | |
| 1595 | 1601 | ist->file_index, ist->st->index, |
| 1596 | − ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), ost->resample_channels, | |
| 1597 | − dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels); | |
| 1602 | + ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), | |
| 1603 | + ost->resample_channels, ost->resample_channel_layout, | |
| 1604 | + dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), | |
| 1605 | + dec->channels, dec->channel_layout); | |
| 1598 | 1606 | ost->resample_sample_fmt = dec->sample_fmt; |
| 1599 | 1607 | ost->resample_channels = dec->channels; |
| 1608 | + ost->resample_channel_layout = dec->channel_layout; | |
| 1600 | 1609 | ost->resample_sample_rate = dec->sample_rate; |
| 1601 | 1610 | swr_free(&ost->swr); |
| 1602 | 1611 | } |
| @@ -1604,6 +1613,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 1 unmodified line | ||
| 1604 | 1613 | if (audio_sync_method <= 1 && !ost->audio_channels_mapped && |
| 1605 | 1614 | ost->resample_sample_fmt == enc->sample_fmt && |
| 1606 | 1615 | ost->resample_channels == enc->channels && |
| 1616 | + ost->resample_channel_layout == enc->channel_layout && | |
| 1607 | 1617 | ost->resample_sample_rate == enc->sample_rate) { |
| 1608 | 1618 | //ost->swr = NULL; |
| 1609 | 1619 | ost->audio_resample = 0; |
| @@ -1673,7 +1683,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 63 unmodified lines | ||
| 1673 | 1683 | exit_program(1); |
| 1674 | 1684 | } |
| 1675 | 1685 | |
| 1676 | − if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta) < 0) { | |
| 1686 | + if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta, &out_linesize) < 0) { | |
| 1677 | 1687 | av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); |
| 1678 | 1688 | exit_program(1); |
| 1679 | 1689 | } |
| @@ -1686,11 +1696,11 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 6 unmodified lines | ||
| 1686 | 1696 | buf[i] = t; |
| 1687 | 1697 | } |
| 1688 | 1698 | size += byte_delta; |
| 1699 | + buf_linesize = allocated_async_buf_size; | |
| 1689 | 1700 | av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); |
| 1690 | 1701 | } |
| 1691 | 1702 | } else if (audio_sync_method > 1) { |
| 1692 | 1703 | int comp = av_clip(delta, -audio_sync_method, audio_sync_method); |
| 1693 | − av_assert0(ost->audio_resample); | |
| 1694 | 1704 | av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", |
| 1695 | 1705 | delta, comp, enc->sample_rate); |
| 1696 | 1706 | // fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2)); |
| @@ -1703,8 +1713,10 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 6 unmodified lines | ||
| 1703 | 1713 | |
| 1704 | 1714 | if (ost->audio_resample || ost->audio_channels_mapped) { |
| 1705 | 1715 | buftmp = audio_buf; |
| 1706 | − size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, allocated_audio_buf_size / (enc->channels * osize), | |
| 1707 | − buf, size / (dec->channels * isize)); | |
| 1716 | + size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, | |
| 1717 | + allocated_audio_buf_size / (enc->channels * osize), | |
| 1718 | + buf, | |
| 1719 | + size / (dec->channels * isize)); | |
| 1708 | 1720 | if (size_out < 0) { |
| 1709 | 1721 | av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n"); |
| 1710 | 1722 | exit_program(1); |
| @@ -3078,6 +3090,7 @@ static int transcode_init(void) · 1367 unmodified lines | ||
| 3078 | 3090 | if (!ost->fifo) { |
| 3079 | 3091 | return AVERROR(ENOMEM); |
| 3080 | 3092 | } |
| 3093 | + | |
| 3081 | 3094 | if (!codec->sample_rate) |
| 3082 | 3095 | codec->sample_rate = icodec->sample_rate; |
| 3083 | 3096 | choose_sample_rate(ost->st, ost->enc); |
| @@ -3110,13 +3123,15 @@ static int transcode_init(void) · 26 unmodified lines | ||
| 3110 | 3123 | if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) |
| 3111 | 3124 | codec->channel_layout = 0; |
| 3112 | 3125 | |
| 3113 | − ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; | |
| 3114 | − ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt | |
| 3115 | − || codec->channel_layout != icodec->channel_layout; | |
| 3116 | − icodec->request_channels = codec->channels; | |
| 3126 | + | |
| 3127 | +// ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; | |
| 3128 | +// ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt | |
| 3129 | +// || codec->channel_layout != icodec->channel_layout; | |
| 3130 | + icodec->request_channels = codec-> channels; | |
| 3117 | 3131 | ost->resample_sample_fmt = icodec->sample_fmt; |
| 3118 | 3132 | ost->resample_sample_rate = icodec->sample_rate; |
| 3119 | 3133 | ost->resample_channels = icodec->channels; |
| 3134 | + ost->resample_channel_layout = icodec->channel_layout; | |
| 3120 | 3135 | break; |
| 3121 | 3136 | case AVMEDIA_TYPE_VIDEO: |
| 3122 | 3137 | if (!ost->filter) { |
| @@ -0,0 +1,15 @@ | ||
| 1 | +NAME = avresample | |
| 2 | +FFLIBS = avutil | |
| 3 | + | |
| 4 | +HEADERS = avresample.h \ | |
| 5 | + version.h | |
| 6 | + | |
| 7 | +OBJS = audio_convert.o \ | |
| 8 | + audio_data.o \ | |
| 9 | + audio_mix.o \ | |
| 10 | + audio_mix_matrix.o \ | |
| 11 | + options.o \ | |
| 12 | + resample.o \ | |
| 13 | + utils.o | |
| 14 | + | |
| 15 | +TESTPROGS = avresample | |
| @@ -0,0 +1,334 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> | |
| 3 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 4 | + * | |
| 5 | + * This file is part of Libav. | |
| 6 | + * | |
| 7 | + * Libav is free software; you can redistribute it and/or | |
| 8 | + * modify it under the terms of the GNU Lesser General Public | |
| 9 | + * License as published by the Free Software Foundation; either | |
| 10 | + * version 2.1 of the License, or (at your option) any later version. | |
| 11 | + * | |
| 12 | + * Libav is distributed in the hope that it will be useful, | |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 | + * Lesser General Public License for more details. | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU Lesser General Public | |
| 18 | + * License along with Libav; if not, write to the Free Software | |
| 19 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#include <stdint.h> | |
| 23 | + | |
| 24 | +#include "config.h" | |
| 25 | +#include "libavutil/libm.h" | |
| 26 | +#include "libavutil/log.h" | |
| 27 | +#include "libavutil/mem.h" | |
| 28 | +#include "libavutil/samplefmt.h" | |
| 29 | +#include "audio_convert.h" | |
| 30 | +#include "audio_data.h" | |
| 31 | + | |
| 32 | +enum ConvFuncType { | |
| 33 | + CONV_FUNC_TYPE_FLAT, | |
| 34 | + CONV_FUNC_TYPE_INTERLEAVE, | |
| 35 | + CONV_FUNC_TYPE_DEINTERLEAVE, | |
| 36 | +}; | |
| 37 | + | |
| 38 | +typedef void (conv_func_flat)(uint8_t *out, const uint8_t *in, int len); | |
| 39 | + | |
| 40 | +typedef void (conv_func_interleave)(uint8_t *out, uint8_t *const *in, | |
| 41 | + int len, int channels); | |
| 42 | + | |
| 43 | +typedef void (conv_func_deinterleave)(uint8_t **out, const uint8_t *in, int len, | |
| 44 | + int channels); | |
| 45 | + | |
| 46 | +struct AudioConvert { | |
| 47 | + AVAudioResampleContext *avr; | |
| 48 | + enum AVSampleFormat in_fmt; | |
| 49 | + enum AVSampleFormat out_fmt; | |
| 50 | + int channels; | |
| 51 | + int planes; | |
| 52 | + int ptr_align; | |
| 53 | + int samples_align; | |
| 54 | + int has_optimized_func; | |
| 55 | + const char *func_descr; | |
| 56 | + const char *func_descr_generic; | |
| 57 | + enum ConvFuncType func_type; | |
| 58 | + conv_func_flat *conv_flat; | |
| 59 | + conv_func_flat *conv_flat_generic; | |
| 60 | + conv_func_interleave *conv_interleave; | |
| 61 | + conv_func_interleave *conv_interleave_generic; | |
| 62 | + conv_func_deinterleave *conv_deinterleave; | |
| 63 | + conv_func_deinterleave *conv_deinterleave_generic; | |
| 64 | +}; | |
| 65 | + | |
| 66 | +void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, | |
| 67 | + enum AVSampleFormat in_fmt, int channels, | |
| 68 | + int ptr_align, int samples_align, | |
| 69 | + const char *descr, void *conv) | |
| 70 | +{ | |
| 71 | + int found = 0; | |
| 72 | + | |
| 73 | + switch (ac->func_type) { | |
| 74 | + case CONV_FUNC_TYPE_FLAT: | |
| 75 | + if (av_get_packed_sample_fmt(ac->in_fmt) == in_fmt && | |
| 76 | + av_get_packed_sample_fmt(ac->out_fmt) == out_fmt) { | |
| 77 | + ac->conv_flat = conv; | |
| 78 | + ac->func_descr = descr; | |
| 79 | + ac->ptr_align = ptr_align; | |
| 80 | + ac->samples_align = samples_align; | |
| 81 | + if (ptr_align == 1 && samples_align == 1) { | |
| 82 | + ac->conv_flat_generic = conv; | |
| 83 | + ac->func_descr_generic = descr; | |
| 84 | + } else { | |
| 85 | + ac->has_optimized_func = 1; | |
| 86 | + } | |
| 87 | + found = 1; | |
| 88 | + } | |
| 89 | + break; | |
| 90 | + case CONV_FUNC_TYPE_INTERLEAVE: | |
| 91 | + if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt && | |
| 92 | + (!channels || ac->channels == channels)) { | |
| 93 | + ac->conv_interleave = conv; | |
| 94 | + ac->func_descr = descr; | |
| 95 | + ac->ptr_align = ptr_align; | |
| 96 | + ac->samples_align = samples_align; | |
| 97 | + if (ptr_align == 1 && samples_align == 1) { | |
| 98 | + ac->conv_interleave_generic = conv; | |
| 99 | + ac->func_descr_generic = descr; | |
| 100 | + } else { | |
| 101 | + ac->has_optimized_func = 1; | |
| 102 | + } | |
| 103 | + found = 1; | |
| 104 | + } | |
| 105 | + break; | |
| 106 | + case CONV_FUNC_TYPE_DEINTERLEAVE: | |
| 107 | + if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt && | |
| 108 | + (!channels || ac->channels == channels)) { | |
| 109 | + ac->conv_deinterleave = conv; | |
| 110 | + ac->func_descr = descr; | |
| 111 | + ac->ptr_align = ptr_align; | |
| 112 | + ac->samples_align = samples_align; | |
| 113 | + if (ptr_align == 1 && samples_align == 1) { | |
| 114 | + ac->conv_deinterleave_generic = conv; | |
| 115 | + ac->func_descr_generic = descr; | |
| 116 | + } else { | |
| 117 | + ac->has_optimized_func = 1; | |
| 118 | + } | |
| 119 | + found = 1; | |
| 120 | + } | |
| 121 | + break; | |
| 122 | + } | |
| 123 | + if (found) { | |
| 124 | + av_log(ac->avr, AV_LOG_DEBUG, "audio_convert: found function: %-4s " | |
| 125 | + "to %-4s (%s)\n", av_get_sample_fmt_name(ac->in_fmt), | |
| 126 | + av_get_sample_fmt_name(ac->out_fmt), descr); | |
| 127 | + } | |
| 128 | +} | |
| 129 | + | |
| 130 | +#define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt | |
| 131 | + | |
| 132 | +#define CONV_LOOP(otype, expr) \ | |
| 133 | + do { \ | |
| 134 | + *(otype *)po = expr; \ | |
| 135 | + pi += is; \ | |
| 136 | + po += os; \ | |
| 137 | + } while (po < end); \ | |
| 138 | + | |
| 139 | +#define CONV_FUNC_FLAT(ofmt, otype, ifmt, itype, expr) \ | |
| 140 | +static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t *in, \ | |
| 141 | + int len) \ | |
| 142 | +{ \ | |
| 143 | + int is = sizeof(itype); \ | |
| 144 | + int os = sizeof(otype); \ | |
| 145 | + const uint8_t *pi = in; \ | |
| 146 | + uint8_t *po = out; \ | |
| 147 | + uint8_t *end = out + os * len; \ | |
| 148 | + CONV_LOOP(otype, expr) \ | |
| 149 | +} | |
| 150 | + | |
| 151 | +#define CONV_FUNC_INTERLEAVE(ofmt, otype, ifmt, itype, expr) \ | |
| 152 | +static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t **in, \ | |
| 153 | + int len, int channels) \ | |
| 154 | +{ \ | |
| 155 | + int ch; \ | |
| 156 | + int out_bps = sizeof(otype); \ | |
| 157 | + int is = sizeof(itype); \ | |
| 158 | + int os = channels * out_bps; \ | |
| 159 | + for (ch = 0; ch < channels; ch++) { \ | |
| 160 | + const uint8_t *pi = in[ch]; \ | |
| 161 | + uint8_t *po = out + ch * out_bps; \ | |
| 162 | + uint8_t *end = po + os * len; \ | |
| 163 | + CONV_LOOP(otype, expr) \ | |
| 164 | + } \ | |
| 165 | +} | |
| 166 | + | |
| 167 | +#define CONV_FUNC_DEINTERLEAVE(ofmt, otype, ifmt, itype, expr) \ | |
| 168 | +static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t **out, const uint8_t *in, \ | |
| 169 | + int len, int channels) \ | |
| 170 | +{ \ | |
| 171 | + int ch; \ | |
| 172 | + int in_bps = sizeof(itype); \ | |
| 173 | + int is = channels * in_bps; \ | |
| 174 | + int os = sizeof(otype); \ | |
| 175 | + for (ch = 0; ch < channels; ch++) { \ | |
| 176 | + const uint8_t *pi = in + ch * in_bps; \ | |
| 177 | + uint8_t *po = out[ch]; \ | |
| 178 | + uint8_t *end = po + os * len; \ | |
| 179 | + CONV_LOOP(otype, expr) \ | |
| 180 | + } \ | |
| 181 | +} | |
| 182 | + | |
| 183 | +#define CONV_FUNC_GROUP(ofmt, otype, ifmt, itype, expr) \ | |
| 184 | +CONV_FUNC_FLAT( ofmt, otype, ifmt, itype, expr) \ | |
| 185 | +CONV_FUNC_INTERLEAVE( ofmt, otype, ifmt ## P, itype, expr) \ | |
| 186 | +CONV_FUNC_DEINTERLEAVE(ofmt ## P, otype, ifmt, itype, expr) | |
| 187 | + | |
| 188 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_U8, uint8_t, *(const uint8_t *)pi) | |
| 189 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) << 8) | |
| 190 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) << 24) | |
| 191 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0f / (1 << 7))) | |
| 192 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0 / (1 << 7))) | |
| 193 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t, (*(const int16_t *)pi >> 8) + 0x80) | |
| 194 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi) | |
| 195 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi << 16) | |
| 196 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi * (1.0f / (1 << 15))) | |
| 197 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi * (1.0 / (1 << 15))) | |
| 198 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t, (*(const int32_t *)pi >> 24) + 0x80) | |
| 199 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi >> 16) | |
| 200 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi) | |
| 201 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi * (1.0f / (1U << 31))) | |
| 202 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi * (1.0 / (1U << 31))) | |
| 203 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8( lrintf(*(const float *)pi * (1 << 7)) + 0x80)) | |
| 204 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16( lrintf(*(const float *)pi * (1 << 15)))) | |
| 205 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *)pi * (1U << 31)))) | |
| 206 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_FLT, float, *(const float *)pi) | |
| 207 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_FLT, float, *(const float *)pi) | |
| 208 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8( lrint(*(const double *)pi * (1 << 7)) + 0x80)) | |
| 209 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16( lrint(*(const double *)pi * (1 << 15)))) | |
| 210 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *)pi * (1U << 31)))) | |
| 211 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_DBL, double, *(const double *)pi) | |
| 212 | +CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_DBL, double, *(const double *)pi) | |
| 213 | + | |
| 214 | +#define SET_CONV_FUNC_GROUP(ofmt, ifmt) \ | |
| 215 | +ff_audio_convert_set_func(ac, ofmt, ifmt, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt, ifmt)); \ | |
| 216 | +ff_audio_convert_set_func(ac, ofmt ## P, ifmt, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt ## P, ifmt)); \ | |
| 217 | +ff_audio_convert_set_func(ac, ofmt, ifmt ## P, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt, ifmt ## P)); | |
| 218 | + | |
| 219 | +static void set_generic_function(AudioConvert *ac) | |
| 220 | +{ | |
| 221 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8) | |
| 222 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8) | |
| 223 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8) | |
| 224 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8) | |
| 225 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8) | |
| 226 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16) | |
| 227 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16) | |
| 228 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16) | |
| 229 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16) | |
| 230 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16) | |
| 231 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32) | |
| 232 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32) | |
| 233 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32) | |
| 234 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32) | |
| 235 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32) | |
| 236 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT) | |
| 237 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT) | |
| 238 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT) | |
| 239 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT) | |
| 240 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT) | |
| 241 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL) | |
| 242 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL) | |
| 243 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL) | |
| 244 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL) | |
| 245 | + SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL) | |
| 246 | +} | |
| 247 | + | |
| 248 | +AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, | |
| 249 | + enum AVSampleFormat out_fmt, | |
| 250 | + enum AVSampleFormat in_fmt, | |
| 251 | + int channels) | |
| 252 | +{ | |
| 253 | + AudioConvert *ac; | |
| 254 | + int in_planar, out_planar; | |
| 255 | + | |
| 256 | + ac = av_mallocz(sizeof(*ac)); | |
| 257 | + if (!ac) | |
| 258 | + return NULL; | |
| 259 | + | |
| 260 | + ac->avr = avr; | |
| 261 | + ac->out_fmt = out_fmt; | |
| 262 | + ac->in_fmt = in_fmt; | |
| 263 | + ac->channels = channels; | |
| 264 | + | |
| 265 | + in_planar = av_sample_fmt_is_planar(in_fmt); | |
| 266 | + out_planar = av_sample_fmt_is_planar(out_fmt); | |
| 267 | + | |
| 268 | + if (in_planar == out_planar) { | |
| 269 | + ac->func_type = CONV_FUNC_TYPE_FLAT; | |
| 270 | + ac->planes = in_planar ? ac->channels : 1; | |
| 271 | + } else if (in_planar) | |
| 272 | + ac->func_type = CONV_FUNC_TYPE_INTERLEAVE; | |
| 273 | + else | |
| 274 | + ac->func_type = CONV_FUNC_TYPE_DEINTERLEAVE; | |
| 275 | + | |
| 276 | + set_generic_function(ac); | |
| 277 | + | |
| 278 | + if (ARCH_X86) | |
| 279 | + ff_audio_convert_init_x86(ac); | |
| 280 | + | |
| 281 | + return ac; | |
| 282 | +} | |
| 283 | + | |
| 284 | +int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in, int len) | |
| 285 | +{ | |
| 286 | + int use_generic = 1; | |
| 287 | + | |
| 288 | + /* determine whether to use the optimized function based on pointer and | |
| 289 | + samples alignment in both the input and output */ | |
| 290 | + if (ac->has_optimized_func) { | |
| 291 | + int ptr_align = FFMIN(in->ptr_align, out->ptr_align); | |
| 292 | + int samples_align = FFMIN(in->samples_align, out->samples_align); | |
| 293 | + int aligned_len = FFALIGN(len, ac->samples_align); | |
| 294 | + if (!(ptr_align % ac->ptr_align) && samples_align >= aligned_len) { | |
| 295 | + len = aligned_len; | |
| 296 | + use_generic = 0; | |
| 297 | + } | |
| 298 | + } | |
| 299 | + av_dlog(ac->avr, "%d samples - audio_convert: %s to %s (%s)\n", len, | |
| 300 | + av_get_sample_fmt_name(ac->in_fmt), | |
| 301 | + av_get_sample_fmt_name(ac->out_fmt), | |
| 302 | + use_generic ? ac->func_descr_generic : ac->func_descr); | |
| 303 | + | |
| 304 | + switch (ac->func_type) { | |
| 305 | + case CONV_FUNC_TYPE_FLAT: { | |
| 306 | + int p; | |
| 307 | + if (!in->is_planar) | |
| 308 | + len *= in->channels; | |
| 309 | + if (use_generic) { | |
| 310 | + for (p = 0; p < ac->planes; p++) | |
| 311 | + ac->conv_flat_generic(out->data[p], in->data[p], len); | |
| 312 | + } else { | |
| 313 | + for (p = 0; p < ac->planes; p++) | |
| 314 | + ac->conv_flat(out->data[p], in->data[p], len); | |
| 315 | + } | |
| 316 | + break; | |
| 317 | + } | |
| 318 | + case CONV_FUNC_TYPE_INTERLEAVE: | |
| 319 | + if (use_generic) | |
| 320 | + ac->conv_interleave_generic(out->data[0], in->data, len, ac->channels); | |
| 321 | + else | |
| 322 | + ac->conv_interleave(out->data[0], in->data, len, ac->channels); | |
| 323 | + break; | |
| 324 | + case CONV_FUNC_TYPE_DEINTERLEAVE: | |
| 325 | + if (use_generic) | |
| 326 | + ac->conv_deinterleave_generic(out->data, in->data[0], len, ac->channels); | |
| 327 | + else | |
| 328 | + ac->conv_deinterleave(out->data, in->data[0], len, ac->channels); | |
| 329 | + break; | |
| 330 | + } | |
| 331 | + | |
| 332 | + out->nb_samples = in->nb_samples; | |
| 333 | + return 0; | |
| 334 | +} | |
| @@ -0,0 +1,87 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#ifndef AVRESAMPLE_AUDIO_CONVERT_H | |
| 22 | +#define AVRESAMPLE_AUDIO_CONVERT_H | |
| 23 | + | |
| 24 | +#include "libavutil/samplefmt.h" | |
| 25 | +#include "avresample.h" | |
| 26 | +#include "audio_data.h" | |
| 27 | + | |
| 28 | +typedef struct AudioConvert AudioConvert; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Set conversion function if the parameters match. | |
| 32 | + * | |
| 33 | + * This compares the parameters of the conversion function to the parameters | |
| 34 | + * in the AudioConvert context. If the parameters do not match, no changes are | |
| 35 | + * made to the active functions. If the parameters do match and the alignment | |
| 36 | + * is not constrained, the function is set as the generic conversion function. | |
| 37 | + * If the parameters match and the alignment is constrained, the function is | |
| 38 | + * set as the optimized conversion function. | |
| 39 | + * | |
| 40 | + * @param ac AudioConvert context | |
| 41 | + * @param out_fmt output sample format | |
| 42 | + * @param in_fmt input sample format | |
| 43 | + * @param channels number of channels, or 0 for any number of channels | |
| 44 | + * @param ptr_align buffer pointer alignment, in bytes | |
| 45 | + * @param sample_align buffer size alignment, in samples | |
| 46 | + * @param descr function type description (e.g. "C" or "SSE") | |
| 47 | + * @param conv conversion function pointer | |
| 48 | + */ | |
| 49 | +void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, | |
| 50 | + enum AVSampleFormat in_fmt, int channels, | |
| 51 | + int ptr_align, int samples_align, | |
| 52 | + const char *descr, void *conv); | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * Allocate and initialize AudioConvert context for sample format conversion. | |
| 56 | + * | |
| 57 | + * @param avr AVAudioResampleContext | |
| 58 | + * @param out_fmt output sample format | |
| 59 | + * @param in_fmt input sample format | |
| 60 | + * @param channels number of channels | |
| 61 | + * @return newly-allocated AudioConvert context | |
| 62 | + */ | |
| 63 | +AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, | |
| 64 | + enum AVSampleFormat out_fmt, | |
| 65 | + enum AVSampleFormat in_fmt, | |
| 66 | + int channels); | |
| 67 | + | |
| 68 | +/** | |
| 69 | + * Convert audio data from one sample format to another. | |
| 70 | + * | |
| 71 | + * For each call, the alignment of the input and output AudioData buffers are | |
| 72 | + * examined to determine whether to use the generic or optimized conversion | |
| 73 | + * function (when available). | |
| 74 | + * | |
| 75 | + * @param ac AudioConvert context | |
| 76 | + * @param out output audio data | |
| 77 | + * @param in input audio data | |
| 78 | + * @param len number of samples to convert | |
| 79 | + * @return 0 on success, negative AVERROR code on failure | |
| 80 | + */ | |
| 81 | +int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in, int len); | |
| 82 | + | |
| 83 | +/* arch-specific initialization functions */ | |
| 84 | + | |
| 85 | +void ff_audio_convert_init_x86(AudioConvert *ac); | |
| 86 | + | |
| 87 | +#endif /* AVRESAMPLE_AUDIO_CONVERT_H */ | |
| @@ -0,0 +1,345 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include <stdint.h> | |
| 22 | + | |
| 23 | +#include "libavutil/mem.h" | |
| 24 | +#include "audio_data.h" | |
| 25 | + | |
| 26 | +static const AVClass audio_data_class = { | |
| 27 | + .class_name = "AudioData", | |
| 28 | + .item_name = av_default_item_name, | |
| 29 | + .version = LIBAVUTIL_VERSION_INT, | |
| 30 | +}; | |
| 31 | + | |
| 32 | +/* | |
| 33 | + * Calculate alignment for data pointers. | |
| 34 | + */ | |
| 35 | +static void calc_ptr_alignment(AudioData *a) | |
| 36 | +{ | |
| 37 | + int p; | |
| 38 | + int min_align = 128; | |
| 39 | + | |
| 40 | + for (p = 0; p < a->planes; p++) { | |
| 41 | + int cur_align = 128; | |
| 42 | + while ((intptr_t)a->data[p] % cur_align) | |
| 43 | + cur_align >>= 1; | |
| 44 | + if (cur_align < min_align) | |
| 45 | + min_align = cur_align; | |
| 46 | + } | |
| 47 | + a->ptr_align = min_align; | |
| 48 | +} | |
| 49 | + | |
| 50 | +int ff_audio_data_set_channels(AudioData *a, int channels) | |
| 51 | +{ | |
| 52 | + if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS || | |
| 53 | + channels > a->allocated_channels) | |
| 54 | + return AVERROR(EINVAL); | |
| 55 | + | |
| 56 | + a->channels = channels; | |
| 57 | + a->planes = a->is_planar ? channels : 1; | |
| 58 | + | |
| 59 | + calc_ptr_alignment(a); | |
| 60 | + | |
| 61 | + return 0; | |
| 62 | +} | |
| 63 | + | |
| 64 | +int ff_audio_data_init(AudioData *a, void **src, int plane_size, int channels, | |
| 65 | + int nb_samples, enum AVSampleFormat sample_fmt, | |
| 66 | + int read_only, const char *name) | |
| 67 | +{ | |
| 68 | + int p; | |
| 69 | + | |
| 70 | + memset(a, 0, sizeof(*a)); | |
| 71 | + a->class = &audio_data_class; | |
| 72 | + | |
| 73 | + if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) { | |
| 74 | + av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels); | |
| 75 | + return AVERROR(EINVAL); | |
| 76 | + } | |
| 77 | + | |
| 78 | + a->sample_size = av_get_bytes_per_sample(sample_fmt); | |
| 79 | + if (!a->sample_size) { | |
| 80 | + av_log(a, AV_LOG_ERROR, "invalid sample format\n"); | |
| 81 | + return AVERROR(EINVAL); | |
| 82 | + } | |
| 83 | + a->is_planar = av_sample_fmt_is_planar(sample_fmt); | |
| 84 | + a->planes = a->is_planar ? channels : 1; | |
| 85 | + a->stride = a->sample_size * (a->is_planar ? 1 : channels); | |
| 86 | + | |
| 87 | + for (p = 0; p < (a->is_planar ? channels : 1); p++) { | |
| 88 | + if (!src[p]) { | |
| 89 | + av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p); | |
| 90 | + return AVERROR(EINVAL); | |
| 91 | + } | |
| 92 | + a->data[p] = src[p]; | |
| 93 | + } | |
| 94 | + a->allocated_samples = nb_samples * !read_only; | |
| 95 | + a->nb_samples = nb_samples; | |
| 96 | + a->sample_fmt = sample_fmt; | |
| 97 | + a->channels = channels; | |
| 98 | + a->allocated_channels = channels; | |
| 99 | + a->read_only = read_only; | |
| 100 | + a->allow_realloc = 0; | |
| 101 | + a->name = name ? name : "{no name}"; | |
| 102 | + | |
| 103 | + calc_ptr_alignment(a); | |
| 104 | + a->samples_align = plane_size / a->stride; | |
| 105 | + | |
| 106 | + return 0; | |
| 107 | +} | |
| 108 | + | |
| 109 | +AudioData *ff_audio_data_alloc(int channels, int nb_samples, | |
| 110 | + enum AVSampleFormat sample_fmt, const char *name) | |
| 111 | +{ | |
| 112 | + AudioData *a; | |
| 113 | + int ret; | |
| 114 | + | |
| 115 | + if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) | |
| 116 | + return NULL; | |
| 117 | + | |
| 118 | + a = av_mallocz(sizeof(*a)); | |
| 119 | + if (!a) | |
| 120 | + return NULL; | |
| 121 | + | |
| 122 | + a->sample_size = av_get_bytes_per_sample(sample_fmt); | |
| 123 | + if (!a->sample_size) { | |
| 124 | + av_free(a); | |
| 125 | + return NULL; | |
| 126 | + } | |
| 127 | + a->is_planar = av_sample_fmt_is_planar(sample_fmt); | |
| 128 | + a->planes = a->is_planar ? channels : 1; | |
| 129 | + a->stride = a->sample_size * (a->is_planar ? 1 : channels); | |
| 130 | + | |
| 131 | + a->class = &audio_data_class; | |
| 132 | + a->sample_fmt = sample_fmt; | |
| 133 | + a->channels = channels; | |
| 134 | + a->allocated_channels = channels; | |
| 135 | + a->read_only = 0; | |
| 136 | + a->allow_realloc = 1; | |
| 137 | + a->name = name ? name : "{no name}"; | |
| 138 | + | |
| 139 | + if (nb_samples > 0) { | |
| 140 | + ret = ff_audio_data_realloc(a, nb_samples); | |
| 141 | + if (ret < 0) { | |
| 142 | + av_free(a); | |
| 143 | + return NULL; | |
| 144 | + } | |
| 145 | + return a; | |
| 146 | + } else { | |
| 147 | + calc_ptr_alignment(a); | |
| 148 | + return a; | |
| 149 | + } | |
| 150 | +} | |
| 151 | + | |
| 152 | +int ff_audio_data_realloc(AudioData *a, int nb_samples) | |
| 153 | +{ | |
| 154 | + int ret, new_buf_size, plane_size, p; | |
| 155 | + | |
| 156 | + /* check if buffer is already large enough */ | |
| 157 | + if (a->allocated_samples >= nb_samples) | |
| 158 | + return 0; | |
| 159 | + | |
| 160 | + /* validate that the output is not read-only and realloc is allowed */ | |
| 161 | + if (a->read_only || !a->allow_realloc) | |
| 162 | + return AVERROR(EINVAL); | |
| 163 | + | |
| 164 | + new_buf_size = av_samples_get_buffer_size(&plane_size, | |
| 165 | + a->allocated_channels, nb_samples, | |
| 166 | + a->sample_fmt, 0); | |
| 167 | + if (new_buf_size < 0) | |
| 168 | + return new_buf_size; | |
| 169 | + | |
| 170 | + /* if there is already data in the buffer and the sample format is planar, | |
| 171 | + allocate a new buffer and copy the data, otherwise just realloc the | |
| 172 | + internal buffer and set new data pointers */ | |
| 173 | + if (a->nb_samples > 0 && a->is_planar) { | |
| 174 | + uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL }; | |
| 175 | + | |
| 176 | + ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels, | |
| 177 | + nb_samples, a->sample_fmt, 0); | |
| 178 | + if (ret < 0) | |
| 179 | + return ret; | |
| 180 | + | |
| 181 | + for (p = 0; p < a->planes; p++) | |
| 182 | + memcpy(new_data[p], a->data[p], a->nb_samples * a->stride); | |
| 183 | + | |
| 184 | + av_freep(&a->buffer); | |
| 185 | + memcpy(a->data, new_data, sizeof(new_data)); | |
| 186 | + a->buffer = a->data[0]; | |
| 187 | + } else { | |
| 188 | + av_freep(&a->buffer); | |
| 189 | + a->buffer = av_malloc(new_buf_size); | |
| 190 | + if (!a->buffer) | |
| 191 | + return AVERROR(ENOMEM); | |
| 192 | + ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer, | |
| 193 | + a->allocated_channels, nb_samples, | |
| 194 | + a->sample_fmt, 0); | |
| 195 | + if (ret < 0) | |
| 196 | + return ret; | |
| 197 | + } | |
| 198 | + a->buffer_size = new_buf_size; | |
| 199 | + a->allocated_samples = nb_samples; | |
| 200 | + | |
| 201 | + calc_ptr_alignment(a); | |
| 202 | + a->samples_align = plane_size / a->stride; | |
| 203 | + | |
| 204 | + return 0; | |
| 205 | +} | |
| 206 | + | |
| 207 | +void ff_audio_data_free(AudioData **a) | |
| 208 | +{ | |
| 209 | + if (!*a) | |
| 210 | + return; | |
| 211 | + av_free((*a)->buffer); | |
| 212 | + av_freep(a); | |
| 213 | +} | |
| 214 | + | |
| 215 | +int ff_audio_data_copy(AudioData *dst, AudioData *src) | |
| 216 | +{ | |
| 217 | + int ret, p; | |
| 218 | + | |
| 219 | + /* validate input/output compatibility */ | |
| 220 | + if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels) | |
| 221 | + return AVERROR(EINVAL); | |
| 222 | + | |
| 223 | + /* if the input is empty, just empty the output */ | |
| 224 | + if (!src->nb_samples) { | |
| 225 | + dst->nb_samples = 0; | |
| 226 | + return 0; | |
| 227 | + } | |
| 228 | + | |
| 229 | + /* reallocate output if necessary */ | |
| 230 | + ret = ff_audio_data_realloc(dst, src->nb_samples); | |
| 231 | + if (ret < 0) | |
| 232 | + return ret; | |
| 233 | + | |
| 234 | + /* copy data */ | |
| 235 | + for (p = 0; p < src->planes; p++) | |
| 236 | + memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride); | |
| 237 | + dst->nb_samples = src->nb_samples; | |
| 238 | + | |
| 239 | + return 0; | |
| 240 | +} | |
| 241 | + | |
| 242 | +int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src, | |
| 243 | + int src_offset, int nb_samples) | |
| 244 | +{ | |
| 245 | + int ret, p, dst_offset2, dst_move_size; | |
| 246 | + | |
| 247 | + /* validate input/output compatibility */ | |
| 248 | + if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) { | |
| 249 | + av_log(src, AV_LOG_ERROR, "sample format mismatch\n"); | |
| 250 | + return AVERROR(EINVAL); | |
| 251 | + } | |
| 252 | + | |
| 253 | + /* validate offsets are within the buffer bounds */ | |
| 254 | + if (dst_offset < 0 || dst_offset > dst->nb_samples || | |
| 255 | + src_offset < 0 || src_offset > src->nb_samples) { | |
| 256 | + av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n", | |
| 257 | + src_offset, dst_offset); | |
| 258 | + return AVERROR(EINVAL); | |
| 259 | + } | |
| 260 | + | |
| 261 | + /* check offsets and sizes to see if we can just do nothing and return */ | |
| 262 | + if (nb_samples > src->nb_samples - src_offset) | |
| 263 | + nb_samples = src->nb_samples - src_offset; | |
| 264 | + if (nb_samples <= 0) | |
| 265 | + return 0; | |
| 266 | + | |
| 267 | + /* validate that the output is not read-only */ | |
| 268 | + if (dst->read_only) { | |
| 269 | + av_log(dst, AV_LOG_ERROR, "dst is read-only\n"); | |
| 270 | + return AVERROR(EINVAL); | |
| 271 | + } | |
| 272 | + | |
| 273 | + /* reallocate output if necessary */ | |
| 274 | + ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples); | |
| 275 | + if (ret < 0) { | |
| 276 | + av_log(dst, AV_LOG_ERROR, "error reallocating dst\n"); | |
| 277 | + return ret; | |
| 278 | + } | |
| 279 | + | |
| 280 | + dst_offset2 = dst_offset + nb_samples; | |
| 281 | + dst_move_size = dst->nb_samples - dst_offset; | |
| 282 | + | |
| 283 | + for (p = 0; p < src->planes; p++) { | |
| 284 | + if (dst_move_size > 0) { | |
| 285 | + memmove(dst->data[p] + dst_offset2 * dst->stride, | |
| 286 | + dst->data[p] + dst_offset * dst->stride, | |
| 287 | + dst_move_size * dst->stride); | |
| 288 | + } | |
| 289 | + memcpy(dst->data[p] + dst_offset * dst->stride, | |
| 290 | + src->data[p] + src_offset * src->stride, | |
| 291 | + nb_samples * src->stride); | |
| 292 | + } | |
| 293 | + dst->nb_samples += nb_samples; | |
| 294 | + | |
| 295 | + return 0; | |
| 296 | +} | |
| 297 | + | |
| 298 | +void ff_audio_data_drain(AudioData *a, int nb_samples) | |
| 299 | +{ | |
| 300 | + if (a->nb_samples <= nb_samples) { | |
| 301 | + /* drain the whole buffer */ | |
| 302 | + a->nb_samples = 0; | |
| 303 | + } else { | |
| 304 | + int p; | |
| 305 | + int move_offset = a->stride * nb_samples; | |
| 306 | + int move_size = a->stride * (a->nb_samples - nb_samples); | |
| 307 | + | |
| 308 | + for (p = 0; p < a->planes; p++) | |
| 309 | + memmove(a->data[p], a->data[p] + move_offset, move_size); | |
| 310 | + | |
| 311 | + a->nb_samples -= nb_samples; | |
| 312 | + } | |
| 313 | +} | |
| 314 | + | |
| 315 | +int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, | |
| 316 | + int nb_samples) | |
| 317 | +{ | |
| 318 | + uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS]; | |
| 319 | + int offset_size, p; | |
| 320 | + | |
| 321 | + if (offset >= a->nb_samples) | |
| 322 | + return 0; | |
| 323 | + offset_size = offset * a->stride; | |
| 324 | + for (p = 0; p < a->planes; p++) | |
| 325 | + offset_data[p] = a->data[p] + offset_size; | |
| 326 | + | |
| 327 | + return av_audio_fifo_write(af, (void **)offset_data, nb_samples); | |
| 328 | +} | |
| 329 | + | |
| 330 | +int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples) | |
| 331 | +{ | |
| 332 | + int ret; | |
| 333 | + | |
| 334 | + if (a->read_only) | |
| 335 | + return AVERROR(EINVAL); | |
| 336 | + | |
| 337 | + ret = ff_audio_data_realloc(a, nb_samples); | |
| 338 | + if (ret < 0) | |
| 339 | + return ret; | |
| 340 | + | |
| 341 | + ret = av_audio_fifo_read(af, (void **)a->data, nb_samples); | |
| 342 | + if (ret >= 0) | |
| 343 | + a->nb_samples = ret; | |
| 344 | + return ret; | |
| 345 | +} | |
| @@ -0,0 +1,173 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#ifndef AVRESAMPLE_AUDIO_DATA_H | |
| 22 | +#define AVRESAMPLE_AUDIO_DATA_H | |
| 23 | + | |
| 24 | +#include <stdint.h> | |
| 25 | + | |
| 26 | +#include "libavutil/audio_fifo.h" | |
| 27 | +#include "libavutil/log.h" | |
| 28 | +#include "libavutil/samplefmt.h" | |
| 29 | +#include "avresample.h" | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * Audio buffer used for intermediate storage between conversion phases. | |
| 33 | + */ | |
| 34 | +typedef struct AudioData { | |
| 35 | + const AVClass *class; /**< AVClass for logging */ | |
| 36 | + uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers */ | |
| 37 | + uint8_t *buffer; /**< data buffer */ | |
| 38 | + unsigned int buffer_size; /**< allocated buffer size */ | |
| 39 | + int allocated_samples; /**< number of samples the buffer can hold */ | |
| 40 | + int nb_samples; /**< current number of samples */ | |
| 41 | + enum AVSampleFormat sample_fmt; /**< sample format */ | |
| 42 | + int channels; /**< channel count */ | |
| 43 | + int allocated_channels; /**< allocated channel count */ | |
| 44 | + int is_planar; /**< sample format is planar */ | |
| 45 | + int planes; /**< number of data planes */ | |
| 46 | + int sample_size; /**< bytes per sample */ | |
| 47 | + int stride; /**< sample byte offset within a plane */ | |
| 48 | + int read_only; /**< data is read-only */ | |
| 49 | + int allow_realloc; /**< realloc is allowed */ | |
| 50 | + int ptr_align; /**< minimum data pointer alignment */ | |
| 51 | + int samples_align; /**< allocated samples alignment */ | |
| 52 | + const char *name; /**< name for debug logging */ | |
| 53 | +} AudioData; | |
| 54 | + | |
| 55 | +int ff_audio_data_set_channels(AudioData *a, int channels); | |
| 56 | + | |
| 57 | +/** | |
| 58 | + * Initialize AudioData using a given source. | |
| 59 | + * | |
| 60 | + * This does not allocate an internal buffer. It only sets the data pointers | |
| 61 | + * and audio parameters. | |
| 62 | + * | |
| 63 | + * @param a AudioData struct | |
| 64 | + * @param src source data pointers | |
| 65 | + * @param plane_size plane size, in bytes. | |
| 66 | + * This can be 0 if unknown, but that will lead to | |
| 67 | + * optimized functions not being used in many cases, | |
| 68 | + * which could slow down some conversions. | |
| 69 | + * @param channels channel count | |
| 70 | + * @param nb_samples number of samples in the source data | |
| 71 | + * @param sample_fmt sample format | |
| 72 | + * @param read_only indicates if buffer is read only or read/write | |
| 73 | + * @param name name for debug logging (can be NULL) | |
| 74 | + * @return 0 on success, negative AVERROR value on error | |
| 75 | + */ | |
| 76 | +int ff_audio_data_init(AudioData *a, void **src, int plane_size, int channels, | |
| 77 | + int nb_samples, enum AVSampleFormat sample_fmt, | |
| 78 | + int read_only, const char *name); | |
| 79 | + | |
| 80 | +/** | |
| 81 | + * Allocate AudioData. | |
| 82 | + * | |
| 83 | + * This allocates an internal buffer and sets audio parameters. | |
| 84 | + * | |
| 85 | + * @param channels channel count | |
| 86 | + * @param nb_samples number of samples to allocate space for | |
| 87 | + * @param sample_fmt sample format | |
| 88 | + * @param name name for debug logging (can be NULL) | |
| 89 | + * @return newly allocated AudioData struct, or NULL on error | |
| 90 | + */ | |
| 91 | +AudioData *ff_audio_data_alloc(int channels, int nb_samples, | |
| 92 | + enum AVSampleFormat sample_fmt, | |
| 93 | + const char *name); | |
| 94 | + | |
| 95 | +/** | |
| 96 | + * Reallocate AudioData. | |
| 97 | + * | |
| 98 | + * The AudioData must have been previously allocated with ff_audio_data_alloc(). | |
| 99 | + * | |
| 100 | + * @param a AudioData struct | |
| 101 | + * @param nb_samples number of samples to allocate space for | |
| 102 | + * @return 0 on success, negative AVERROR value on error | |
| 103 | + */ | |
| 104 | +int ff_audio_data_realloc(AudioData *a, int nb_samples); | |
| 105 | + | |
| 106 | +/** | |
| 107 | + * Free AudioData. | |
| 108 | + * | |
| 109 | + * The AudioData must have been previously allocated with ff_audio_data_alloc(). | |
| 110 | + * | |
| 111 | + * @param a AudioData struct | |
| 112 | + */ | |
| 113 | +void ff_audio_data_free(AudioData **a); | |
| 114 | + | |
| 115 | +/** | |
| 116 | + * Copy data from one AudioData to another. | |
| 117 | + * | |
| 118 | + * @param out output AudioData | |
| 119 | + * @param in input AudioData | |
| 120 | + * @return 0 on success, negative AVERROR value on error | |
| 121 | + */ | |
| 122 | +int ff_audio_data_copy(AudioData *out, AudioData *in); | |
| 123 | + | |
| 124 | +/** | |
| 125 | + * Append data from one AudioData to the end of another. | |
| 126 | + * | |
| 127 | + * @param dst destination AudioData | |
| 128 | + * @param dst_offset offset, in samples, to start writing, relative to the | |
| 129 | + * start of dst | |
| 130 | + * @param src source AudioData | |
| 131 | + * @param src_offset offset, in samples, to start copying, relative to the | |
| 132 | + * start of the src | |
| 133 | + * @param nb_samples number of samples to copy | |
| 134 | + * @return 0 on success, negative AVERROR value on error | |
| 135 | + */ | |
| 136 | +int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src, | |
| 137 | + int src_offset, int nb_samples); | |
| 138 | + | |
| 139 | +/** | |
| 140 | + * Drain samples from the start of the AudioData. | |
| 141 | + * | |
| 142 | + * Remaining samples are shifted to the start of the AudioData. | |
| 143 | + * | |
| 144 | + * @param a AudioData struct | |
| 145 | + * @param nb_samples number of samples to drain | |
| 146 | + */ | |
| 147 | +void ff_audio_data_drain(AudioData *a, int nb_samples); | |
| 148 | + | |
| 149 | +/** | |
| 150 | + * Add samples in AudioData to an AVAudioFifo. | |
| 151 | + * | |
| 152 | + * @param af Audio FIFO Buffer | |
| 153 | + * @param a AudioData struct | |
| 154 | + * @param offset number of samples to skip from the start of the data | |
| 155 | + * @param nb_samples number of samples to add to the FIFO | |
| 156 | + * @return number of samples actually added to the FIFO, or | |
| 157 | + * negative AVERROR code on error | |
| 158 | + */ | |
| 159 | +int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, | |
| 160 | + int nb_samples); | |
| 161 | + | |
| 162 | +/** | |
| 163 | + * Read samples from an AVAudioFifo to AudioData. | |
| 164 | + * | |
| 165 | + * @param af Audio FIFO Buffer | |
| 166 | + * @param a AudioData struct | |
| 167 | + * @param nb_samples number of samples to read from the FIFO | |
| 168 | + * @return number of samples actually read from the FIFO, or | |
| 169 | + * negative AVERROR code on error | |
| 170 | + */ | |
| 171 | +int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples); | |
| 172 | + | |
| 173 | +#endif /* AVRESAMPLE_AUDIO_DATA_H */ | |
| @@ -0,0 +1,356 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include <stdint.h> | |
| 22 | + | |
| 23 | +#include "libavutil/libm.h" | |
| 24 | +#include "libavutil/samplefmt.h" | |
| 25 | +#include "avresample.h" | |
| 26 | +#include "internal.h" | |
| 27 | +#include "audio_data.h" | |
| 28 | +#include "audio_mix.h" | |
| 29 | + | |
| 30 | +static const char *coeff_type_names[] = { "q6", "q15", "flt" }; | |
| 31 | + | |
| 32 | +void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, | |
| 33 | + enum AVMixCoeffType coeff_type, int in_channels, | |
| 34 | + int out_channels, int ptr_align, int samples_align, | |
| 35 | + const char *descr, void *mix_func) | |
| 36 | +{ | |
| 37 | + if (fmt == am->fmt && coeff_type == am->coeff_type && | |
| 38 | + ( in_channels == am->in_channels || in_channels == 0) && | |
| 39 | + (out_channels == am->out_channels || out_channels == 0)) { | |
| 40 | + char chan_str[16]; | |
| 41 | + am->mix = mix_func; | |
| 42 | + am->func_descr = descr; | |
| 43 | + am->ptr_align = ptr_align; | |
| 44 | + am->samples_align = samples_align; | |
| 45 | + if (ptr_align == 1 && samples_align == 1) { | |
| 46 | + am->mix_generic = mix_func; | |
| 47 | + am->func_descr_generic = descr; | |
| 48 | + } else { | |
| 49 | + am->has_optimized_func = 1; | |
| 50 | + } | |
| 51 | + if (in_channels) { | |
| 52 | + if (out_channels) | |
| 53 | + snprintf(chan_str, sizeof(chan_str), "[%d to %d] ", | |
| 54 | + in_channels, out_channels); | |
| 55 | + else | |
| 56 | + snprintf(chan_str, sizeof(chan_str), "[%d to any] ", | |
| 57 | + in_channels); | |
| 58 | + } else if (out_channels) { | |
| 59 | + snprintf(chan_str, sizeof(chan_str), "[any to %d] ", | |
| 60 | + out_channels); | |
| 61 | + } | |
| 62 | + av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] " | |
| 63 | + "[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt), | |
| 64 | + coeff_type_names[coeff_type], | |
| 65 | + (in_channels || out_channels) ? chan_str : "", descr); | |
| 66 | + } | |
| 67 | +} | |
| 68 | + | |
| 69 | +#define MIX_FUNC_NAME(fmt, cfmt) mix_any_ ## fmt ##_## cfmt ##_c | |
| 70 | + | |
| 71 | +#define MIX_FUNC_GENERIC(fmt, cfmt, stype, ctype, sumtype, expr) \ | |
| 72 | +static void MIX_FUNC_NAME(fmt, cfmt)(stype **samples, ctype **matrix, \ | |
| 73 | + int len, int out_ch, int in_ch) \ | |
| 74 | +{ \ | |
| 75 | + int i, in, out; \ | |
| 76 | + stype temp[AVRESAMPLE_MAX_CHANNELS]; \ | |
| 77 | + for (i = 0; i < len; i++) { \ | |
| 78 | + for (out = 0; out < out_ch; out++) { \ | |
| 79 | + sumtype sum = 0; \ | |
| 80 | + for (in = 0; in < in_ch; in++) \ | |
| 81 | + sum += samples[in][i] * matrix[out][in]; \ | |
| 82 | + temp[out] = expr; \ | |
| 83 | + } \ | |
| 84 | + for (out = 0; out < out_ch; out++) \ | |
| 85 | + samples[out][i] = temp[out]; \ | |
| 86 | + } \ | |
| 87 | +} | |
| 88 | + | |
| 89 | +MIX_FUNC_GENERIC(FLTP, FLT, float, float, float, sum) | |
| 90 | +MIX_FUNC_GENERIC(S16P, FLT, int16_t, float, float, av_clip_int16(lrintf(sum))) | |
| 91 | +MIX_FUNC_GENERIC(S16P, Q15, int16_t, int32_t, int64_t, av_clip_int16(sum >> 15)) | |
| 92 | +MIX_FUNC_GENERIC(S16P, Q6, int16_t, int16_t, int32_t, av_clip_int16(sum >> 6)) | |
| 93 | + | |
| 94 | +/* TODO: templatize the channel-specific C functions */ | |
| 95 | + | |
| 96 | +static void mix_2_to_1_fltp_flt_c(float **samples, float **matrix, int len, | |
| 97 | + int out_ch, int in_ch) | |
| 98 | +{ | |
| 99 | + float *src0 = samples[0]; | |
| 100 | + float *src1 = samples[1]; | |
| 101 | + float *dst = src0; | |
| 102 | + float m0 = matrix[0][0]; | |
| 103 | + float m1 = matrix[0][1]; | |
| 104 | + | |
| 105 | + while (len > 4) { | |
| 106 | + *dst++ = *src0++ * m0 + *src1++ * m1; | |
| 107 | + *dst++ = *src0++ * m0 + *src1++ * m1; | |
| 108 | + *dst++ = *src0++ * m0 + *src1++ * m1; | |
| 109 | + *dst++ = *src0++ * m0 + *src1++ * m1; | |
| 110 | + len -= 4; | |
| 111 | + } | |
| 112 | + while (len > 0) { | |
| 113 | + *dst++ = *src0++ * m0 + *src1++ * m1; | |
| 114 | + len--; | |
| 115 | + } | |
| 116 | +} | |
| 117 | + | |
| 118 | +static void mix_1_to_2_fltp_flt_c(float **samples, float **matrix, int len, | |
| 119 | + int out_ch, int in_ch) | |
| 120 | +{ | |
| 121 | + float v; | |
| 122 | + float *dst0 = samples[0]; | |
| 123 | + float *dst1 = samples[1]; | |
| 124 | + float *src = dst0; | |
| 125 | + float m0 = matrix[0][0]; | |
| 126 | + float m1 = matrix[1][0]; | |
| 127 | + | |
| 128 | + while (len > 4) { | |
| 129 | + v = *src++; | |
| 130 | + *dst0++ = v * m1; | |
| 131 | + *dst1++ = v * m0; | |
| 132 | + v = *src++; | |
| 133 | + *dst0++ = v * m1; | |
| 134 | + *dst1++ = v * m0; | |
| 135 | + v = *src++; | |
| 136 | + *dst0++ = v * m1; | |
| 137 | + *dst1++ = v * m0; | |
| 138 | + v = *src++; | |
| 139 | + *dst0++ = v * m1; | |
| 140 | + *dst1++ = v * m0; | |
| 141 | + len -= 4; | |
| 142 | + } | |
| 143 | + while (len > 0) { | |
| 144 | + v = *src++; | |
| 145 | + *dst0++ = v * m1; | |
| 146 | + *dst1++ = v * m0; | |
| 147 | + len--; | |
| 148 | + } | |
| 149 | +} | |
| 150 | + | |
| 151 | +static void mix_6_to_2_fltp_flt_c(float **samples, float **matrix, int len, | |
| 152 | + int out_ch, int in_ch) | |
| 153 | +{ | |
| 154 | + float v0, v1; | |
| 155 | + float *src0 = samples[0]; | |
| 156 | + float *src1 = samples[1]; | |
| 157 | + float *src2 = samples[2]; | |
| 158 | + float *src3 = samples[3]; | |
| 159 | + float *src4 = samples[4]; | |
| 160 | + float *src5 = samples[5]; | |
| 161 | + float *dst0 = src0; | |
| 162 | + float *dst1 = src1; | |
| 163 | + float *m0 = matrix[0]; | |
| 164 | + float *m1 = matrix[1]; | |
| 165 | + | |
| 166 | + while (len > 0) { | |
| 167 | + v0 = *src0++; | |
| 168 | + v1 = *src1++; | |
| 169 | + *dst0++ = v0 * m0[0] + | |
| 170 | + v1 * m0[1] + | |
| 171 | + *src2 * m0[2] + | |
| 172 | + *src3 * m0[3] + | |
| 173 | + *src4 * m0[4] + | |
| 174 | + *src5 * m0[5]; | |
| 175 | + *dst1++ = v0 * m1[0] + | |
| 176 | + v1 * m1[1] + | |
| 177 | + *src2++ * m1[2] + | |
| 178 | + *src3++ * m1[3] + | |
| 179 | + *src4++ * m1[4] + | |
| 180 | + *src5++ * m1[5]; | |
| 181 | + len--; | |
| 182 | + } | |
| 183 | +} | |
| 184 | + | |
| 185 | +static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len, | |
| 186 | + int out_ch, int in_ch) | |
| 187 | +{ | |
| 188 | + float v0, v1; | |
| 189 | + float *dst0 = samples[0]; | |
| 190 | + float *dst1 = samples[1]; | |
| 191 | + float *dst2 = samples[2]; | |
| 192 | + float *dst3 = samples[3]; | |
| 193 | + float *dst4 = samples[4]; | |
| 194 | + float *dst5 = samples[5]; | |
| 195 | + float *src0 = dst0; | |
| 196 | + float *src1 = dst1; | |
| 197 | + | |
| 198 | + while (len > 0) { | |
| 199 | + v0 = *src0++; | |
| 200 | + v1 = *src1++; | |
| 201 | + *dst0++ = v0 * matrix[0][0] + v1 * matrix[0][1]; | |
| 202 | + *dst1++ = v0 * matrix[1][0] + v1 * matrix[1][1]; | |
| 203 | + *dst2++ = v0 * matrix[2][0] + v1 * matrix[2][1]; | |
| 204 | + *dst3++ = v0 * matrix[3][0] + v1 * matrix[3][1]; | |
| 205 | + *dst4++ = v0 * matrix[4][0] + v1 * matrix[4][1]; | |
| 206 | + *dst5++ = v0 * matrix[5][0] + v1 * matrix[5][1]; | |
| 207 | + len--; | |
| 208 | + } | |
| 209 | +} | |
| 210 | + | |
| 211 | +static int mix_function_init(AudioMix *am) | |
| 212 | +{ | |
| 213 | + /* any-to-any C versions */ | |
| 214 | + | |
| 215 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
| 216 | + 0, 0, 1, 1, "C", MIX_FUNC_NAME(FLTP, FLT)); | |
| 217 | + | |
| 218 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | |
| 219 | + 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, FLT)); | |
| 220 | + | |
| 221 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q15, | |
| 222 | + 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q15)); | |
| 223 | + | |
| 224 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q6, | |
| 225 | + 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q6)); | |
| 226 | + | |
| 227 | + /* channel-specific C versions */ | |
| 228 | + | |
| 229 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
| 230 | + 2, 1, 1, 1, "C", mix_2_to_1_fltp_flt_c); | |
| 231 | + | |
| 232 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
| 233 | + 1, 2, 1, 1, "C", mix_1_to_2_fltp_flt_c); | |
| 234 | + | |
| 235 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
| 236 | + 6, 2, 1, 1, "C", mix_6_to_2_fltp_flt_c); | |
| 237 | + | |
| 238 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
| 239 | + 2, 6, 1, 1, "C", mix_2_to_6_fltp_flt_c); | |
| 240 | + | |
| 241 | + if (ARCH_X86) | |
| 242 | + ff_audio_mix_init_x86(am); | |
| 243 | + | |
| 244 | + if (!am->mix) { | |
| 245 | + av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] " | |
| 246 | + "[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt), | |
| 247 | + coeff_type_names[am->coeff_type], am->in_channels, | |
| 248 | + am->out_channels); | |
| 249 | + return AVERROR_PATCHWELCOME; | |
| 250 | + } | |
| 251 | + return 0; | |
| 252 | +} | |
| 253 | + | |
| 254 | +int ff_audio_mix_init(AVAudioResampleContext *avr) | |
| 255 | +{ | |
| 256 | + int ret; | |
| 257 | + | |
| 258 | + /* build matrix if the user did not already set one */ | |
| 259 | + if (!avr->am->matrix) { | |
| 260 | + int i, j; | |
| 261 | + char in_layout_name[128]; | |
| 262 | + char out_layout_name[128]; | |
| 263 | + double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels * | |
| 264 | + sizeof(*matrix_dbl)); | |
| 265 | + if (!matrix_dbl) | |
| 266 | + return AVERROR(ENOMEM); | |
| 267 | + | |
| 268 | + ret = avresample_build_matrix(avr->in_channel_layout, | |
| 269 | + avr->out_channel_layout, | |
| 270 | + avr->center_mix_level, | |
| 271 | + avr->surround_mix_level, | |
| 272 | + avr->lfe_mix_level, 1, matrix_dbl, | |
| 273 | + avr->in_channels); | |
| 274 | + if (ret < 0) { | |
| 275 | + av_free(matrix_dbl); | |
| 276 | + return ret; | |
| 277 | + } | |
| 278 | + | |
| 279 | + av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), | |
| 280 | + avr->in_channels, avr->in_channel_layout); | |
| 281 | + av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name), | |
| 282 | + avr->out_channels, avr->out_channel_layout); | |
| 283 | + av_log(avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n", | |
| 284 | + in_layout_name, out_layout_name); | |
| 285 | + for (i = 0; i < avr->out_channels; i++) { | |
| 286 | + for (j = 0; j < avr->in_channels; j++) { | |
| 287 | + av_log(avr, AV_LOG_DEBUG, " %0.3f ", | |
| 288 | + matrix_dbl[i * avr->in_channels + j]); | |
| 289 | + } | |
| 290 | + av_log(avr, AV_LOG_DEBUG, "\n"); | |
| 291 | + } | |
| 292 | + | |
| 293 | + ret = avresample_set_matrix(avr, matrix_dbl, avr->in_channels); | |
| 294 | + if (ret < 0) { | |
| 295 | + av_free(matrix_dbl); | |
| 296 | + return ret; | |
| 297 | + } | |
| 298 | + av_free(matrix_dbl); | |
| 299 | + } | |
| 300 | + | |
| 301 | + avr->am->fmt = avr->internal_sample_fmt; | |
| 302 | + avr->am->coeff_type = avr->mix_coeff_type; | |
| 303 | + avr->am->in_layout = avr->in_channel_layout; | |
| 304 | + avr->am->out_layout = avr->out_channel_layout; | |
| 305 | + avr->am->in_channels = avr->in_channels; | |
| 306 | + avr->am->out_channels = avr->out_channels; | |
| 307 | + | |
| 308 | + ret = mix_function_init(avr->am); | |
| 309 | + if (ret < 0) | |
| 310 | + return ret; | |
| 311 | + | |
| 312 | + return 0; | |
| 313 | +} | |
| 314 | + | |
| 315 | +void ff_audio_mix_close(AudioMix *am) | |
| 316 | +{ | |
| 317 | + if (!am) | |
| 318 | + return; | |
| 319 | + if (am->matrix) { | |
| 320 | + av_free(am->matrix[0]); | |
| 321 | + am->matrix = NULL; | |
| 322 | + } | |
| 323 | + memset(am->matrix_q6, 0, sizeof(am->matrix_q6 )); | |
| 324 | + memset(am->matrix_q15, 0, sizeof(am->matrix_q15)); | |
| 325 | + memset(am->matrix_flt, 0, sizeof(am->matrix_flt)); | |
| 326 | +} | |
| 327 | + | |
| 328 | +int ff_audio_mix(AudioMix *am, AudioData *src) | |
| 329 | +{ | |
| 330 | + int use_generic = 1; | |
| 331 | + int len = src->nb_samples; | |
| 332 | + | |
| 333 | + /* determine whether to use the optimized function based on pointer and | |
| 334 | + samples alignment in both the input and output */ | |
| 335 | + if (am->has_optimized_func) { | |
| 336 | + int aligned_len = FFALIGN(len, am->samples_align); | |
| 337 | + if (!(src->ptr_align % am->ptr_align) && | |
| 338 | + src->samples_align >= aligned_len) { | |
| 339 | + len = aligned_len; | |
| 340 | + use_generic = 0; | |
| 341 | + } | |
| 342 | + } | |
| 343 | + av_dlog(am->avr, "audio_mix: %d samples - %d to %d channels (%s)\n", | |
| 344 | + src->nb_samples, am->in_channels, am->out_channels, | |
| 345 | + use_generic ? am->func_descr_generic : am->func_descr); | |
| 346 | + | |
| 347 | + if (use_generic) | |
| 348 | + am->mix_generic(src->data, am->matrix, len, am->out_channels, | |
| 349 | + am->in_channels); | |
| 350 | + else | |
| 351 | + am->mix(src->data, am->matrix, len, am->out_channels, am->in_channels); | |
| 352 | + | |
| 353 | + ff_audio_data_set_channels(src, am->out_channels); | |
| 354 | + | |
| 355 | + return 0; | |
| 356 | +} | |
| @@ -0,0 +1,108 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#ifndef AVRESAMPLE_AUDIO_MIX_H | |
| 22 | +#define AVRESAMPLE_AUDIO_MIX_H | |
| 23 | + | |
| 24 | +#include <stdint.h> | |
| 25 | + | |
| 26 | +#include "libavutil/samplefmt.h" | |
| 27 | +#include "avresample.h" | |
| 28 | +#include "audio_data.h" | |
| 29 | + | |
| 30 | +typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch, | |
| 31 | + int in_ch); | |
| 32 | + | |
| 33 | +typedef struct AudioMix { | |
| 34 | + AVAudioResampleContext *avr; | |
| 35 | + enum AVSampleFormat fmt; | |
| 36 | + enum AVMixCoeffType coeff_type; | |
| 37 | + uint64_t in_layout; | |
| 38 | + uint64_t out_layout; | |
| 39 | + int in_channels; | |
| 40 | + int out_channels; | |
| 41 | + | |
| 42 | + int ptr_align; | |
| 43 | + int samples_align; | |
| 44 | + int has_optimized_func; | |
| 45 | + const char *func_descr; | |
| 46 | + const char *func_descr_generic; | |
| 47 | + mix_func *mix; | |
| 48 | + mix_func *mix_generic; | |
| 49 | + | |
| 50 | + int16_t *matrix_q6[AVRESAMPLE_MAX_CHANNELS]; | |
| 51 | + int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS]; | |
| 52 | + float *matrix_flt[AVRESAMPLE_MAX_CHANNELS]; | |
| 53 | + void **matrix; | |
| 54 | +} AudioMix; | |
| 55 | + | |
| 56 | +/** | |
| 57 | + * Set mixing function if the parameters match. | |
| 58 | + * | |
| 59 | + * This compares the parameters of the mixing function to the parameters in the | |
| 60 | + * AudioMix context. If the parameters do not match, no changes are made to the | |
| 61 | + * active functions. If the parameters do match and the alignment is not | |
| 62 | + * constrained, the function is set as the generic mixing function. If the | |
| 63 | + * parameters match and the alignment is constrained, the function is set as | |
| 64 | + * the optimized mixing function. | |
| 65 | + * | |
| 66 | + * @param am AudioMix context | |
| 67 | + * @param fmt input/output sample format | |
| 68 | + * @param coeff_type mixing coefficient type | |
| 69 | + * @param in_channels number of input channels, or 0 for any number of channels | |
| 70 | + * @param out_channels number of output channels, or 0 for any number of channels | |
| 71 | + * @param ptr_align buffer pointer alignment, in bytes | |
| 72 | + * @param sample_align buffer size alignment, in samples | |
| 73 | + * @param descr function type description (e.g. "C" or "SSE") | |
| 74 | + * @param mix_func mixing function pointer | |
| 75 | + */ | |
| 76 | +void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, | |
| 77 | + enum AVMixCoeffType coeff_type, int in_channels, | |
| 78 | + int out_channels, int ptr_align, int samples_align, | |
| 79 | + const char *descr, void *mix_func); | |
| 80 | + | |
| 81 | +/** | |
| 82 | + * Initialize the AudioMix context in the AVAudioResampleContext. | |
| 83 | + * | |
| 84 | + * The parameters in the AVAudioResampleContext are used to initialize the | |
| 85 | + * AudioMix context and set the mixing matrix. | |
| 86 | + * | |
| 87 | + * @param avr AVAudioResampleContext | |
| 88 | + * @return 0 on success, negative AVERROR code on failure | |
| 89 | + */ | |
| 90 | +int ff_audio_mix_init(AVAudioResampleContext *avr); | |
| 91 | + | |
| 92 | +/** | |
| 93 | + * Close an AudioMix context. | |
| 94 | + * | |
| 95 | + * This clears and frees the mixing matrix arrays. | |
| 96 | + */ | |
| 97 | +void ff_audio_mix_close(AudioMix *am); | |
| 98 | + | |
| 99 | +/** | |
| 100 | + * Apply channel mixing to audio data using the current mixing matrix. | |
| 101 | + */ | |
| 102 | +int ff_audio_mix(AudioMix *am, AudioData *src); | |
| 103 | + | |
| 104 | +/* arch-specific initialization functions */ | |
| 105 | + | |
| 106 | +void ff_audio_mix_init_x86(AudioMix *am); | |
| 107 | + | |
| 108 | +#endif /* AVRESAMPLE_AUDIO_MIX_H */ | |
| @@ -0,0 +1,346 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) | |
| 3 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 4 | + * | |
| 5 | + * This file is part of Libav. | |
| 6 | + * | |
| 7 | + * Libav is free software; you can redistribute it and/or | |
| 8 | + * modify it under the terms of the GNU Lesser General Public | |
| 9 | + * License as published by the Free Software Foundation; either | |
| 10 | + * version 2.1 of the License, or (at your option) any later version. | |
| 11 | + * | |
| 12 | + * Libav is distributed in the hope that it will be useful, | |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 | + * Lesser General Public License for more details. | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU Lesser General Public | |
| 18 | + * License along with Libav; if not, write to the Free Software | |
| 19 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#include <stdint.h> | |
| 23 | + | |
| 24 | +#include "libavutil/libm.h" | |
| 25 | +#include "libavutil/samplefmt.h" | |
| 26 | +#include "avresample.h" | |
| 27 | +#include "internal.h" | |
| 28 | +#include "audio_data.h" | |
| 29 | +#include "audio_mix.h" | |
| 30 | + | |
| 31 | +/* channel positions */ | |
| 32 | +#define FRONT_LEFT 0 | |
| 33 | +#define FRONT_RIGHT 1 | |
| 34 | +#define FRONT_CENTER 2 | |
| 35 | +#define LOW_FREQUENCY 3 | |
| 36 | +#define BACK_LEFT 4 | |
| 37 | +#define BACK_RIGHT 5 | |
| 38 | +#define FRONT_LEFT_OF_CENTER 6 | |
| 39 | +#define FRONT_RIGHT_OF_CENTER 7 | |
| 40 | +#define BACK_CENTER 8 | |
| 41 | +#define SIDE_LEFT 9 | |
| 42 | +#define SIDE_RIGHT 10 | |
| 43 | +#define TOP_CENTER 11 | |
| 44 | +#define TOP_FRONT_LEFT 12 | |
| 45 | +#define TOP_FRONT_CENTER 13 | |
| 46 | +#define TOP_FRONT_RIGHT 14 | |
| 47 | +#define TOP_BACK_LEFT 15 | |
| 48 | +#define TOP_BACK_CENTER 16 | |
| 49 | +#define TOP_BACK_RIGHT 17 | |
| 50 | +#define STEREO_LEFT 29 | |
| 51 | +#define STEREO_RIGHT 30 | |
| 52 | +#define WIDE_LEFT 31 | |
| 53 | +#define WIDE_RIGHT 32 | |
| 54 | +#define SURROUND_DIRECT_LEFT 33 | |
| 55 | +#define SURROUND_DIRECT_RIGHT 34 | |
| 56 | + | |
| 57 | +static av_always_inline int even(uint64_t layout) | |
| 58 | +{ | |
| 59 | + return (!layout || (layout & (layout - 1))); | |
| 60 | +} | |
| 61 | + | |
| 62 | +static int sane_layout(uint64_t layout) | |
| 63 | +{ | |
| 64 | + /* check that there is at least 1 front speaker */ | |
| 65 | + if (!(layout & AV_CH_LAYOUT_SURROUND)) | |
| 66 | + return 0; | |
| 67 | + | |
| 68 | + /* check for left/right symmetry */ | |
| 69 | + if (!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT)) || | |
| 70 | + !even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT)) || | |
| 71 | + !even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)) || | |
| 72 | + !even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)) || | |
| 73 | + !even(layout & (AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT)) || | |
| 74 | + !even(layout & (AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT)) || | |
| 75 | + !even(layout & (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT)) || | |
| 76 | + !even(layout & (AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT)) || | |
| 77 | + !even(layout & (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT))) | |
| 78 | + return 0; | |
| 79 | + | |
| 80 | + return 1; | |
| 81 | +} | |
| 82 | + | |
| 83 | +int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, | |
| 84 | + double center_mix_level, double surround_mix_level, | |
| 85 | + double lfe_mix_level, int normalize, | |
| 86 | + double *matrix_out, int stride) | |
| 87 | +{ | |
| 88 | + int i, j, out_i, out_j; | |
| 89 | + double matrix[64][64] = {{0}}; | |
| 90 | + int64_t unaccounted = in_layout & ~out_layout; | |
| 91 | + double maxcoef = 0; | |
| 92 | + int in_channels, out_channels; | |
| 93 | + | |
| 94 | + in_channels = av_get_channel_layout_nb_channels( in_layout); | |
| 95 | + out_channels = av_get_channel_layout_nb_channels(out_layout); | |
| 96 | + | |
| 97 | + memset(matrix_out, 0, out_channels * stride * sizeof(*matrix_out)); | |
| 98 | + | |
| 99 | + /* check if layouts are supported */ | |
| 100 | + if (!in_layout || in_channels > AVRESAMPLE_MAX_CHANNELS) | |
| 101 | + return AVERROR(EINVAL); | |
| 102 | + if (!out_layout || out_channels > AVRESAMPLE_MAX_CHANNELS) | |
| 103 | + return AVERROR(EINVAL); | |
| 104 | + | |
| 105 | + /* check if layouts are unbalanced or abnormal */ | |
| 106 | + if (!sane_layout(in_layout) || !sane_layout(out_layout)) | |
| 107 | + return AVERROR_PATCHWELCOME; | |
| 108 | + | |
| 109 | + /* route matching input/output channels */ | |
| 110 | + for (i = 0; i < 64; i++) { | |
| 111 | + if (in_layout & out_layout & (1ULL << i)) | |
| 112 | + matrix[i][i] = 1.0; | |
| 113 | + } | |
| 114 | + | |
| 115 | + /* mix front center to front left/right */ | |
| 116 | + if (unaccounted & AV_CH_FRONT_CENTER) { | |
| 117 | + if ((out_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) { | |
| 118 | + matrix[FRONT_LEFT ][FRONT_CENTER] += M_SQRT1_2; | |
| 119 | + matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2; | |
| 120 | + } else | |
| 121 | + return AVERROR_PATCHWELCOME; | |
| 122 | + } | |
| 123 | + /* mix front left/right to center */ | |
| 124 | + if (unaccounted & AV_CH_LAYOUT_STEREO) { | |
| 125 | + if (out_layout & AV_CH_FRONT_CENTER) { | |
| 126 | + matrix[FRONT_CENTER][FRONT_LEFT ] += M_SQRT1_2; | |
| 127 | + matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2; | |
| 128 | + /* mix left/right/center to center */ | |
| 129 | + if (in_layout & AV_CH_FRONT_CENTER) | |
| 130 | + matrix[FRONT_CENTER][FRONT_CENTER] = center_mix_level * M_SQRT2; | |
| 131 | + } else | |
| 132 | + return AVERROR_PATCHWELCOME; | |
| 133 | + } | |
| 134 | + /* mix back center to back, side, or front */ | |
| 135 | + if (unaccounted & AV_CH_BACK_CENTER) { | |
| 136 | + if (out_layout & AV_CH_BACK_LEFT) { | |
| 137 | + matrix[BACK_LEFT ][BACK_CENTER] += M_SQRT1_2; | |
| 138 | + matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2; | |
| 139 | + } else if (out_layout & AV_CH_SIDE_LEFT) { | |
| 140 | + matrix[SIDE_LEFT ][BACK_CENTER] += M_SQRT1_2; | |
| 141 | + matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2; | |
| 142 | + } else if (out_layout & AV_CH_FRONT_LEFT) { | |
| 143 | + matrix[FRONT_LEFT ][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | |
| 144 | + matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | |
| 145 | + } else if (out_layout & AV_CH_FRONT_CENTER) { | |
| 146 | + matrix[FRONT_CENTER][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | |
| 147 | + } else | |
| 148 | + return AVERROR_PATCHWELCOME; | |
| 149 | + } | |
| 150 | + /* mix back left/right to back center, side, or front */ | |
| 151 | + if (unaccounted & AV_CH_BACK_LEFT) { | |
| 152 | + if (out_layout & AV_CH_BACK_CENTER) { | |
| 153 | + matrix[BACK_CENTER][BACK_LEFT ] += M_SQRT1_2; | |
| 154 | + matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2; | |
| 155 | + } else if (out_layout & AV_CH_SIDE_LEFT) { | |
| 156 | + /* if side channels do not exist in the input, just copy back | |
| 157 | + channels to side channels, otherwise mix back into side */ | |
| 158 | + if (in_layout & AV_CH_SIDE_LEFT) { | |
| 159 | + matrix[SIDE_LEFT ][BACK_LEFT ] += M_SQRT1_2; | |
| 160 | + matrix[SIDE_RIGHT][BACK_RIGHT] += M_SQRT1_2; | |
| 161 | + } else { | |
| 162 | + matrix[SIDE_LEFT ][BACK_LEFT ] += 1.0; | |
| 163 | + matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0; | |
| 164 | + } | |
| 165 | + } else if (out_layout & AV_CH_FRONT_LEFT) { | |
| 166 | + matrix[FRONT_LEFT ][BACK_LEFT ] += surround_mix_level; | |
| 167 | + matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level; | |
| 168 | + } else if (out_layout & AV_CH_FRONT_CENTER) { | |
| 169 | + matrix[FRONT_CENTER][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; | |
| 170 | + matrix[FRONT_CENTER][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; | |
| 171 | + } else | |
| 172 | + return AVERROR_PATCHWELCOME; | |
| 173 | + } | |
| 174 | + /* mix side left/right into back or front */ | |
| 175 | + if (unaccounted & AV_CH_SIDE_LEFT) { | |
| 176 | + if (out_layout & AV_CH_BACK_LEFT) { | |
| 177 | + /* if back channels do not exist in the input, just copy side | |
| 178 | + channels to back channels, otherwise mix side into back */ | |
| 179 | + if (in_layout & AV_CH_BACK_LEFT) { | |
| 180 | + matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; | |
| 181 | + matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; | |
| 182 | + } else { | |
| 183 | + matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; | |
| 184 | + matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; | |
| 185 | + } | |
| 186 | + } else if (out_layout & AV_CH_BACK_CENTER) { | |
| 187 | + matrix[BACK_CENTER][SIDE_LEFT ] += M_SQRT1_2; | |
| 188 | + matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2; | |
| 189 | + } else if (out_layout & AV_CH_FRONT_LEFT) { | |
| 190 | + matrix[FRONT_LEFT ][SIDE_LEFT ] += surround_mix_level; | |
| 191 | + matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level; | |
| 192 | + } else if (out_layout & AV_CH_FRONT_CENTER) { | |
| 193 | + matrix[FRONT_CENTER][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; | |
| 194 | + matrix[FRONT_CENTER][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; | |
| 195 | + } else | |
| 196 | + return AVERROR_PATCHWELCOME; | |
| 197 | + } | |
| 198 | + /* mix left-of-center/right-of-center into front left/right or center */ | |
| 199 | + if (unaccounted & AV_CH_FRONT_LEFT_OF_CENTER) { | |
| 200 | + if (out_layout & AV_CH_FRONT_LEFT) { | |
| 201 | + matrix[FRONT_LEFT ][FRONT_LEFT_OF_CENTER ] += 1.0; | |
| 202 | + matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0; | |
| 203 | + } else if (out_layout & AV_CH_FRONT_CENTER) { | |
| 204 | + matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER ] += M_SQRT1_2; | |
| 205 | + matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2; | |
| 206 | + } else | |
| 207 | + return AVERROR_PATCHWELCOME; | |
| 208 | + } | |
| 209 | + /* mix LFE into front left/right or center */ | |
| 210 | + if (unaccounted & AV_CH_LOW_FREQUENCY) { | |
| 211 | + if (out_layout & AV_CH_FRONT_CENTER) { | |
| 212 | + matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level; | |
| 213 | + } else if (out_layout & AV_CH_FRONT_LEFT) { | |
| 214 | + matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; | |
| 215 | + matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; | |
| 216 | + } else | |
| 217 | + return AVERROR_PATCHWELCOME; | |
| 218 | + } | |
| 219 | + | |
| 220 | + /* transfer internal matrix to output matrix and calculate maximum | |
| 221 | + per-channel coefficient sum */ | |
| 222 | + for (out_i = i = 0; out_i < out_channels && i < 64; i++) { | |
| 223 | + double sum = 0; | |
| 224 | + for (out_j = j = 0; out_j < in_channels && j < 64; j++) { | |
| 225 | + matrix_out[out_i * stride + out_j] = matrix[i][j]; | |
| 226 | + sum += fabs(matrix[i][j]); | |
| 227 | + if (in_layout & (1ULL << j)) | |
| 228 | + out_j++; | |
| 229 | + } | |
| 230 | + maxcoef = FFMAX(maxcoef, sum); | |
| 231 | + if (out_layout & (1ULL << i)) | |
| 232 | + out_i++; | |
| 233 | + } | |
| 234 | + | |
| 235 | + /* normalize */ | |
| 236 | + if (normalize && maxcoef > 1.0) { | |
| 237 | + for (i = 0; i < out_channels; i++) | |
| 238 | + for (j = 0; j < in_channels; j++) | |
| 239 | + matrix_out[i * stride + j] /= maxcoef; | |
| 240 | + } | |
| 241 | + | |
| 242 | + return 0; | |
| 243 | +} | |
| 244 | + | |
| 245 | +int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, | |
| 246 | + int stride) | |
| 247 | +{ | |
| 248 | + int in_channels, out_channels, i, o; | |
| 249 | + | |
| 250 | + in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | |
| 251 | + out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | |
| 252 | + | |
| 253 | + if ( in_channels < 0 || in_channels > AVRESAMPLE_MAX_CHANNELS || | |
| 254 | + out_channels < 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
| 255 | + av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | |
| 256 | + return AVERROR(EINVAL); | |
| 257 | + } | |
| 258 | + | |
| 259 | + switch (avr->mix_coeff_type) { | |
| 260 | + case AV_MIX_COEFF_TYPE_Q6: | |
| 261 | + if (!avr->am->matrix_q6[0]) { | |
| 262 | + av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | |
| 263 | + return AVERROR(EINVAL); | |
| 264 | + } | |
| 265 | + for (o = 0; o < out_channels; o++) | |
| 266 | + for (i = 0; i < in_channels; i++) | |
| 267 | + matrix[o * stride + i] = avr->am->matrix_q6[o][i] / 64.0; | |
| 268 | + break; | |
| 269 | + case AV_MIX_COEFF_TYPE_Q15: | |
| 270 | + if (!avr->am->matrix_q15[0]) { | |
| 271 | + av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | |
| 272 | + return AVERROR(EINVAL); | |
| 273 | + } | |
| 274 | + for (o = 0; o < out_channels; o++) | |
| 275 | + for (i = 0; i < in_channels; i++) | |
| 276 | + matrix[o * stride + i] = avr->am->matrix_q15[o][i] / 32768.0; | |
| 277 | + break; | |
| 278 | + case AV_MIX_COEFF_TYPE_FLT: | |
| 279 | + if (!avr->am->matrix_flt[0]) { | |
| 280 | + av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | |
| 281 | + return AVERROR(EINVAL); | |
| 282 | + } | |
| 283 | + for (o = 0; o < out_channels; o++) | |
| 284 | + for (i = 0; i < in_channels; i++) | |
| 285 | + matrix[o * stride + i] = avr->am->matrix_flt[o][i]; | |
| 286 | + break; | |
| 287 | + default: | |
| 288 | + av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | |
| 289 | + return AVERROR(EINVAL); | |
| 290 | + } | |
| 291 | + return 0; | |
| 292 | +} | |
| 293 | + | |
| 294 | +int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, | |
| 295 | + int stride) | |
| 296 | +{ | |
| 297 | + int in_channels, out_channels, i, o; | |
| 298 | + | |
| 299 | + in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | |
| 300 | + out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | |
| 301 | + | |
| 302 | + if ( in_channels < 0 || in_channels > AVRESAMPLE_MAX_CHANNELS || | |
| 303 | + out_channels < 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
| 304 | + av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | |
| 305 | + return AVERROR(EINVAL); | |
| 306 | + } | |
| 307 | + | |
| 308 | + if (avr->am->matrix) | |
| 309 | + av_freep(avr->am->matrix); | |
| 310 | + | |
| 311 | +#define CONVERT_MATRIX(type, expr) \ | |
| 312 | + avr->am->matrix_## type[0] = av_mallocz(out_channels * in_channels * \ | |
| 313 | + sizeof(*avr->am->matrix_## type[0])); \ | |
| 314 | + if (!avr->am->matrix_## type[0]) \ | |
| 315 | + return AVERROR(ENOMEM); \ | |
| 316 | + for (o = 0; o < out_channels; o++) { \ | |
| 317 | + if (o > 0) \ | |
| 318 | + avr->am->matrix_## type[o] = avr->am->matrix_## type[o - 1] + \ | |
| 319 | + in_channels; \ | |
| 320 | + for (i = 0; i < in_channels; i++) { \ | |
| 321 | + double v = matrix[o * stride + i]; \ | |
| 322 | + avr->am->matrix_## type[o][i] = expr; \ | |
| 323 | + } \ | |
| 324 | + } \ | |
| 325 | + avr->am->matrix = (void **)avr->am->matrix_## type; | |
| 326 | + | |
| 327 | + switch (avr->mix_coeff_type) { | |
| 328 | + case AV_MIX_COEFF_TYPE_Q6: | |
| 329 | + CONVERT_MATRIX(q6, av_clip_int16(lrint(64.0 * v))) | |
| 330 | + break; | |
| 331 | + case AV_MIX_COEFF_TYPE_Q15: | |
| 332 | + CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v))) | |
| 333 | + break; | |
| 334 | + case AV_MIX_COEFF_TYPE_FLT: | |
| 335 | + CONVERT_MATRIX(flt, v) | |
| 336 | + break; | |
| 337 | + default: | |
| 338 | + av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | |
| 339 | + return AVERROR(EINVAL); | |
| 340 | + } | |
| 341 | + | |
| 342 | + /* TODO: detect situations where we can just swap around pointers | |
| 343 | + instead of doing matrix multiplications with 0.0 and 1.0 */ | |
| 344 | + | |
| 345 | + return 0; | |
| 346 | +} | |
| @@ -0,0 +1,340 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002 Fabrice Bellard | |
| 3 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 4 | + * | |
| 5 | + * This file is part of Libav. | |
| 6 | + * | |
| 7 | + * Libav is free software; you can redistribute it and/or | |
| 8 | + * modify it under the terms of the GNU Lesser General Public | |
| 9 | + * License as published by the Free Software Foundation; either | |
| 10 | + * version 2.1 of the License, or (at your option) any later version. | |
| 11 | + * | |
| 12 | + * Libav is distributed in the hope that it will be useful, | |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 | + * Lesser General Public License for more details. | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU Lesser General Public | |
| 18 | + * License along with Libav; if not, write to the Free Software | |
| 19 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#include <stdint.h> | |
| 23 | +#include <stdio.h> | |
| 24 | + | |
| 25 | +#include "libavutil/avstring.h" | |
| 26 | +#include "libavutil/lfg.h" | |
| 27 | +#include "libavutil/libm.h" | |
| 28 | +#include "libavutil/log.h" | |
| 29 | +#include "libavutil/mem.h" | |
| 30 | +#include "libavutil/opt.h" | |
| 31 | +#include "libavutil/samplefmt.h" | |
| 32 | +#include "avresample.h" | |
| 33 | + | |
| 34 | +static double dbl_rand(AVLFG *lfg) | |
| 35 | +{ | |
| 36 | + return 2.0 * (av_lfg_get(lfg) / (double)UINT_MAX) - 1.0; | |
| 37 | +} | |
| 38 | + | |
| 39 | +#define PUT_FUNC(name, fmt, type, expr) \ | |
| 40 | +static void put_sample_ ## name(void **data, enum AVSampleFormat sample_fmt,\ | |
| 41 | + int channels, int sample, int ch, \ | |
| 42 | + double v_dbl) \ | |
| 43 | +{ \ | |
| 44 | + type v = expr; \ | |
| 45 | + type **out = (type **)data; \ | |
| 46 | + if (av_sample_fmt_is_planar(sample_fmt)) \ | |
| 47 | + out[ch][sample] = v; \ | |
| 48 | + else \ | |
| 49 | + out[0][sample * channels + ch] = v; \ | |
| 50 | +} | |
| 51 | + | |
| 52 | +PUT_FUNC(u8, AV_SAMPLE_FMT_U8, uint8_t, av_clip_uint8 ( lrint(v_dbl * (1 << 7)) + 128)) | |
| 53 | +PUT_FUNC(s16, AV_SAMPLE_FMT_S16, int16_t, av_clip_int16 ( lrint(v_dbl * (1 << 15)))) | |
| 54 | +PUT_FUNC(s32, AV_SAMPLE_FMT_S32, int32_t, av_clipl_int32(llrint(v_dbl * (1U << 31)))) | |
| 55 | +PUT_FUNC(flt, AV_SAMPLE_FMT_FLT, float, v_dbl) | |
| 56 | +PUT_FUNC(dbl, AV_SAMPLE_FMT_DBL, double, v_dbl) | |
| 57 | + | |
| 58 | +static void put_sample(void **data, enum AVSampleFormat sample_fmt, | |
| 59 | + int channels, int sample, int ch, double v_dbl) | |
| 60 | +{ | |
| 61 | + switch (av_get_packed_sample_fmt(sample_fmt)) { | |
| 62 | + case AV_SAMPLE_FMT_U8: | |
| 63 | + put_sample_u8(data, sample_fmt, channels, sample, ch, v_dbl); | |
| 64 | + break; | |
| 65 | + case AV_SAMPLE_FMT_S16: | |
| 66 | + put_sample_s16(data, sample_fmt, channels, sample, ch, v_dbl); | |
| 67 | + break; | |
| 68 | + case AV_SAMPLE_FMT_S32: | |
| 69 | + put_sample_s32(data, sample_fmt, channels, sample, ch, v_dbl); | |
| 70 | + break; | |
| 71 | + case AV_SAMPLE_FMT_FLT: | |
| 72 | + put_sample_flt(data, sample_fmt, channels, sample, ch, v_dbl); | |
| 73 | + break; | |
| 74 | + case AV_SAMPLE_FMT_DBL: | |
| 75 | + put_sample_dbl(data, sample_fmt, channels, sample, ch, v_dbl); | |
| 76 | + break; | |
| 77 | + } | |
| 78 | +} | |
| 79 | + | |
| 80 | +static void audiogen(AVLFG *rnd, void **data, enum AVSampleFormat sample_fmt, | |
| 81 | + int channels, int sample_rate, int nb_samples) | |
| 82 | +{ | |
| 83 | + int i, ch, k; | |
| 84 | + double v, f, a, ampa; | |
| 85 | + double tabf1[AVRESAMPLE_MAX_CHANNELS]; | |
| 86 | + double tabf2[AVRESAMPLE_MAX_CHANNELS]; | |
| 87 | + double taba[AVRESAMPLE_MAX_CHANNELS]; | |
| 88 | + | |
| 89 | +#define PUT_SAMPLE put_sample(data, sample_fmt, channels, k, ch, v); | |
| 90 | + | |
| 91 | + k = 0; | |
| 92 | + | |
| 93 | + /* 1 second of single freq sinus at 1000 Hz */ | |
| 94 | + a = 0; | |
| 95 | + for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | |
| 96 | + v = sin(a) * 0.30; | |
| 97 | + for (ch = 0; ch < channels; ch++) | |
| 98 | + PUT_SAMPLE | |
| 99 | + a += M_PI * 1000.0 * 2.0 / sample_rate; | |
| 100 | + } | |
| 101 | + | |
| 102 | + /* 1 second of varing frequency between 100 and 10000 Hz */ | |
| 103 | + a = 0; | |
| 104 | + for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | |
| 105 | + v = sin(a) * 0.30; | |
| 106 | + for (ch = 0; ch < channels; ch++) | |
| 107 | + PUT_SAMPLE | |
| 108 | + f = 100.0 + (((10000.0 - 100.0) * i) / sample_rate); | |
| 109 | + a += M_PI * f * 2.0 / sample_rate; | |
| 110 | + } | |
| 111 | + | |
| 112 | + /* 0.5 second of low amplitude white noise */ | |
| 113 | + for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | |
| 114 | + v = dbl_rand(rnd) * 0.30; | |
| 115 | + for (ch = 0; ch < channels; ch++) | |
| 116 | + PUT_SAMPLE | |
| 117 | + } | |
| 118 | + | |
| 119 | + /* 0.5 second of high amplitude white noise */ | |
| 120 | + for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | |
| 121 | + v = dbl_rand(rnd); | |
| 122 | + for (ch = 0; ch < channels; ch++) | |
| 123 | + PUT_SAMPLE | |
| 124 | + } | |
| 125 | + | |
| 126 | + /* 1 second of unrelated ramps for each channel */ | |
| 127 | + for (ch = 0; ch < channels; ch++) { | |
| 128 | + taba[ch] = 0; | |
| 129 | + tabf1[ch] = 100 + av_lfg_get(rnd) % 5000; | |
| 130 | + tabf2[ch] = 100 + av_lfg_get(rnd) % 5000; | |
| 131 | + } | |
| 132 | + for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | |
| 133 | + for (ch = 0; ch < channels; ch++) { | |
| 134 | + v = sin(taba[ch]) * 0.30; | |
| 135 | + PUT_SAMPLE | |
| 136 | + f = tabf1[ch] + (((tabf2[ch] - tabf1[ch]) * i) / sample_rate); | |
| 137 | + taba[ch] += M_PI * f * 2.0 / sample_rate; | |
| 138 | + } | |
| 139 | + } | |
| 140 | + | |
| 141 | + /* 2 seconds of 500 Hz with varying volume */ | |
| 142 | + a = 0; | |
| 143 | + ampa = 0; | |
| 144 | + for (i = 0; i < 2 * sample_rate && k < nb_samples; i++, k++) { | |
| 145 | + for (ch = 0; ch < channels; ch++) { | |
| 146 | + double amp = (1.0 + sin(ampa)) * 0.15; | |
| 147 | + if (ch & 1) | |
| 148 | + amp = 0.30 - amp; | |
| 149 | + v = sin(a) * amp; | |
| 150 | + PUT_SAMPLE | |
| 151 | + a += M_PI * 500.0 * 2.0 / sample_rate; | |
| 152 | + ampa += M_PI * 2.0 / sample_rate; | |
| 153 | + } | |
| 154 | + } | |
| 155 | +} | |
| 156 | + | |
| 157 | +/* formats, rates, and layouts are ordered for priority in testing. | |
| 158 | + e.g. 'avresample-test 4 2 2' will test all input/output combinations of | |
| 159 | + S16/FLTP/S16P/FLT, 48000/44100, and stereo/mono */ | |
| 160 | + | |
| 161 | +static const enum AVSampleFormat formats[] = { | |
| 162 | + AV_SAMPLE_FMT_S16, | |
| 163 | + AV_SAMPLE_FMT_FLTP, | |
| 164 | + AV_SAMPLE_FMT_S16P, | |
| 165 | + AV_SAMPLE_FMT_FLT, | |
| 166 | + AV_SAMPLE_FMT_S32P, | |
| 167 | + AV_SAMPLE_FMT_S32, | |
| 168 | + AV_SAMPLE_FMT_U8P, | |
| 169 | + AV_SAMPLE_FMT_U8, | |
| 170 | + AV_SAMPLE_FMT_DBLP, | |
| 171 | + AV_SAMPLE_FMT_DBL, | |
| 172 | +}; | |
| 173 | + | |
| 174 | +static const int rates[] = { | |
| 175 | + 48000, | |
| 176 | + 44100, | |
| 177 | + 16000 | |
| 178 | +}; | |
| 179 | + | |
| 180 | +static const uint64_t layouts[] = { | |
| 181 | + AV_CH_LAYOUT_STEREO, | |
| 182 | + AV_CH_LAYOUT_MONO, | |
| 183 | + AV_CH_LAYOUT_5POINT1, | |
| 184 | + AV_CH_LAYOUT_7POINT1, | |
| 185 | +}; | |
| 186 | + | |
| 187 | +int main(int argc, char **argv) | |
| 188 | +{ | |
| 189 | + AVAudioResampleContext *s; | |
| 190 | + AVLFG rnd; | |
| 191 | + int ret = 0; | |
| 192 | + uint8_t *in_buf = NULL; | |
| 193 | + uint8_t *out_buf = NULL; | |
| 194 | + unsigned int in_buf_size; | |
| 195 | + unsigned int out_buf_size; | |
| 196 | + uint8_t *in_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | |
| 197 | + uint8_t *out_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | |
| 198 | + int in_linesize; | |
| 199 | + int out_linesize; | |
| 200 | + uint64_t in_ch_layout; | |
| 201 | + int in_channels; | |
| 202 | + enum AVSampleFormat in_fmt; | |
| 203 | + int in_rate; | |
| 204 | + uint64_t out_ch_layout; | |
| 205 | + int out_channels; | |
| 206 | + enum AVSampleFormat out_fmt; | |
| 207 | + int out_rate; | |
| 208 | + int num_formats, num_rates, num_layouts; | |
| 209 | + int i, j, k, l, m, n; | |
| 210 | + | |
| 211 | + num_formats = 2; | |
| 212 | + num_rates = 2; | |
| 213 | + num_layouts = 2; | |
| 214 | + if (argc > 1) { | |
| 215 | + if (!av_strncasecmp(argv[1], "-h", 3)) { | |
| 216 | + av_log(NULL, AV_LOG_INFO, "Usage: avresample-test [<num formats> " | |
| 217 | + "[<num sample rates> [<num channel layouts>]]]\n" | |
| 218 | + "Default is 2 2 2\n"); | |
| 219 | + return 0; | |
| 220 | + } | |
| 221 | + num_formats = strtol(argv[1], NULL, 0); | |
| 222 | + num_formats = av_clip(num_formats, 1, FF_ARRAY_ELEMS(formats)); | |
| 223 | + } | |
| 224 | + if (argc > 2) { | |
| 225 | + num_rates = strtol(argv[2], NULL, 0); | |
| 226 | + num_rates = av_clip(num_rates, 1, FF_ARRAY_ELEMS(rates)); | |
| 227 | + } | |
| 228 | + if (argc > 3) { | |
| 229 | + num_layouts = strtol(argv[3], NULL, 0); | |
| 230 | + num_layouts = av_clip(num_layouts, 1, FF_ARRAY_ELEMS(layouts)); | |
| 231 | + } | |
| 232 | + | |
| 233 | + av_log_set_level(AV_LOG_DEBUG); | |
| 234 | + | |
| 235 | + av_lfg_init(&rnd, 0xC0FFEE); | |
| 236 | + | |
| 237 | + in_buf_size = av_samples_get_buffer_size(&in_linesize, 8, 48000 * 6, | |
| 238 | + AV_SAMPLE_FMT_DBLP, 0); | |
| 239 | + out_buf_size = in_buf_size; | |
| 240 | + | |
| 241 | + in_buf = av_malloc(in_buf_size); | |
| 242 | + if (!in_buf) | |
| 243 | + goto end; | |
| 244 | + out_buf = av_malloc(out_buf_size); | |
| 245 | + if (!out_buf) | |
| 246 | + goto end; | |
| 247 | + | |
| 248 | + s = avresample_alloc_context(); | |
| 249 | + if (!s) { | |
| 250 | + av_log(NULL, AV_LOG_ERROR, "Error allocating AVAudioResampleContext\n"); | |
| 251 | + ret = 1; | |
| 252 | + goto end; | |
| 253 | + } | |
| 254 | + | |
| 255 | + for (i = 0; i < num_formats; i++) { | |
| 256 | + in_fmt = formats[i]; | |
| 257 | + for (k = 0; k < num_layouts; k++) { | |
| 258 | + in_ch_layout = layouts[k]; | |
| 259 | + in_channels = av_get_channel_layout_nb_channels(in_ch_layout); | |
| 260 | + for (m = 0; m < num_rates; m++) { | |
| 261 | + in_rate = rates[m]; | |
| 262 | + | |
| 263 | + ret = av_samples_fill_arrays(in_data, &in_linesize, in_buf, | |
| 264 | + in_channels, in_rate * 6, | |
| 265 | + in_fmt, 0); | |
| 266 | + if (ret < 0) { | |
| 267 | + av_log(s, AV_LOG_ERROR, "failed in_data fill arrays\n"); | |
| 268 | + goto end; | |
| 269 | + } | |
| 270 | + audiogen(&rnd, (void **)in_data, in_fmt, in_channels, in_rate, in_rate * 6); | |
| 271 | + | |
| 272 | + for (j = 0; j < num_formats; j++) { | |
| 273 | + out_fmt = formats[j]; | |
| 274 | + for (l = 0; l < num_layouts; l++) { | |
| 275 | + out_ch_layout = layouts[l]; | |
| 276 | + out_channels = av_get_channel_layout_nb_channels(out_ch_layout); | |
| 277 | + for (n = 0; n < num_rates; n++) { | |
| 278 | + out_rate = rates[n]; | |
| 279 | + | |
| 280 | + av_log(NULL, AV_LOG_INFO, "%s to %s, %d to %d channels, %d Hz to %d Hz\n", | |
| 281 | + av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt), | |
| 282 | + in_channels, out_channels, in_rate, out_rate); | |
| 283 | + | |
| 284 | + ret = av_samples_fill_arrays(out_data, &out_linesize, | |
| 285 | + out_buf, out_channels, | |
| 286 | + out_rate * 6, out_fmt, 0); | |
| 287 | + if (ret < 0) { | |
| 288 | + av_log(s, AV_LOG_ERROR, "failed out_data fill arrays\n"); | |
| 289 | + goto end; | |
| 290 | + } | |
| 291 | + | |
| 292 | + av_opt_set_int(s, "in_channel_layout", in_ch_layout, 0); | |
| 293 | + av_opt_set_int(s, "in_sample_fmt", in_fmt, 0); | |
| 294 | + av_opt_set_int(s, "in_sample_rate", in_rate, 0); | |
| 295 | + av_opt_set_int(s, "out_channel_layout", out_ch_layout, 0); | |
| 296 | + av_opt_set_int(s, "out_sample_fmt", out_fmt, 0); | |
| 297 | + av_opt_set_int(s, "out_sample_rate", out_rate, 0); | |
| 298 | + | |
| 299 | + av_opt_set_int(s, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); | |
| 300 | + | |
| 301 | + ret = avresample_open(s); | |
| 302 | + if (ret < 0) { | |
| 303 | + av_log(s, AV_LOG_ERROR, "Error opening context\n"); | |
| 304 | + goto end; | |
| 305 | + } | |
| 306 | + | |
| 307 | + ret = avresample_convert(s, (void **)out_data, out_linesize, out_rate * 6, | |
| 308 | + (void **) in_data, in_linesize, in_rate * 6); | |
| 309 | + if (ret < 0) { | |
| 310 | + char errbuf[256]; | |
| 311 | + av_strerror(ret, errbuf, sizeof(errbuf)); | |
| 312 | + av_log(NULL, AV_LOG_ERROR, "%s\n", errbuf); | |
| 313 | + goto end; | |
| 314 | + } | |
| 315 | + av_log(NULL, AV_LOG_INFO, "Converted %d samples to %d samples\n", | |
| 316 | + in_rate * 6, ret); | |
| 317 | + if (avresample_get_delay(s) > 0) | |
| 318 | + av_log(NULL, AV_LOG_INFO, "%d delay samples not converted\n", | |
| 319 | + avresample_get_delay(s)); | |
| 320 | + if (avresample_available(s) > 0) | |
| 321 | + av_log(NULL, AV_LOG_INFO, "%d samples available for output\n", | |
| 322 | + avresample_available(s)); | |
| 323 | + av_log(NULL, AV_LOG_INFO, "\n"); | |
| 324 | + | |
| 325 | + avresample_close(s); | |
| 326 | + } | |
| 327 | + } | |
| 328 | + } | |
| 329 | + } | |
| 330 | + } | |
| 331 | + } | |
| 332 | + | |
| 333 | + ret = 0; | |
| 334 | + | |
| 335 | +end: | |
| 336 | + av_freep(&in_buf); | |
| 337 | + av_freep(&out_buf); | |
| 338 | + avresample_free(&s); | |
| 339 | + return ret; | |
| 340 | +} | |
| @@ -0,0 +1,283 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#ifndef AVRESAMPLE_AVRESAMPLE_H | |
| 22 | +#define AVRESAMPLE_AVRESAMPLE_H | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * @file | |
| 26 | + * external API header | |
| 27 | + */ | |
| 28 | + | |
| 29 | +#include "libavutil/audioconvert.h" | |
| 30 | +#include "libavutil/avutil.h" | |
| 31 | +#include "libavutil/dict.h" | |
| 32 | +#include "libavutil/log.h" | |
| 33 | + | |
| 34 | +#include "libavresample/version.h" | |
| 35 | + | |
| 36 | +#define AVRESAMPLE_MAX_CHANNELS 32 | |
| 37 | + | |
| 38 | +typedef struct AVAudioResampleContext AVAudioResampleContext; | |
| 39 | + | |
| 40 | +/** Mixing Coefficient Types */ | |
| 41 | +enum AVMixCoeffType { | |
| 42 | + AV_MIX_COEFF_TYPE_Q6, /** 16-bit 10.6 fixed-point */ | |
| 43 | + AV_MIX_COEFF_TYPE_Q15, /** 32-bit 17.15 fixed-point */ | |
| 44 | + AV_MIX_COEFF_TYPE_FLT, /** floating-point */ | |
| 45 | + AV_MIX_COEFF_TYPE_NB, /** Number of coeff types. Not part of ABI */ | |
| 46 | +}; | |
| 47 | + | |
| 48 | +/** | |
| 49 | + * Return the LIBAVRESAMPLE_VERSION_INT constant. | |
| 50 | + */ | |
| 51 | +unsigned avresample_version(void); | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * Return the libavresample build-time configuration. | |
| 55 | + * @return configure string | |
| 56 | + */ | |
| 57 | +const char *avresample_configuration(void); | |
| 58 | + | |
| 59 | +/** | |
| 60 | + * Return the libavresample license. | |
| 61 | + */ | |
| 62 | +const char *avresample_license(void); | |
| 63 | + | |
| 64 | +/** | |
| 65 | + * Get the AVClass for AVAudioResampleContext. | |
| 66 | + * | |
| 67 | + * Can be used in combination with AV_OPT_SEARCH_FAKE_OBJ for examining options | |
| 68 | + * without allocating a context. | |
| 69 | + * | |
| 70 | + * @see av_opt_find(). | |
| 71 | + * | |
| 72 | + * @return AVClass for AVAudioResampleContext | |
| 73 | + */ | |
| 74 | +const AVClass *avresample_get_class(void); | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Allocate AVAudioResampleContext and set options. | |
| 78 | + * | |
| 79 | + * @return allocated audio resample context, or NULL on failure | |
| 80 | + */ | |
| 81 | +AVAudioResampleContext *avresample_alloc_context(void); | |
| 82 | + | |
| 83 | +/** | |
| 84 | + * Initialize AVAudioResampleContext. | |
| 85 | + * | |
| 86 | + * @param avr audio resample context | |
| 87 | + * @return 0 on success, negative AVERROR code on failure | |
| 88 | + */ | |
| 89 | +int avresample_open(AVAudioResampleContext *avr); | |
| 90 | + | |
| 91 | +/** | |
| 92 | + * Close AVAudioResampleContext. | |
| 93 | + * | |
| 94 | + * This closes the context, but it does not change the parameters. The context | |
| 95 | + * can be reopened with avresample_open(). It does, however, clear the output | |
| 96 | + * FIFO and any remaining leftover samples in the resampling delay buffer. If | |
| 97 | + * there was a custom matrix being used, that is also cleared. | |
| 98 | + * | |
| 99 | + * @see avresample_convert() | |
| 100 | + * @see avresample_set_matrix() | |
| 101 | + * | |
| 102 | + * @param avr audio resample context | |
| 103 | + */ | |
| 104 | +void avresample_close(AVAudioResampleContext *avr); | |
| 105 | + | |
| 106 | +/** | |
| 107 | + * Free AVAudioResampleContext and associated AVOption values. | |
| 108 | + * | |
| 109 | + * This also calls avresample_close() before freeing. | |
| 110 | + * | |
| 111 | + * @param avr audio resample context | |
| 112 | + */ | |
| 113 | +void avresample_free(AVAudioResampleContext **avr); | |
| 114 | + | |
| 115 | +/** | |
| 116 | + * Generate a channel mixing matrix. | |
| 117 | + * | |
| 118 | + * This function is the one used internally by libavresample for building the | |
| 119 | + * default mixing matrix. It is made public just as a utility function for | |
| 120 | + * building custom matrices. | |
| 121 | + * | |
| 122 | + * @param in_layout input channel layout | |
| 123 | + * @param out_layout output channel layout | |
| 124 | + * @param center_mix_level mix level for the center channel | |
| 125 | + * @param surround_mix_level mix level for the surround channel(s) | |
| 126 | + * @param lfe_mix_level mix level for the low-frequency effects channel | |
| 127 | + * @param normalize if 1, coefficients will be normalized to prevent | |
| 128 | + * overflow. if 0, coefficients will not be | |
| 129 | + * normalized. | |
| 130 | + * @param[out] matrix mixing coefficients; matrix[i + stride * o] is | |
| 131 | + * the weight of input channel i in output channel o. | |
| 132 | + * @param stride distance between adjacent input channels in the | |
| 133 | + * matrix array | |
| 134 | + * @return 0 on success, negative AVERROR code on failure | |
| 135 | + */ | |
| 136 | +int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, | |
| 137 | + double center_mix_level, double surround_mix_level, | |
| 138 | + double lfe_mix_level, int normalize, double *matrix, | |
| 139 | + int stride); | |
| 140 | + | |
| 141 | +/** | |
| 142 | + * Get the current channel mixing matrix. | |
| 143 | + * | |
| 144 | + * @param avr audio resample context | |
| 145 | + * @param matrix mixing coefficients; matrix[i + stride * o] is the weight of | |
| 146 | + * input channel i in output channel o. | |
| 147 | + * @param stride distance between adjacent input channels in the matrix array | |
| 148 | + * @return 0 on success, negative AVERROR code on failure | |
| 149 | + */ | |
| 150 | +int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, | |
| 151 | + int stride); | |
| 152 | + | |
| 153 | +/** | |
| 154 | + * Set channel mixing matrix. | |
| 155 | + * | |
| 156 | + * Allows for setting a custom mixing matrix, overriding the default matrix | |
| 157 | + * generated internally during avresample_open(). This function can be called | |
| 158 | + * anytime on an allocated context, either before or after calling | |
| 159 | + * avresample_open(). avresample_convert() always uses the current matrix. | |
| 160 | + * Calling avresample_close() on the context will clear the current matrix. | |
| 161 | + * | |
| 162 | + * @see avresample_close() | |
| 163 | + * | |
| 164 | + * @param avr audio resample context | |
| 165 | + * @param matrix mixing coefficients; matrix[i + stride * o] is the weight of | |
| 166 | + * input channel i in output channel o. | |
| 167 | + * @param stride distance between adjacent input channels in the matrix array | |
| 168 | + * @return 0 on success, negative AVERROR code on failure | |
| 169 | + */ | |
| 170 | +int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, | |
| 171 | + int stride); | |
| 172 | + | |
| 173 | +/** | |
| 174 | + * Set compensation for resampling. | |
| 175 | + * | |
| 176 | + * This can be called anytime after avresample_open(). If resampling was not | |
| 177 | + * being done previously, the AVAudioResampleContext is closed and reopened | |
| 178 | + * with resampling enabled. In this case, any samples remaining in the output | |
| 179 | + * FIFO and the current channel mixing matrix will be restored after reopening | |
| 180 | + * the context. | |
| 181 | + * | |
| 182 | + * @param avr audio resample context | |
| 183 | + * @param sample_delta compensation delta, in samples | |
| 184 | + * @param compensation_distance compensation distance, in samples | |
| 185 | + * @return 0 on success, negative AVERROR code on failure | |
| 186 | + */ | |
| 187 | +int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, | |
| 188 | + int compensation_distance); | |
| 189 | + | |
| 190 | +/** | |
| 191 | + * Convert input samples and write them to the output FIFO. | |
| 192 | + * | |
| 193 | + * The output data can be NULL or have fewer allocated samples than required. | |
| 194 | + * In this case, any remaining samples not written to the output will be added | |
| 195 | + * to an internal FIFO buffer, to be returned at the next call to this function | |
| 196 | + * or to avresample_read(). | |
| 197 | + * | |
| 198 | + * If converting sample rate, there may be data remaining in the internal | |
| 199 | + * resampling delay buffer. avresample_get_delay() tells the number of remaining | |
| 200 | + * samples. To get this data as output, call avresample_convert() with NULL | |
| 201 | + * input. | |
| 202 | + * | |
| 203 | + * At the end of the conversion process, there may be data remaining in the | |
| 204 | + * internal FIFO buffer. avresample_available() tells the number of remaining | |
| 205 | + * samples. To get this data as output, either call avresample_convert() with | |
| 206 | + * NULL input or call avresample_read(). | |
| 207 | + * | |
| 208 | + * @see avresample_available() | |
| 209 | + * @see avresample_read() | |
| 210 | + * @see avresample_get_delay() | |
| 211 | + * | |
| 212 | + * @param avr audio resample context | |
| 213 | + * @param output output data pointers | |
| 214 | + * @param out_plane_size output plane size, in bytes. | |
| 215 | + * This can be 0 if unknown, but that will lead to | |
| 216 | + * optimized functions not being used directly on the | |
| 217 | + * output, which could slow down some conversions. | |
| 218 | + * @param out_samples maximum number of samples that the output buffer can hold | |
| 219 | + * @param input input data pointers | |
| 220 | + * @param in_plane_size input plane size, in bytes | |
| 221 | + * This can be 0 if unknown, but that will lead to | |
| 222 | + * optimized functions not being used directly on the | |
| 223 | + * input, which could slow down some conversions. | |
| 224 | + * @param in_samples number of input samples to convert | |
| 225 | + * @return number of samples written to the output buffer, | |
| 226 | + * not including converted samples added to the internal | |
| 227 | + * output FIFO | |
| 228 | + */ | |
| 229 | +int avresample_convert(AVAudioResampleContext *avr, void **output, | |
| 230 | + int out_plane_size, int out_samples, void **input, | |
| 231 | + int in_plane_size, int in_samples); | |
| 232 | + | |
| 233 | +/** | |
| 234 | + * Return the number of samples currently in the resampling delay buffer. | |
| 235 | + * | |
| 236 | + * When resampling, there may be a delay between the input and output. Any | |
| 237 | + * unconverted samples in each call are stored internally in a delay buffer. | |
| 238 | + * This function allows the user to determine the current number of samples in | |
| 239 | + * the delay buffer, which can be useful for synchronization. | |
| 240 | + * | |
| 241 | + * @see avresample_convert() | |
| 242 | + * | |
| 243 | + * @param avr audio resample context | |
| 244 | + * @return number of samples currently in the resampling delay buffer | |
| 245 | + */ | |
| 246 | +int avresample_get_delay(AVAudioResampleContext *avr); | |
| 247 | + | |
| 248 | +/** | |
| 249 | + * Return the number of available samples in the output FIFO. | |
| 250 | + * | |
| 251 | + * During conversion, if the user does not specify an output buffer or | |
| 252 | + * specifies an output buffer that is smaller than what is needed, remaining | |
| 253 | + * samples that are not written to the output are stored to an internal FIFO | |
| 254 | + * buffer. The samples in the FIFO can be read with avresample_read() or | |
| 255 | + * avresample_convert(). | |
| 256 | + * | |
| 257 | + * @see avresample_read() | |
| 258 | + * @see avresample_convert() | |
| 259 | + * | |
| 260 | + * @param avr audio resample context | |
| 261 | + * @return number of samples available for reading | |
| 262 | + */ | |
| 263 | +int avresample_available(AVAudioResampleContext *avr); | |
| 264 | + | |
| 265 | +/** | |
| 266 | + * Read samples from the output FIFO. | |
| 267 | + * | |
| 268 | + * During conversion, if the user does not specify an output buffer or | |
| 269 | + * specifies an output buffer that is smaller than what is needed, remaining | |
| 270 | + * samples that are not written to the output are stored to an internal FIFO | |
| 271 | + * buffer. This function can be used to read samples from that internal FIFO. | |
| 272 | + * | |
| 273 | + * @see avresample_available() | |
| 274 | + * @see avresample_convert() | |
| 275 | + * | |
| 276 | + * @param avr audio resample context | |
| 277 | + * @param output output data pointers | |
| 278 | + * @param nb_samples number of samples to read from the FIFO | |
| 279 | + * @return the number of samples written to output | |
| 280 | + */ | |
| 281 | +int avresample_read(AVAudioResampleContext *avr, void **output, int nb_samples); | |
| 282 | + | |
| 283 | +#endif /* AVRESAMPLE_AVRESAMPLE_H */ | |
| @@ -0,0 +1,75 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#ifndef AVRESAMPLE_INTERNAL_H | |
| 22 | +#define AVRESAMPLE_INTERNAL_H | |
| 23 | + | |
| 24 | +#include "libavutil/audio_fifo.h" | |
| 25 | +#include "libavutil/log.h" | |
| 26 | +#include "libavutil/opt.h" | |
| 27 | +#include "libavutil/samplefmt.h" | |
| 28 | +#include "avresample.h" | |
| 29 | +#include "audio_convert.h" | |
| 30 | +#include "audio_data.h" | |
| 31 | +#include "audio_mix.h" | |
| 32 | +#include "resample.h" | |
| 33 | + | |
| 34 | +struct AVAudioResampleContext { | |
| 35 | + const AVClass *av_class; /**< AVClass for logging and AVOptions */ | |
| 36 | + | |
| 37 | + uint64_t in_channel_layout; /**< input channel layout */ | |
| 38 | + enum AVSampleFormat in_sample_fmt; /**< input sample format */ | |
| 39 | + int in_sample_rate; /**< input sample rate */ | |
| 40 | + uint64_t out_channel_layout; /**< output channel layout */ | |
| 41 | + enum AVSampleFormat out_sample_fmt; /**< output sample format */ | |
| 42 | + int out_sample_rate; /**< output sample rate */ | |
| 43 | + enum AVSampleFormat internal_sample_fmt; /**< internal sample format */ | |
| 44 | + enum AVMixCoeffType mix_coeff_type; /**< mixing coefficient type */ | |
| 45 | + double center_mix_level; /**< center mix level */ | |
| 46 | + double surround_mix_level; /**< surround mix level */ | |
| 47 | + double lfe_mix_level; /**< lfe mix level */ | |
| 48 | + int force_resampling; /**< force resampling */ | |
| 49 | + int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */ | |
| 50 | + int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */ | |
| 51 | + int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */ | |
| 52 | + double cutoff; /**< resampling cutoff frequency. 1.0 corresponds to half the output sample rate */ | |
| 53 | + | |
| 54 | + int in_channels; /**< number of input channels */ | |
| 55 | + int out_channels; /**< number of output channels */ | |
| 56 | + int resample_channels; /**< number of channels used for resampling */ | |
| 57 | + int downmix_needed; /**< downmixing is needed */ | |
| 58 | + int upmix_needed; /**< upmixing is needed */ | |
| 59 | + int mixing_needed; /**< either upmixing or downmixing is needed */ | |
| 60 | + int resample_needed; /**< resampling is needed */ | |
| 61 | + int in_convert_needed; /**< input sample format conversion is needed */ | |
| 62 | + int out_convert_needed; /**< output sample format conversion is needed */ | |
| 63 | + | |
| 64 | + AudioData *in_buffer; /**< buffer for converted input */ | |
| 65 | + AudioData *resample_out_buffer; /**< buffer for output from resampler */ | |
| 66 | + AudioData *out_buffer; /**< buffer for converted output */ | |
| 67 | + AVAudioFifo *out_fifo; /**< FIFO for output samples */ | |
| 68 | + | |
| 69 | + AudioConvert *ac_in; /**< input sample format conversion context */ | |
| 70 | + AudioConvert *ac_out; /**< output sample format conversion context */ | |
| 71 | + ResampleContext *resample; /**< resampling context */ | |
| 72 | + AudioMix *am; /**< channel mixing context */ | |
| 73 | +}; | |
| 74 | + | |
| 75 | +#endif /* AVRESAMPLE_INTERNAL_H */ | |
| @@ -0,0 +1,4 @@ | ||
| 1 | +LIBAVRESAMPLE_$MAJOR { | |
| 2 | + global: av*; | |
| 3 | + local: *; | |
| 4 | +}; | |
| @@ -0,0 +1,89 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include "libavutil/mathematics.h" | |
| 22 | +#include "libavutil/opt.h" | |
| 23 | +#include "avresample.h" | |
| 24 | +#include "internal.h" | |
| 25 | +#include "audio_mix.h" | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * @file | |
| 29 | + * Options definition for AVAudioResampleContext. | |
| 30 | + */ | |
| 31 | + | |
| 32 | +#define OFFSET(x) offsetof(AVAudioResampleContext, x) | |
| 33 | +#define PARAM AV_OPT_FLAG_AUDIO_PARAM | |
| 34 | + | |
| 35 | +static const AVOption options[] = { | |
| 36 | + { "in_channel_layout", "Input Channel Layout", OFFSET(in_channel_layout), AV_OPT_TYPE_INT64, { 0 }, INT64_MIN, INT64_MAX, PARAM }, | |
| 37 | + { "in_sample_fmt", "Input Sample Format", OFFSET(in_sample_fmt), AV_OPT_TYPE_INT, { AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NB-1, PARAM }, | |
| 38 | + { "in_sample_rate", "Input Sample Rate", OFFSET(in_sample_rate), AV_OPT_TYPE_INT, { 48000 }, 1, INT_MAX, PARAM }, | |
| 39 | + { "out_channel_layout", "Output Channel Layout", OFFSET(out_channel_layout), AV_OPT_TYPE_INT64, { 0 }, INT64_MIN, INT64_MAX, PARAM }, | |
| 40 | + { "out_sample_fmt", "Output Sample Format", OFFSET(out_sample_fmt), AV_OPT_TYPE_INT, { AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NB-1, PARAM }, | |
| 41 | + { "out_sample_rate", "Output Sample Rate", OFFSET(out_sample_rate), AV_OPT_TYPE_INT, { 48000 }, 1, INT_MAX, PARAM }, | |
| 42 | + { "internal_sample_fmt", "Internal Sample Format", OFFSET(internal_sample_fmt), AV_OPT_TYPE_INT, { AV_SAMPLE_FMT_FLTP }, AV_SAMPLE_FMT_NONE, AV_SAMPLE_FMT_NB-1, PARAM }, | |
| 43 | + { "mix_coeff_type", "Mixing Coefficient Type", OFFSET(mix_coeff_type), AV_OPT_TYPE_INT, { AV_MIX_COEFF_TYPE_FLT }, AV_MIX_COEFF_TYPE_Q6, AV_MIX_COEFF_TYPE_NB-1, PARAM, "mix_coeff_type" }, | |
| 44 | + { "q6", "16-bit 10.6 Fixed-Point", 0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_Q6 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | |
| 45 | + { "q15", "32-bit 17.15 Fixed-Point", 0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_Q15 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | |
| 46 | + { "flt", "Floating-Point", 0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_FLT }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | |
| 47 | + { "center_mix_level", "Center Mix Level", OFFSET(center_mix_level), AV_OPT_TYPE_DOUBLE, { M_SQRT1_2 }, -32.0, 32.0, PARAM }, | |
| 48 | + { "surround_mix_level", "Surround Mix Level", OFFSET(surround_mix_level), AV_OPT_TYPE_DOUBLE, { M_SQRT1_2 }, -32.0, 32.0, PARAM }, | |
| 49 | + { "lfe_mix_level", "LFE Mix Level", OFFSET(lfe_mix_level), AV_OPT_TYPE_DOUBLE, { 0.0 }, -32.0, 32.0, PARAM }, | |
| 50 | + { "force_resampling", "Force Resampling", OFFSET(force_resampling), AV_OPT_TYPE_INT, { 0 }, 0, 1, PARAM }, | |
| 51 | + { "filter_size", "Resampling Filter Size", OFFSET(filter_size), AV_OPT_TYPE_INT, { 16 }, 0, 32, /* ??? */ PARAM }, | |
| 52 | + { "phase_shift", "Resampling Phase Shift", OFFSET(phase_shift), AV_OPT_TYPE_INT, { 10 }, 0, 30, /* ??? */ PARAM }, | |
| 53 | + { "linear_interp", "Use Linear Interpolation", OFFSET(linear_interp), AV_OPT_TYPE_INT, { 0 }, 0, 1, PARAM }, | |
| 54 | + { "cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, { 0.8 }, 0.0, 1.0, PARAM }, | |
| 55 | + { NULL }, | |
| 56 | +}; | |
| 57 | + | |
| 58 | +static const AVClass av_resample_context_class = { | |
| 59 | + .class_name = "AVAudioResampleContext", | |
| 60 | + .item_name = av_default_item_name, | |
| 61 | + .option = options, | |
| 62 | + .version = LIBAVUTIL_VERSION_INT, | |
| 63 | +}; | |
| 64 | + | |
| 65 | +AVAudioResampleContext *avresample_alloc_context(void) | |
| 66 | +{ | |
| 67 | + AVAudioResampleContext *avr; | |
| 68 | + | |
| 69 | + avr = av_mallocz(sizeof(*avr)); | |
| 70 | + if (!avr) | |
| 71 | + return NULL; | |
| 72 | + | |
| 73 | + avr->av_class = &av_resample_context_class; | |
| 74 | + av_opt_set_defaults(avr); | |
| 75 | + | |
| 76 | + avr->am = av_mallocz(sizeof(*avr->am)); | |
| 77 | + if (!avr->am) { | |
| 78 | + av_free(avr); | |
| 79 | + return NULL; | |
| 80 | + } | |
| 81 | + avr->am->avr = avr; | |
| 82 | + | |
| 83 | + return avr; | |
| 84 | +} | |
| 85 | + | |
| 86 | +const AVClass *avresample_get_class(void) | |
| 87 | +{ | |
| 88 | + return &av_resample_context_class; | |
| 89 | +} | |
| @@ -0,0 +1,480 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> | |
| 3 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 4 | + * | |
| 5 | + * This file is part of Libav. | |
| 6 | + * | |
| 7 | + * Libav is free software; you can redistribute it and/or | |
| 8 | + * modify it under the terms of the GNU Lesser General Public | |
| 9 | + * License as published by the Free Software Foundation; either | |
| 10 | + * version 2.1 of the License, or (at your option) any later version. | |
| 11 | + * | |
| 12 | + * Libav is distributed in the hope that it will be useful, | |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 | + * Lesser General Public License for more details. | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU Lesser General Public | |
| 18 | + * License along with Libav; if not, write to the Free Software | |
| 19 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#include "libavutil/libm.h" | |
| 23 | +#include "libavutil/log.h" | |
| 24 | +#include "internal.h" | |
| 25 | +#include "audio_data.h" | |
| 26 | + | |
| 27 | +#ifdef CONFIG_RESAMPLE_FLT | |
| 28 | +/* float template */ | |
| 29 | +#define FILTER_SHIFT 0 | |
| 30 | +#define FELEM float | |
| 31 | +#define FELEM2 float | |
| 32 | +#define FELEML float | |
| 33 | +#define WINDOW_TYPE 24 | |
| 34 | +#elifdef CONFIG_RESAMPLE_S32 | |
| 35 | +/* s32 template */ | |
| 36 | +#define FILTER_SHIFT 30 | |
| 37 | +#define FELEM int32_t | |
| 38 | +#define FELEM2 int64_t | |
| 39 | +#define FELEML int64_t | |
| 40 | +#define FELEM_MAX INT32_MAX | |
| 41 | +#define FELEM_MIN INT32_MIN | |
| 42 | +#define WINDOW_TYPE 12 | |
| 43 | +#else | |
| 44 | +/* s16 template */ | |
| 45 | +#define FILTER_SHIFT 15 | |
| 46 | +#define FELEM int16_t | |
| 47 | +#define FELEM2 int32_t | |
| 48 | +#define FELEML int64_t | |
| 49 | +#define FELEM_MAX INT16_MAX | |
| 50 | +#define FELEM_MIN INT16_MIN | |
| 51 | +#define WINDOW_TYPE 9 | |
| 52 | +#endif | |
| 53 | + | |
| 54 | +struct ResampleContext { | |
| 55 | + AVAudioResampleContext *avr; | |
| 56 | + AudioData *buffer; | |
| 57 | + FELEM *filter_bank; | |
| 58 | + int filter_length; | |
| 59 | + int ideal_dst_incr; | |
| 60 | + int dst_incr; | |
| 61 | + int index; | |
| 62 | + int frac; | |
| 63 | + int src_incr; | |
| 64 | + int compensation_distance; | |
| 65 | + int phase_shift; | |
| 66 | + int phase_mask; | |
| 67 | + int linear; | |
| 68 | + double factor; | |
| 69 | +}; | |
| 70 | + | |
| 71 | +/** | |
| 72 | + * 0th order modified bessel function of the first kind. | |
| 73 | + */ | |
| 74 | +static double bessel(double x) | |
| 75 | +{ | |
| 76 | + double v = 1; | |
| 77 | + double lastv = 0; | |
| 78 | + double t = 1; | |
| 79 | + int i; | |
| 80 | + | |
| 81 | + x = x * x / 4; | |
| 82 | + for (i = 1; v != lastv; i++) { | |
| 83 | + lastv = v; | |
| 84 | + t *= x / (i * i); | |
| 85 | + v += t; | |
| 86 | + } | |
| 87 | + return v; | |
| 88 | +} | |
| 89 | + | |
| 90 | +/** | |
| 91 | + * Build a polyphase filterbank. | |
| 92 | + * | |
| 93 | + * @param[out] filter filter coefficients | |
| 94 | + * @param factor resampling factor | |
| 95 | + * @param tap_count tap count | |
| 96 | + * @param phase_count phase count | |
| 97 | + * @param scale wanted sum of coefficients for each filter | |
| 98 | + * @param type 0->cubic | |
| 99 | + * 1->blackman nuttall windowed sinc | |
| 100 | + * 2..16->kaiser windowed sinc beta=2..16 | |
| 101 | + * @return 0 on success, negative AVERROR code on failure | |
| 102 | + */ | |
| 103 | +static int build_filter(FELEM *filter, double factor, int tap_count, | |
| 104 | + int phase_count, int scale, int type) | |
| 105 | +{ | |
| 106 | + int ph, i; | |
| 107 | + double x, y, w; | |
| 108 | + double *tab; | |
| 109 | + const int center = (tap_count - 1) / 2; | |
| 110 | + | |
| 111 | + tab = av_malloc(tap_count * sizeof(*tab)); | |
| 112 | + if (!tab) | |
| 113 | + return AVERROR(ENOMEM); | |
| 114 | + | |
| 115 | + /* if upsampling, only need to interpolate, no filter */ | |
| 116 | + if (factor > 1.0) | |
| 117 | + factor = 1.0; | |
| 118 | + | |
| 119 | + for (ph = 0; ph < phase_count; ph++) { | |
| 120 | + double norm = 0; | |
| 121 | + for (i = 0; i < tap_count; i++) { | |
| 122 | + x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor; | |
| 123 | + if (x == 0) y = 1.0; | |
| 124 | + else y = sin(x) / x; | |
| 125 | + switch (type) { | |
| 126 | + case 0: { | |
| 127 | + const float d = -0.5; //first order derivative = -0.5 | |
| 128 | + x = fabs(((double)(i - center) - (double)ph / phase_count) * factor); | |
| 129 | + if (x < 1.0) y = 1 - 3 * x*x + 2 * x*x*x + d * ( -x*x + x*x*x); | |
| 130 | + else y = d * (-4 + 8 * x - 5 * x*x + x*x*x); | |
| 131 | + break; | |
| 132 | + } | |
| 133 | + case 1: | |
| 134 | + w = 2.0 * x / (factor * tap_count) + M_PI; | |
| 135 | + y *= 0.3635819 - 0.4891775 * cos( w) + | |
| 136 | + 0.1365995 * cos(2 * w) - | |
| 137 | + 0.0106411 * cos(3 * w); | |
| 138 | + break; | |
| 139 | + default: | |
| 140 | + w = 2.0 * x / (factor * tap_count * M_PI); | |
| 141 | + y *= bessel(type * sqrt(FFMAX(1 - w * w, 0))); | |
| 142 | + break; | |
| 143 | + } | |
| 144 | + | |
| 145 | + tab[i] = y; | |
| 146 | + norm += y; | |
| 147 | + } | |
| 148 | + | |
| 149 | + /* normalize so that an uniform color remains the same */ | |
| 150 | + for (i = 0; i < tap_count; i++) { | |
| 151 | +#ifdef CONFIG_RESAMPLE_FLT | |
| 152 | + filter[ph * tap_count + i] = tab[i] / norm; | |
| 153 | +#else | |
| 154 | + filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), | |
| 155 | + FELEM_MIN, FELEM_MAX); | |
| 156 | +#endif | |
| 157 | + } | |
| 158 | + } | |
| 159 | + | |
| 160 | + av_free(tab); | |
| 161 | + return 0; | |
| 162 | +} | |
| 163 | + | |
| 164 | +ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr) | |
| 165 | +{ | |
| 166 | + ResampleContext *c; | |
| 167 | + int out_rate = avr->out_sample_rate; | |
| 168 | + int in_rate = avr->in_sample_rate; | |
| 169 | + double factor = FFMIN(out_rate * avr->cutoff / in_rate, 1.0); | |
| 170 | + int phase_count = 1 << avr->phase_shift; | |
| 171 | + | |
| 172 | + /* TODO: add support for s32 and float internal formats */ | |
| 173 | + if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P) { | |
| 174 | + av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " | |
| 175 | + "resampling: %s\n", | |
| 176 | + av_get_sample_fmt_name(avr->internal_sample_fmt)); | |
| 177 | + return NULL; | |
| 178 | + } | |
| 179 | + c = av_mallocz(sizeof(*c)); | |
| 180 | + if (!c) | |
| 181 | + return NULL; | |
| 182 | + | |
| 183 | + c->avr = avr; | |
| 184 | + c->phase_shift = avr->phase_shift; | |
| 185 | + c->phase_mask = phase_count - 1; | |
| 186 | + c->linear = avr->linear_interp; | |
| 187 | + c->factor = factor; | |
| 188 | + c->filter_length = FFMAX((int)ceil(avr->filter_size / factor), 1); | |
| 189 | + | |
| 190 | + c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * sizeof(FELEM)); | |
| 191 | + if (!c->filter_bank) | |
| 192 | + goto error; | |
| 193 | + | |
| 194 | + if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, | |
| 195 | + 1 << FILTER_SHIFT, WINDOW_TYPE) < 0) | |
| 196 | + goto error; | |
| 197 | + | |
| 198 | + memcpy(&c->filter_bank[c->filter_length * phase_count + 1], | |
| 199 | + c->filter_bank, (c->filter_length - 1) * sizeof(FELEM)); | |
| 200 | + c->filter_bank[c->filter_length * phase_count] = c->filter_bank[c->filter_length - 1]; | |
| 201 | + | |
| 202 | + c->compensation_distance = 0; | |
| 203 | + if (!av_reduce(&c->src_incr, &c->dst_incr, out_rate, | |
| 204 | + in_rate * (int64_t)phase_count, INT32_MAX / 2)) | |
| 205 | + goto error; | |
| 206 | + c->ideal_dst_incr = c->dst_incr; | |
| 207 | + | |
| 208 | + c->index = -phase_count * ((c->filter_length - 1) / 2); | |
| 209 | + c->frac = 0; | |
| 210 | + | |
| 211 | + /* allocate internal buffer */ | |
| 212 | + c->buffer = ff_audio_data_alloc(avr->resample_channels, 0, | |
| 213 | + avr->internal_sample_fmt, | |
| 214 | + "resample buffer"); | |
| 215 | + if (!c->buffer) | |
| 216 | + goto error; | |
| 217 | + | |
| 218 | + av_log(avr, AV_LOG_DEBUG, "resample: %s from %d Hz to %d Hz\n", | |
| 219 | + av_get_sample_fmt_name(avr->internal_sample_fmt), | |
| 220 | + avr->in_sample_rate, avr->out_sample_rate); | |
| 221 | + | |
| 222 | + return c; | |
| 223 | + | |
| 224 | +error: | |
| 225 | + ff_audio_data_free(&c->buffer); | |
| 226 | + av_free(c->filter_bank); | |
| 227 | + av_free(c); | |
| 228 | + return NULL; | |
| 229 | +} | |
| 230 | + | |
| 231 | +void ff_audio_resample_free(ResampleContext **c) | |
| 232 | +{ | |
| 233 | + if (!*c) | |
| 234 | + return; | |
| 235 | + ff_audio_data_free(&(*c)->buffer); | |
| 236 | + av_free((*c)->filter_bank); | |
| 237 | + av_freep(c); | |
| 238 | +} | |
| 239 | + | |
| 240 | +int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, | |
| 241 | + int compensation_distance) | |
| 242 | +{ | |
| 243 | + ResampleContext *c; | |
| 244 | + AudioData *fifo_buf = NULL; | |
| 245 | + int ret = 0; | |
| 246 | + | |
| 247 | + if (compensation_distance < 0) | |
| 248 | + return AVERROR(EINVAL); | |
| 249 | + if (!compensation_distance && sample_delta) | |
| 250 | + return AVERROR(EINVAL); | |
| 251 | + | |
| 252 | + /* if resampling was not enabled previously, re-initialize the | |
| 253 | + AVAudioResampleContext and force resampling */ | |
| 254 | + if (!avr->resample_needed) { | |
| 255 | + int fifo_samples; | |
| 256 | + double matrix[AVRESAMPLE_MAX_CHANNELS * AVRESAMPLE_MAX_CHANNELS] = { 0 }; | |
| 257 | + | |
| 258 | + /* buffer any remaining samples in the output FIFO before closing */ | |
| 259 | + fifo_samples = av_audio_fifo_size(avr->out_fifo); | |
| 260 | + if (fifo_samples > 0) { | |
| 261 | + fifo_buf = ff_audio_data_alloc(avr->out_channels, fifo_samples, | |
| 262 | + avr->out_sample_fmt, NULL); | |
| 263 | + if (!fifo_buf) | |
| 264 | + return AVERROR(EINVAL); | |
| 265 | + ret = ff_audio_data_read_from_fifo(avr->out_fifo, fifo_buf, | |
| 266 | + fifo_samples); | |
| 267 | + if (ret < 0) | |
| 268 | + goto reinit_fail; | |
| 269 | + } | |
| 270 | + /* save the channel mixing matrix */ | |
| 271 | + ret = avresample_get_matrix(avr, matrix, AVRESAMPLE_MAX_CHANNELS); | |
| 272 | + if (ret < 0) | |
| 273 | + goto reinit_fail; | |
| 274 | + | |
| 275 | + /* close the AVAudioResampleContext */ | |
| 276 | + avresample_close(avr); | |
| 277 | + | |
| 278 | + avr->force_resampling = 1; | |
| 279 | + | |
| 280 | + /* restore the channel mixing matrix */ | |
| 281 | + ret = avresample_set_matrix(avr, matrix, AVRESAMPLE_MAX_CHANNELS); | |
| 282 | + if (ret < 0) | |
| 283 | + goto reinit_fail; | |
| 284 | + | |
| 285 | + /* re-open the AVAudioResampleContext */ | |
| 286 | + ret = avresample_open(avr); | |
| 287 | + if (ret < 0) | |
| 288 | + goto reinit_fail; | |
| 289 | + | |
| 290 | + /* restore buffered samples to the output FIFO */ | |
| 291 | + if (fifo_samples > 0) { | |
| 292 | + ret = ff_audio_data_add_to_fifo(avr->out_fifo, fifo_buf, 0, | |
| 293 | + fifo_samples); | |
| 294 | + if (ret < 0) | |
| 295 | + goto reinit_fail; | |
| 296 | + ff_audio_data_free(&fifo_buf); | |
| 297 | + } | |
| 298 | + } | |
| 299 | + c = avr->resample; | |
| 300 | + c->compensation_distance = compensation_distance; | |
| 301 | + if (compensation_distance) { | |
| 302 | + c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * | |
| 303 | + (int64_t)sample_delta / compensation_distance; | |
| 304 | + } else { | |
| 305 | + c->dst_incr = c->ideal_dst_incr; | |
| 306 | + } | |
| 307 | + return 0; | |
| 308 | + | |
| 309 | +reinit_fail: | |
| 310 | + ff_audio_data_free(&fifo_buf); | |
| 311 | + return ret; | |
| 312 | +} | |
| 313 | + | |
| 314 | +static int resample(ResampleContext *c, int16_t *dst, const int16_t *src, | |
| 315 | + int *consumed, int src_size, int dst_size, int update_ctx) | |
| 316 | +{ | |
| 317 | + int dst_index, i; | |
| 318 | + int index = c->index; | |
| 319 | + int frac = c->frac; | |
| 320 | + int dst_incr_frac = c->dst_incr % c->src_incr; | |
| 321 | + int dst_incr = c->dst_incr / c->src_incr; | |
| 322 | + int compensation_distance = c->compensation_distance; | |
| 323 | + | |
| 324 | + if (!dst != !src) | |
| 325 | + return AVERROR(EINVAL); | |
| 326 | + | |
| 327 | + if (compensation_distance == 0 && c->filter_length == 1 && | |
| 328 | + c->phase_shift == 0) { | |
| 329 | + int64_t index2 = ((int64_t)index) << 32; | |
| 330 | + int64_t incr = (1LL << 32) * c->dst_incr / c->src_incr; | |
| 331 | + dst_size = FFMIN(dst_size, | |
| 332 | + (src_size-1-index) * (int64_t)c->src_incr / | |
| 333 | + c->dst_incr); | |
| 334 | + | |
| 335 | + if (dst) { | |
| 336 | + for(dst_index = 0; dst_index < dst_size; dst_index++) { | |
| 337 | + dst[dst_index] = src[index2 >> 32]; | |
| 338 | + index2 += incr; | |
| 339 | + } | |
| 340 | + } else { | |
| 341 | + dst_index = dst_size; | |
| 342 | + } | |
| 343 | + index += dst_index * dst_incr; | |
| 344 | + index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr; | |
| 345 | + frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr; | |
| 346 | + } else { | |
| 347 | + for (dst_index = 0; dst_index < dst_size; dst_index++) { | |
| 348 | + FELEM *filter = c->filter_bank + | |
| 349 | + c->filter_length * (index & c->phase_mask); | |
| 350 | + int sample_index = index >> c->phase_shift; | |
| 351 | + | |
| 352 | + if (!dst && (sample_index + c->filter_length > src_size || | |
| 353 | + -sample_index >= src_size)) | |
| 354 | + break; | |
| 355 | + | |
| 356 | + if (dst) { | |
| 357 | + FELEM2 val = 0; | |
| 358 | + | |
| 359 | + if (sample_index < 0) { | |
| 360 | + for (i = 0; i < c->filter_length; i++) | |
| 361 | + val += src[FFABS(sample_index + i) % src_size] * | |
| 362 | + (FELEM2)filter[i]; | |
| 363 | + } else if (sample_index + c->filter_length > src_size) { | |
| 364 | + break; | |
| 365 | + } else if (c->linear) { | |
| 366 | + FELEM2 v2 = 0; | |
| 367 | + for (i = 0; i < c->filter_length; i++) { | |
| 368 | + val += src[abs(sample_index + i)] * (FELEM2)filter[i]; | |
| 369 | + v2 += src[abs(sample_index + i)] * (FELEM2)filter[i + c->filter_length]; | |
| 370 | + } | |
| 371 | + val += (v2 - val) * (FELEML)frac / c->src_incr; | |
| 372 | + } else { | |
| 373 | + for (i = 0; i < c->filter_length; i++) | |
| 374 | + val += src[sample_index + i] * (FELEM2)filter[i]; | |
| 375 | + } | |
| 376 | + | |
| 377 | +#ifdef CONFIG_RESAMPLE_FLT | |
| 378 | + dst[dst_index] = av_clip_int16(lrintf(val)); | |
| 379 | +#else | |
| 380 | + val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; | |
| 381 | + dst[dst_index] = av_clip_int16(val); | |
| 382 | +#endif | |
| 383 | + } | |
| 384 | + | |
| 385 | + frac += dst_incr_frac; | |
| 386 | + index += dst_incr; | |
| 387 | + if (frac >= c->src_incr) { | |
| 388 | + frac -= c->src_incr; | |
| 389 | + index++; | |
| 390 | + } | |
| 391 | + if (dst_index + 1 == compensation_distance) { | |
| 392 | + compensation_distance = 0; | |
| 393 | + dst_incr_frac = c->ideal_dst_incr % c->src_incr; | |
| 394 | + dst_incr = c->ideal_dst_incr / c->src_incr; | |
| 395 | + } | |
| 396 | + } | |
| 397 | + } | |
| 398 | + if (consumed) | |
| 399 | + *consumed = FFMAX(index, 0) >> c->phase_shift; | |
| 400 | + | |
| 401 | + if (update_ctx) { | |
| 402 | + if (index >= 0) | |
| 403 | + index &= c->phase_mask; | |
| 404 | + | |
| 405 | + if (compensation_distance) { | |
| 406 | + compensation_distance -= dst_index; | |
| 407 | + if (compensation_distance <= 0) | |
| 408 | + return AVERROR_BUG; | |
| 409 | + } | |
| 410 | + c->frac = frac; | |
| 411 | + c->index = index; | |
| 412 | + c->dst_incr = dst_incr_frac + c->src_incr*dst_incr; | |
| 413 | + c->compensation_distance = compensation_distance; | |
| 414 | + } | |
| 415 | + | |
| 416 | + return dst_index; | |
| 417 | +} | |
| 418 | + | |
| 419 | +int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src, | |
| 420 | + int *consumed) | |
| 421 | +{ | |
| 422 | + int ch, in_samples, in_leftover, out_samples = 0; | |
| 423 | + int ret = AVERROR(EINVAL); | |
| 424 | + | |
| 425 | + in_samples = src ? src->nb_samples : 0; | |
| 426 | + in_leftover = c->buffer->nb_samples; | |
| 427 | + | |
| 428 | + /* add input samples to the internal buffer */ | |
| 429 | + if (src) { | |
| 430 | + ret = ff_audio_data_combine(c->buffer, in_leftover, src, 0, in_samples); | |
| 431 | + if (ret < 0) | |
| 432 | + return ret; | |
| 433 | + } else if (!in_leftover) { | |
| 434 | + /* no remaining samples to flush */ | |
| 435 | + return 0; | |
| 436 | + } else { | |
| 437 | + /* TODO: pad buffer to flush completely */ | |
| 438 | + } | |
| 439 | + | |
| 440 | + /* calculate output size and reallocate output buffer if needed */ | |
| 441 | + /* TODO: try to calculate this without the dummy resample() run */ | |
| 442 | + if (!dst->read_only && dst->allow_realloc) { | |
| 443 | + out_samples = resample(c, NULL, NULL, NULL, c->buffer->nb_samples, | |
| 444 | + INT_MAX, 0); | |
| 445 | + ret = ff_audio_data_realloc(dst, out_samples); | |
| 446 | + if (ret < 0) { | |
| 447 | + av_log(c->avr, AV_LOG_ERROR, "error reallocating output\n"); | |
| 448 | + return ret; | |
| 449 | + } | |
| 450 | + } | |
| 451 | + | |
| 452 | + /* resample each channel plane */ | |
| 453 | + for (ch = 0; ch < c->buffer->channels; ch++) { | |
| 454 | + out_samples = resample(c, (int16_t *)dst->data[ch], | |
| 455 | + (const int16_t *)c->buffer->data[ch], consumed, | |
| 456 | + c->buffer->nb_samples, dst->allocated_samples, | |
| 457 | + ch + 1 == c->buffer->channels); | |
| 458 | + } | |
| 459 | + if (out_samples < 0) { | |
| 460 | + av_log(c->avr, AV_LOG_ERROR, "error during resampling\n"); | |
| 461 | + return out_samples; | |
| 462 | + } | |
| 463 | + | |
| 464 | + /* drain consumed samples from the internal buffer */ | |
| 465 | + ff_audio_data_drain(c->buffer, *consumed); | |
| 466 | + | |
| 467 | + av_dlog(c->avr, "resampled %d in + %d leftover to %d out + %d leftover\n", | |
| 468 | + in_samples, in_leftover, out_samples, c->buffer->nb_samples); | |
| 469 | + | |
| 470 | + dst->nb_samples = out_samples; | |
| 471 | + return 0; | |
| 472 | +} | |
| 473 | + | |
| 474 | +int avresample_get_delay(AVAudioResampleContext *avr) | |
| 475 | +{ | |
| 476 | + if (!avr->resample_needed || !avr->resample) | |
| 477 | + return 0; | |
| 478 | + | |
| 479 | + return avr->resample->buffer->nb_samples; | |
| 480 | +} | |
| @@ -0,0 +1,70 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#ifndef AVRESAMPLE_RESAMPLE_H | |
| 22 | +#define AVRESAMPLE_RESAMPLE_H | |
| 23 | + | |
| 24 | +#include "avresample.h" | |
| 25 | +#include "audio_data.h" | |
| 26 | + | |
| 27 | +typedef struct ResampleContext ResampleContext; | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Allocate and initialize a ResampleContext. | |
| 31 | + * | |
| 32 | + * The parameters in the AVAudioResampleContext are used to initialize the | |
| 33 | + * ResampleContext. | |
| 34 | + * | |
| 35 | + * @param avr AVAudioResampleContext | |
| 36 | + * @return newly-allocated ResampleContext | |
| 37 | + */ | |
| 38 | +ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr); | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * Free a ResampleContext. | |
| 42 | + * | |
| 43 | + * @param c ResampleContext | |
| 44 | + */ | |
| 45 | +void ff_audio_resample_free(ResampleContext **c); | |
| 46 | + | |
| 47 | +/** | |
| 48 | + * Resample audio data. | |
| 49 | + * | |
| 50 | + * Changes the sample rate. | |
| 51 | + * | |
| 52 | + * @par | |
| 53 | + * All samples in the source data may not be consumed depending on the | |
| 54 | + * resampling parameters and the size of the output buffer. The unconsumed | |
| 55 | + * samples are automatically added to the start of the source in the next call. | |
| 56 | + * If the destination data can be reallocated, that may be done in this function | |
| 57 | + * in order to fit all available output. If it cannot be reallocated, fewer | |
| 58 | + * input samples will be consumed in order to have the output fit in the | |
| 59 | + * destination data buffers. | |
| 60 | + * | |
| 61 | + * @param c ResampleContext | |
| 62 | + * @param dst destination audio data | |
| 63 | + * @param src source audio data | |
| 64 | + * @param consumed number of samples consumed from the source | |
| 65 | + * @return number of samples written to the destination | |
| 66 | + */ | |
| 67 | +int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src, | |
| 68 | + int *consumed); | |
| 69 | + | |
| 70 | +#endif /* AVRESAMPLE_RESAMPLE_H */ | |
| @@ -0,0 +1,405 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include "libavutil/dict.h" | |
| 22 | +// #include "libavutil/error.h" | |
| 23 | +#include "libavutil/log.h" | |
| 24 | +#include "libavutil/mem.h" | |
| 25 | +#include "libavutil/opt.h" | |
| 26 | + | |
| 27 | +#include "avresample.h" | |
| 28 | +#include "audio_data.h" | |
| 29 | +#include "internal.h" | |
| 30 | + | |
| 31 | +int avresample_open(AVAudioResampleContext *avr) | |
| 32 | +{ | |
| 33 | + int ret; | |
| 34 | + | |
| 35 | + /* set channel mixing parameters */ | |
| 36 | + avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | |
| 37 | + if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) { | |
| 38 | + av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n", | |
| 39 | + avr->in_channel_layout); | |
| 40 | + return AVERROR(EINVAL); | |
| 41 | + } | |
| 42 | + avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | |
| 43 | + if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) { | |
| 44 | + av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n", | |
| 45 | + avr->out_channel_layout); | |
| 46 | + return AVERROR(EINVAL); | |
| 47 | + } | |
| 48 | + avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels); | |
| 49 | + avr->downmix_needed = avr->in_channels > avr->out_channels; | |
| 50 | + avr->upmix_needed = avr->out_channels > avr->in_channels || | |
| 51 | + avr->am->matrix || | |
| 52 | + (avr->out_channels == avr->in_channels && | |
| 53 | + avr->in_channel_layout != avr->out_channel_layout); | |
| 54 | + avr->mixing_needed = avr->downmix_needed || avr->upmix_needed; | |
| 55 | + | |
| 56 | + /* set resampling parameters */ | |
| 57 | + avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate || | |
| 58 | + avr->force_resampling; | |
| 59 | + | |
| 60 | + /* set sample format conversion parameters */ | |
| 61 | + /* override user-requested internal format to avoid unexpected failures | |
| 62 | + TODO: support more internal formats */ | |
| 63 | + if (avr->resample_needed && avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P) { | |
| 64 | + av_log(avr, AV_LOG_WARNING, "Using s16p as internal sample format\n"); | |
| 65 | + avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; | |
| 66 | + } else if (avr->mixing_needed && | |
| 67 | + avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && | |
| 68 | + avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { | |
| 69 | + av_log(avr, AV_LOG_WARNING, "Using fltp as internal sample format\n"); | |
| 70 | + avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; | |
| 71 | + } | |
| 72 | + if (avr->in_channels == 1) | |
| 73 | + avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); | |
| 74 | + if (avr->out_channels == 1) | |
| 75 | + avr->out_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); | |
| 76 | + avr->in_convert_needed = (avr->resample_needed || avr->mixing_needed) && | |
| 77 | + avr->in_sample_fmt != avr->internal_sample_fmt; | |
| 78 | + if (avr->resample_needed || avr->mixing_needed) | |
| 79 | + avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt; | |
| 80 | + else | |
| 81 | + avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt; | |
| 82 | + | |
| 83 | + /* allocate buffers */ | |
| 84 | + if (avr->mixing_needed || avr->in_convert_needed) { | |
| 85 | + avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels), | |
| 86 | + 0, avr->internal_sample_fmt, | |
| 87 | + "in_buffer"); | |
| 88 | + if (!avr->in_buffer) { | |
| 89 | + ret = AVERROR(EINVAL); | |
| 90 | + goto error; | |
| 91 | + } | |
| 92 | + } | |
| 93 | + if (avr->resample_needed) { | |
| 94 | + avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels, | |
| 95 | + 0, avr->internal_sample_fmt, | |
| 96 | + "resample_out_buffer"); | |
| 97 | + if (!avr->resample_out_buffer) { | |
| 98 | + ret = AVERROR(EINVAL); | |
| 99 | + goto error; | |
| 100 | + } | |
| 101 | + } | |
| 102 | + if (avr->out_convert_needed) { | |
| 103 | + avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0, | |
| 104 | + avr->out_sample_fmt, "out_buffer"); | |
| 105 | + if (!avr->out_buffer) { | |
| 106 | + ret = AVERROR(EINVAL); | |
| 107 | + goto error; | |
| 108 | + } | |
| 109 | + } | |
| 110 | + avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels, | |
| 111 | + 1024); | |
| 112 | + if (!avr->out_fifo) { | |
| 113 | + ret = AVERROR(ENOMEM); | |
| 114 | + goto error; | |
| 115 | + } | |
| 116 | + | |
| 117 | + /* setup contexts */ | |
| 118 | + if (avr->in_convert_needed) { | |
| 119 | + avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt, | |
| 120 | + avr->in_sample_fmt, avr->in_channels); | |
| 121 | + if (!avr->ac_in) { | |
| 122 | + ret = AVERROR(ENOMEM); | |
| 123 | + goto error; | |
| 124 | + } | |
| 125 | + } | |
| 126 | + if (avr->out_convert_needed) { | |
| 127 | + enum AVSampleFormat src_fmt; | |
| 128 | + if (avr->in_convert_needed) | |
| 129 | + src_fmt = avr->internal_sample_fmt; | |
| 130 | + else | |
| 131 | + src_fmt = avr->in_sample_fmt; | |
| 132 | + avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt, | |
| 133 | + avr->out_channels); | |
| 134 | + if (!avr->ac_out) { | |
| 135 | + ret = AVERROR(ENOMEM); | |
| 136 | + goto error; | |
| 137 | + } | |
| 138 | + } | |
| 139 | + if (avr->resample_needed) { | |
| 140 | + avr->resample = ff_audio_resample_init(avr); | |
| 141 | + if (!avr->resample) { | |
| 142 | + ret = AVERROR(ENOMEM); | |
| 143 | + goto error; | |
| 144 | + } | |
| 145 | + } | |
| 146 | + if (avr->mixing_needed) { | |
| 147 | + ret = ff_audio_mix_init(avr); | |
| 148 | + if (ret < 0) | |
| 149 | + goto error; | |
| 150 | + } | |
| 151 | + | |
| 152 | + return 0; | |
| 153 | + | |
| 154 | +error: | |
| 155 | + avresample_close(avr); | |
| 156 | + return ret; | |
| 157 | +} | |
| 158 | + | |
| 159 | +void avresample_close(AVAudioResampleContext *avr) | |
| 160 | +{ | |
| 161 | + ff_audio_data_free(&avr->in_buffer); | |
| 162 | + ff_audio_data_free(&avr->resample_out_buffer); | |
| 163 | + ff_audio_data_free(&avr->out_buffer); | |
| 164 | + av_audio_fifo_free(avr->out_fifo); | |
| 165 | + avr->out_fifo = NULL; | |
| 166 | + av_freep(&avr->ac_in); | |
| 167 | + av_freep(&avr->ac_out); | |
| 168 | + ff_audio_resample_free(&avr->resample); | |
| 169 | + ff_audio_mix_close(avr->am); | |
| 170 | + return; | |
| 171 | +} | |
| 172 | + | |
| 173 | +void avresample_free(AVAudioResampleContext **avr) | |
| 174 | +{ | |
| 175 | + if (!*avr) | |
| 176 | + return; | |
| 177 | + avresample_close(*avr); | |
| 178 | + av_freep(&(*avr)->am); | |
| 179 | + av_opt_free(*avr); | |
| 180 | + av_freep(avr); | |
| 181 | +} | |
| 182 | + | |
| 183 | +static int handle_buffered_output(AVAudioResampleContext *avr, | |
| 184 | + AudioData *output, AudioData *converted) | |
| 185 | +{ | |
| 186 | + int ret; | |
| 187 | + | |
| 188 | + if (!output || av_audio_fifo_size(avr->out_fifo) > 0 || | |
| 189 | + (converted && output->allocated_samples < converted->nb_samples)) { | |
| 190 | + if (converted) { | |
| 191 | + /* if there are any samples in the output FIFO or if the | |
| 192 | + user-supplied output buffer is not large enough for all samples, | |
| 193 | + we add to the output FIFO */ | |
| 194 | + av_dlog(avr, "[FIFO] add %s to out_fifo\n", converted->name); | |
| 195 | + ret = ff_audio_data_add_to_fifo(avr->out_fifo, converted, 0, | |
| 196 | + converted->nb_samples); | |
| 197 | + if (ret < 0) | |
| 198 | + return ret; | |
| 199 | + } | |
| 200 | + | |
| 201 | + /* if the user specified an output buffer, read samples from the output | |
| 202 | + FIFO to the user output */ | |
| 203 | + if (output && output->allocated_samples > 0) { | |
| 204 | + av_dlog(avr, "[FIFO] read from out_fifo to output\n"); | |
| 205 | + av_dlog(avr, "[end conversion]\n"); | |
| 206 | + return ff_audio_data_read_from_fifo(avr->out_fifo, output, | |
| 207 | + output->allocated_samples); | |
| 208 | + } | |
| 209 | + } else if (converted) { | |
| 210 | + /* copy directly to output if it is large enough or there is not any | |
| 211 | + data in the output FIFO */ | |
| 212 | + av_dlog(avr, "[copy] %s to output\n", converted->name); | |
| 213 | + output->nb_samples = 0; | |
| 214 | + ret = ff_audio_data_copy(output, converted); | |
| 215 | + if (ret < 0) | |
| 216 | + return ret; | |
| 217 | + av_dlog(avr, "[end conversion]\n"); | |
| 218 | + return output->nb_samples; | |
| 219 | + } | |
| 220 | + av_dlog(avr, "[end conversion]\n"); | |
| 221 | + return 0; | |
| 222 | +} | |
| 223 | + | |
| 224 | +int avresample_convert(AVAudioResampleContext *avr, void **output, | |
| 225 | + int out_plane_size, int out_samples, void **input, | |
| 226 | + int in_plane_size, int in_samples) | |
| 227 | +{ | |
| 228 | + AudioData input_buffer; | |
| 229 | + AudioData output_buffer; | |
| 230 | + AudioData *current_buffer; | |
| 231 | + int ret; | |
| 232 | + | |
| 233 | + /* reset internal buffers */ | |
| 234 | + if (avr->in_buffer) { | |
| 235 | + avr->in_buffer->nb_samples = 0; | |
| 236 | + ff_audio_data_set_channels(avr->in_buffer, | |
| 237 | + avr->in_buffer->allocated_channels); | |
| 238 | + } | |
| 239 | + if (avr->resample_out_buffer) { | |
| 240 | + avr->resample_out_buffer->nb_samples = 0; | |
| 241 | + ff_audio_data_set_channels(avr->resample_out_buffer, | |
| 242 | + avr->resample_out_buffer->allocated_channels); | |
| 243 | + } | |
| 244 | + if (avr->out_buffer) { | |
| 245 | + avr->out_buffer->nb_samples = 0; | |
| 246 | + ff_audio_data_set_channels(avr->out_buffer, | |
| 247 | + avr->out_buffer->allocated_channels); | |
| 248 | + } | |
| 249 | + | |
| 250 | + av_dlog(avr, "[start conversion]\n"); | |
| 251 | + | |
| 252 | + /* initialize output_buffer with output data */ | |
| 253 | + if (output) { | |
| 254 | + ret = ff_audio_data_init(&output_buffer, output, out_plane_size, | |
| 255 | + avr->out_channels, out_samples, | |
| 256 | + avr->out_sample_fmt, 0, "output"); | |
| 257 | + if (ret < 0) | |
| 258 | + return ret; | |
| 259 | + output_buffer.nb_samples = 0; | |
| 260 | + } | |
| 261 | + | |
| 262 | + if (input) { | |
| 263 | + /* initialize input_buffer with input data */ | |
| 264 | + ret = ff_audio_data_init(&input_buffer, input, in_plane_size, | |
| 265 | + avr->in_channels, in_samples, | |
| 266 | + avr->in_sample_fmt, 1, "input"); | |
| 267 | + if (ret < 0) | |
| 268 | + return ret; | |
| 269 | + current_buffer = &input_buffer; | |
| 270 | + | |
| 271 | + if (avr->upmix_needed && !avr->in_convert_needed && !avr->resample_needed && | |
| 272 | + !avr->out_convert_needed && output && out_samples >= in_samples) { | |
| 273 | + /* in some rare cases we can copy input to output and upmix | |
| 274 | + directly in the output buffer */ | |
| 275 | + av_dlog(avr, "[copy] %s to output\n", current_buffer->name); | |
| 276 | + ret = ff_audio_data_copy(&output_buffer, current_buffer); | |
| 277 | + if (ret < 0) | |
| 278 | + return ret; | |
| 279 | + current_buffer = &output_buffer; | |
| 280 | + } else if (avr->mixing_needed || avr->in_convert_needed) { | |
| 281 | + /* if needed, copy or convert input to in_buffer, and downmix if | |
| 282 | + applicable */ | |
| 283 | + if (avr->in_convert_needed) { | |
| 284 | + ret = ff_audio_data_realloc(avr->in_buffer, | |
| 285 | + current_buffer->nb_samples); | |
| 286 | + if (ret < 0) | |
| 287 | + return ret; | |
| 288 | + av_dlog(avr, "[convert] %s to in_buffer\n", current_buffer->name); | |
| 289 | + ret = ff_audio_convert(avr->ac_in, avr->in_buffer, current_buffer, | |
| 290 | + current_buffer->nb_samples); | |
| 291 | + if (ret < 0) | |
| 292 | + return ret; | |
| 293 | + } else { | |
| 294 | + av_dlog(avr, "[copy] %s to in_buffer\n", current_buffer->name); | |
| 295 | + ret = ff_audio_data_copy(avr->in_buffer, current_buffer); | |
| 296 | + if (ret < 0) | |
| 297 | + return ret; | |
| 298 | + } | |
| 299 | + ff_audio_data_set_channels(avr->in_buffer, avr->in_channels); | |
| 300 | + if (avr->downmix_needed) { | |
| 301 | + av_dlog(avr, "[downmix] in_buffer\n"); | |
| 302 | + ret = ff_audio_mix(avr->am, avr->in_buffer); | |
| 303 | + if (ret < 0) | |
| 304 | + return ret; | |
| 305 | + } | |
| 306 | + current_buffer = avr->in_buffer; | |
| 307 | + } | |
| 308 | + } else { | |
| 309 | + /* flush resampling buffer and/or output FIFO if input is NULL */ | |
| 310 | + if (!avr->resample_needed) | |
| 311 | + return handle_buffered_output(avr, output ? &output_buffer : NULL, | |
| 312 | + NULL); | |
| 313 | + current_buffer = NULL; | |
| 314 | + } | |
| 315 | + | |
| 316 | + if (avr->resample_needed) { | |
| 317 | + AudioData *resample_out; | |
| 318 | + int consumed = 0; | |
| 319 | + | |
| 320 | + if (!avr->out_convert_needed && output && out_samples > 0) | |
| 321 | + resample_out = &output_buffer; | |
| 322 | + else | |
| 323 | + resample_out = avr->resample_out_buffer; | |
| 324 | + av_dlog(avr, "[resample] %s to %s\n", current_buffer->name, | |
| 325 | + resample_out->name); | |
| 326 | + ret = ff_audio_resample(avr->resample, resample_out, | |
| 327 | + current_buffer, &consumed); | |
| 328 | + if (ret < 0) | |
| 329 | + return ret; | |
| 330 | + | |
| 331 | + /* if resampling did not produce any samples, just return 0 */ | |
| 332 | + if (resample_out->nb_samples == 0) { | |
| 333 | + av_dlog(avr, "[end conversion]\n"); | |
| 334 | + return 0; | |
| 335 | + } | |
| 336 | + | |
| 337 | + current_buffer = resample_out; | |
| 338 | + } | |
| 339 | + | |
| 340 | + if (avr->upmix_needed) { | |
| 341 | + av_dlog(avr, "[upmix] %s\n", current_buffer->name); | |
| 342 | + ret = ff_audio_mix(avr->am, current_buffer); | |
| 343 | + if (ret < 0) | |
| 344 | + return ret; | |
| 345 | + } | |
| 346 | + | |
| 347 | + /* if we resampled or upmixed directly to output, return here */ | |
| 348 | + if (current_buffer == &output_buffer) { | |
| 349 | + av_dlog(avr, "[end conversion]\n"); | |
| 350 | + return current_buffer->nb_samples; | |
| 351 | + } | |
| 352 | + | |
| 353 | + if (avr->out_convert_needed) { | |
| 354 | + if (output && out_samples >= current_buffer->nb_samples) { | |
| 355 | + /* convert directly to output */ | |
| 356 | + av_dlog(avr, "[convert] %s to output\n", current_buffer->name); | |
| 357 | + ret = ff_audio_convert(avr->ac_out, &output_buffer, current_buffer, | |
| 358 | + current_buffer->nb_samples); | |
| 359 | + if (ret < 0) | |
| 360 | + return ret; | |
| 361 | + | |
| 362 | + av_dlog(avr, "[end conversion]\n"); | |
| 363 | + return output_buffer.nb_samples; | |
| 364 | + } else { | |
| 365 | + ret = ff_audio_data_realloc(avr->out_buffer, | |
| 366 | + current_buffer->nb_samples); | |
| 367 | + if (ret < 0) | |
| 368 | + return ret; | |
| 369 | + av_dlog(avr, "[convert] %s to out_buffer\n", current_buffer->name); | |
| 370 | + ret = ff_audio_convert(avr->ac_out, avr->out_buffer, | |
| 371 | + current_buffer, current_buffer->nb_samples); | |
| 372 | + if (ret < 0) | |
| 373 | + return ret; | |
| 374 | + current_buffer = avr->out_buffer; | |
| 375 | + } | |
| 376 | + } | |
| 377 | + | |
| 378 | + return handle_buffered_output(avr, &output_buffer, current_buffer); | |
| 379 | +} | |
| 380 | + | |
| 381 | +int avresample_available(AVAudioResampleContext *avr) | |
| 382 | +{ | |
| 383 | + return av_audio_fifo_size(avr->out_fifo); | |
| 384 | +} | |
| 385 | + | |
| 386 | +int avresample_read(AVAudioResampleContext *avr, void **output, int nb_samples) | |
| 387 | +{ | |
| 388 | + return av_audio_fifo_read(avr->out_fifo, output, nb_samples); | |
| 389 | +} | |
| 390 | + | |
| 391 | +unsigned avresample_version(void) | |
| 392 | +{ | |
| 393 | + return LIBAVRESAMPLE_VERSION_INT; | |
| 394 | +} | |
| 395 | + | |
| 396 | +const char *avresample_license(void) | |
| 397 | +{ | |
| 398 | +#define LICENSE_PREFIX "libavresample license: " | |
| 399 | + return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; | |
| 400 | +} | |
| 401 | + | |
| 402 | +const char *avresample_configuration(void) | |
| 403 | +{ | |
| 404 | + return FFMPEG_CONFIGURATION; | |
| 405 | +} | |
| @@ -0,0 +1,41 @@ | ||
| 1 | +/* | |
| 2 | + * This file is part of Libav. | |
| 3 | + * | |
| 4 | + * Libav is free software; you can redistribute it and/or | |
| 5 | + * modify it under the terms of the GNU Lesser General Public | |
| 6 | + * License as published by the Free Software Foundation; either | |
| 7 | + * version 2.1 of the License, or (at your option) any later version. | |
| 8 | + * | |
| 9 | + * Libav is distributed in the hope that it will be useful, | |
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 12 | + * Lesser General Public License for more details. | |
| 13 | + * | |
| 14 | + * You should have received a copy of the GNU Lesser General Public | |
| 15 | + * License along with Libav; if not, write to the Free Software | |
| 16 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 17 | + */ | |
| 18 | + | |
| 19 | +#ifndef AVRESAMPLE_VERSION_H | |
| 20 | +#define AVRESAMPLE_VERSION_H | |
| 21 | + | |
| 22 | +#define LIBAVRESAMPLE_VERSION_MAJOR 0 | |
| 23 | +#define LIBAVRESAMPLE_VERSION_MINOR 0 | |
| 24 | +#define LIBAVRESAMPLE_VERSION_MICRO 0 | |
| 25 | + | |
| 26 | +#define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \ | |
| 27 | + LIBAVRESAMPLE_VERSION_MINOR, \ | |
| 28 | + LIBAVRESAMPLE_VERSION_MICRO) | |
| 29 | +#define LIBAVRESAMPLE_VERSION AV_VERSION(LIBAVRESAMPLE_VERSION_MAJOR, \ | |
| 30 | + LIBAVRESAMPLE_VERSION_MINOR, \ | |
| 31 | + LIBAVRESAMPLE_VERSION_MICRO) | |
| 32 | +#define LIBAVRESAMPLE_BUILD LIBAVRESAMPLE_VERSION_INT | |
| 33 | + | |
| 34 | +#define LIBAVRESAMPLE_IDENT "Lavr" AV_STRINGIFY(LIBAVRESAMPLE_VERSION) | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * These FF_API_* defines are not part of public API. | |
| 38 | + * They may change, break or disappear at any time. | |
| 39 | + */ | |
| 40 | + | |
| 41 | +#endif /* AVRESAMPLE_VERSION_H */ | |
| @@ -0,0 +1,5 @@ | ||
| 1 | +OBJS += x86/audio_convert_init.o \ | |
| 2 | + x86/audio_mix_init.o | |
| 3 | + | |
| 4 | +YASM-OBJS += x86/audio_convert.o \ | |
| 5 | + x86/audio_mix.o | |
| @@ -0,0 +1,104 @@ | ||
| 1 | +;****************************************************************************** | |
| 2 | +;* x86 optimized Format Conversion Utils | |
| 3 | +;* Copyright (c) 2008 Loren Merritt | |
| 4 | +;* | |
| 5 | +;* This file is part of Libav. | |
| 6 | +;* | |
| 7 | +;* Libav is free software; you can redistribute it and/or | |
| 8 | +;* modify it under the terms of the GNU Lesser General Public | |
| 9 | +;* License as published by the Free Software Foundation; either | |
| 10 | +;* version 2.1 of the License, or (at your option) any later version. | |
| 11 | +;* | |
| 12 | +;* Libav is distributed in the hope that it will be useful, | |
| 13 | +;* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 | +;* Lesser General Public License for more details. | |
| 16 | +;* | |
| 17 | +;* You should have received a copy of the GNU Lesser General Public | |
| 18 | +;* License along with Libav; if not, write to the Free Software | |
| 19 | +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 | +;****************************************************************************** | |
| 21 | + | |
| 22 | +%include "x86inc.asm" | |
| 23 | +%include "x86util.asm" | |
| 24 | + | |
| 25 | +SECTION_TEXT | |
| 26 | + | |
| 27 | +;----------------------------------------------------------------------------- | |
| 28 | +; void ff_conv_fltp_to_flt_6ch(float *dst, float *const *src, int len, | |
| 29 | +; int channels); | |
| 30 | +;----------------------------------------------------------------------------- | |
| 31 | + | |
| 32 | +%macro CONV_FLTP_TO_FLT_6CH 0 | |
| 33 | +cglobal conv_fltp_to_flt_6ch, 2,8,7, dst, src, src1, src2, src3, src4, src5, len | |
| 34 | +%if ARCH_X86_64 | |
| 35 | + mov lend, r2d | |
| 36 | +%else | |
| 37 | + %define lend dword r2m | |
| 38 | +%endif | |
| 39 | + mov src1q, [srcq+1*gprsize] | |
| 40 | + mov src2q, [srcq+2*gprsize] | |
| 41 | + mov src3q, [srcq+3*gprsize] | |
| 42 | + mov src4q, [srcq+4*gprsize] | |
| 43 | + mov src5q, [srcq+5*gprsize] | |
| 44 | + mov srcq, [srcq] | |
| 45 | + sub src1q, srcq | |
| 46 | + sub src2q, srcq | |
| 47 | + sub src3q, srcq | |
| 48 | + sub src4q, srcq | |
| 49 | + sub src5q, srcq | |
| 50 | +.loop: | |
| 51 | + mova m0, [srcq ] | |
| 52 | + mova m1, [srcq+src1q] | |
| 53 | + mova m2, [srcq+src2q] | |
| 54 | + mova m3, [srcq+src3q] | |
| 55 | + mova m4, [srcq+src4q] | |
| 56 | + mova m5, [srcq+src5q] | |
| 57 | +%if cpuflag(sse) | |
| 58 | + SBUTTERFLYPS 0, 1, 6 | |
| 59 | + SBUTTERFLYPS 2, 3, 6 | |
| 60 | + SBUTTERFLYPS 4, 5, 6 | |
| 61 | + | |
| 62 | + movaps m6, m4 | |
| 63 | + shufps m4, m0, q3210 | |
| 64 | + movlhps m0, m2 | |
| 65 | + movhlps m6, m2 | |
| 66 | + movaps [dstq ], m0 | |
| 67 | + movaps [dstq+16], m4 | |
| 68 | + movaps [dstq+32], m6 | |
| 69 | + | |
| 70 | + movaps m6, m5 | |
| 71 | + shufps m5, m1, q3210 | |
| 72 | + movlhps m1, m3 | |
| 73 | + movhlps m6, m3 | |
| 74 | + movaps [dstq+48], m1 | |
| 75 | + movaps [dstq+64], m5 | |
| 76 | + movaps [dstq+80], m6 | |
| 77 | +%else ; mmx | |
| 78 | + SBUTTERFLY dq, 0, 1, 6 | |
| 79 | + SBUTTERFLY dq, 2, 3, 6 | |
| 80 | + SBUTTERFLY dq, 4, 5, 6 | |
| 81 | + | |
| 82 | + movq [dstq ], m0 | |
| 83 | + movq [dstq+ 8], m2 | |
| 84 | + movq [dstq+16], m4 | |
| 85 | + movq [dstq+24], m1 | |
| 86 | + movq [dstq+32], m3 | |
| 87 | + movq [dstq+40], m5 | |
| 88 | +%endif | |
| 89 | + add srcq, mmsize | |
| 90 | + add dstq, mmsize*6 | |
| 91 | + sub lend, mmsize/4 | |
| 92 | + jg .loop | |
| 93 | +%if mmsize == 8 | |
| 94 | + emms | |
| 95 | + RET | |
| 96 | +%else | |
| 97 | + REP_RET | |
| 98 | +%endif | |
| 99 | +%endmacro | |
| 100 | + | |
| 101 | +INIT_MMX mmx | |
| 102 | +CONV_FLTP_TO_FLT_6CH | |
| 103 | +INIT_XMM sse | |
| 104 | +CONV_FLTP_TO_FLT_6CH | |
| @@ -0,0 +1,42 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include "config.h" | |
| 22 | +#include "libavutil/cpu.h" | |
| 23 | +#include "libavresample/audio_convert.h" | |
| 24 | + | |
| 25 | +extern void ff_conv_fltp_to_flt_6ch_mmx(float *dst, float *const *src, int len); | |
| 26 | +extern void ff_conv_fltp_to_flt_6ch_sse(float *dst, float *const *src, int len); | |
| 27 | + | |
| 28 | +av_cold void ff_audio_convert_init_x86(AudioConvert *ac) | |
| 29 | +{ | |
| 30 | +#if HAVE_YASM | |
| 31 | + int mm_flags = av_get_cpu_flags(); | |
| 32 | + | |
| 33 | + if (mm_flags & AV_CPU_FLAG_MMX && HAVE_MMX) { | |
| 34 | + ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | |
| 35 | + 6, 1, 4, "MMX", ff_conv_fltp_to_flt_6ch_mmx); | |
| 36 | + } | |
| 37 | + if (mm_flags & AV_CPU_FLAG_SSE && HAVE_SSE) { | |
| 38 | + ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | |
| 39 | + 6, 16, 4, "SSE", ff_conv_fltp_to_flt_6ch_sse); | |
| 40 | + } | |
| 41 | +#endif | |
| 42 | +} | |
| @@ -0,0 +1,64 @@ | ||
| 1 | +;****************************************************************************** | |
| 2 | +;* x86 optimized channel mixing | |
| 3 | +;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 4 | +;* | |
| 5 | +;* This file is part of Libav. | |
| 6 | +;* | |
| 7 | +;* Libav is free software; you can redistribute it and/or | |
| 8 | +;* modify it under the terms of the GNU Lesser General Public | |
| 9 | +;* License as published by the Free Software Foundation; either | |
| 10 | +;* version 2.1 of the License, or (at your option) any later version. | |
| 11 | +;* | |
| 12 | +;* Libav is distributed in the hope that it will be useful, | |
| 13 | +;* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 | +;* Lesser General Public License for more details. | |
| 16 | +;* | |
| 17 | +;* You should have received a copy of the GNU Lesser General Public | |
| 18 | +;* License along with Libav; if not, write to the Free Software | |
| 19 | +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 | +;****************************************************************************** | |
| 21 | + | |
| 22 | +%include "x86inc.asm" | |
| 23 | +%include "x86util.asm" | |
| 24 | + | |
| 25 | +SECTION_TEXT | |
| 26 | + | |
| 27 | +;----------------------------------------------------------------------------- | |
| 28 | +; void ff_mix_2_to_1_fltp_flt(float **src, float **matrix, int len, | |
| 29 | +; int out_ch, int in_ch); | |
| 30 | +;----------------------------------------------------------------------------- | |
| 31 | + | |
| 32 | +%macro MIX_2_TO_1_FLTP_FLT 0 | |
| 33 | +cglobal mix_2_to_1_fltp_flt, 3,4,6, src, matrix, len, src1 | |
| 34 | + mov src1q, [srcq+gprsize] | |
| 35 | + mov srcq, [srcq ] | |
| 36 | + sub src1q, srcq | |
| 37 | + mov matrixq, [matrixq ] | |
| 38 | + VBROADCASTSS m4, [matrixq ] | |
| 39 | + VBROADCASTSS m5, [matrixq+4] | |
| 40 | + ALIGN 16 | |
| 41 | +.loop: | |
| 42 | + mulps m0, m4, [srcq ] | |
| 43 | + mulps m1, m5, [srcq+src1q ] | |
| 44 | + mulps m2, m4, [srcq+ mmsize] | |
| 45 | + mulps m3, m5, [srcq+src1q+mmsize] | |
| 46 | + addps m0, m0, m1 | |
| 47 | + addps m2, m2, m3 | |
| 48 | + mova [srcq ], m0 | |
| 49 | + mova [srcq+mmsize], m2 | |
| 50 | + add srcq, mmsize*2 | |
| 51 | + sub lend, mmsize*2/4 | |
| 52 | + jg .loop | |
| 53 | +%if mmsize == 32 | |
| 54 | + vzeroupper | |
| 55 | + RET | |
| 56 | +%else | |
| 57 | + REP_RET | |
| 58 | +%endif | |
| 59 | +%endmacro | |
| 60 | + | |
| 61 | +INIT_XMM sse | |
| 62 | +MIX_2_TO_1_FLTP_FLT | |
| 63 | +INIT_YMM avx | |
| 64 | +MIX_2_TO_1_FLTP_FLT | |
| @@ -0,0 +1,44 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | |
| 3 | + * | |
| 4 | + * This file is part of Libav. | |
| 5 | + * | |
| 6 | + * Libav is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU Lesser General Public | |
| 8 | + * License as published by the Free Software Foundation; either | |
| 9 | + * version 2.1 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + * Libav is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | + * Lesser General Public License for more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU Lesser General Public | |
| 17 | + * License along with Libav; if not, write to the Free Software | |
| 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include "config.h" | |
| 22 | +#include "libavutil/cpu.h" | |
| 23 | +#include "libavresample/audio_mix.h" | |
| 24 | + | |
| 25 | +extern void ff_mix_2_to_1_fltp_flt_sse(float **src, float **matrix, int len, | |
| 26 | + int out_ch, int in_ch); | |
| 27 | +extern void ff_mix_2_to_1_fltp_flt_avx(float **src, float **matrix, int len, | |
| 28 | + int out_ch, int in_ch); | |
| 29 | + | |
| 30 | +av_cold void ff_audio_mix_init_x86(AudioMix *am) | |
| 31 | +{ | |
| 32 | +#if HAVE_YASM | |
| 33 | + int mm_flags = av_get_cpu_flags(); | |
| 34 | + | |
| 35 | + if (mm_flags & AV_CPU_FLAG_SSE && HAVE_SSE) { | |
| 36 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
| 37 | + 2, 1, 16, 8, "SSE", ff_mix_2_to_1_fltp_flt_sse); | |
| 38 | + } | |
| 39 | + if (mm_flags & AV_CPU_FLAG_AVX && HAVE_AVX) { | |
| 40 | + ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | |
| 41 | + 2, 1, 32, 16, "AVX", ff_mix_2_to_1_fltp_flt_avx); | |
| 42 | + } | |
| 43 | +#endif | |
| 44 | +} | |
| @@ -585,3 +585,12 @@ · 584 unmodified lines | ||
| 585 | 585 | pminsd %1, %3 |
| 586 | 586 | pmaxsd %1, %2 |
| 587 | 587 | %endmacro |
| 588 | + | |
| 589 | +%macro VBROADCASTSS 2 ; dst xmm/ymm, src m32 | |
| 590 | +%if cpuflag(avx) | |
| 591 | + vbroadcastss %1, %2 | |
| 592 | +%else ; sse | |
| 593 | + movss %1, %2 | |
| 594 | + shufps %1, %1, 0 | |
| 595 | +%endif | |
| 596 | +%endmacro | |
| @@ -55,8 +55,8 @@ fate-aac-ap05_48: CMD = pcm -i $(SAMPLES)/aac/ap05_48.mp4 · 54 unmodified lines | ||
| 55 | 55 | fate-aac-ap05_48: REF = $(SAMPLES)/aac/ap05_48.s16 |
| 56 | 56 | |
| 57 | 57 | FATE_AAC += fate-aac-latm_stereo_to_51 |
| 58 | −fate-aac-latm_stereo_to_51: CMD = pcm -i $(SAMPLES)/aac/latm_stereo_to_51.ts -ac 6 | |
| 59 | −fate-aac-latm_stereo_to_51: REF = $(SAMPLES)/aac/latm_stereo_to_51.s16 | |
| 58 | +fate-aac-latm_stereo_to_51: CMD = pcm -i $(SAMPLES)/aac/latm_stereo_to_51.ts -channel_layout 5.1 | |
| 59 | +fate-aac-latm_stereo_to_51: REF = $(SAMPLES)/aac/latm_stereo_to_51_ref.s16 | |
| 60 | 60 | |
| 61 | 61 | fate-aac-ct%: CMD = pcm -i $(SAMPLES)/aac/CT_DecoderCheck/$(@:fate-aac-ct-%=%) |
| 62 | 62 | fate-aac-ct%: REF = $(SAMPLES)/aac/CT_DecoderCheck/aacPlusv2.wav |
| @@ -118,7 +118,7 @@ fi · 117 unmodified lines | ||
| 118 | 118 | if [ -n "$do_dv_fmt" ] ; then |
| 119 | 119 | do_lavf_timecode_nodrop dv "-ar 48000 -r 25 -s pal -ac 2" |
| 120 | 120 | do_lavf_timecode_drop dv "-ar 48000 -pix_fmt yuv411p -s ntsc -ac 2" |
| 121 | −do_lavf dv "-ar 48000" "-r 25 -s pal -ac 2" | |
| 121 | +do_lavf dv "-ar 48000 -channel_layout stereo" "-r 25 -s pal" | |
| 122 | 122 | fi |
| 123 | 123 | |
| 124 | 124 | if [ -n "$do_gxf" ] ; then |
| @@ -4,6 +4,6 @@ · 3 unmodified lines | ||
| 4 | 4 | cc33ae4f9e6828914dea0f09d1241b7e *./tests/data/lavf/lavf.dv |
| 5 | 5 | 3480000 ./tests/data/lavf/lavf.dv |
| 6 | 6 | ./tests/data/lavf/lavf.dv CRC=0x8d5e9e8f |
| 7 | −b36c83cd0ba0ebe719f09f885c4bbcd3 *./tests/data/lavf/lavf.dv | |
| 7 | +87d3b20f656235671383a7eaa2f66330 *./tests/data/lavf/lavf.dv | |
| 8 | 8 | 3600000 ./tests/data/lavf/lavf.dv |
| 9 | −./tests/data/lavf/lavf.dv CRC=0x2bc2ae3a | |
| 9 | +./tests/data/lavf/lavf.dv CRC=0x0e868a82 | |