* 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 | - drawtext video filter: fontconfig support | 26 | - drawtext video filter: fontconfig support |
| 27 | - ffmpeg -benchmark_all option | 27 | - ffmpeg -benchmark_all option |
| 28 | - super2xsai filter ported from libmpcodecs | 28 | - super2xsai filter ported from libmpcodecs |
| 29 | - add libavresample audio conversion library for compatibility | ||
| 29 | 30 | ||
| 30 | 31 | ||
| 31 | version 0.10: | 32 | version 0.10: |
| @@ -31,6 +31,7 @@ ALLMANPAGES = $(BASENAMES:%=%.1) · 30 unmodified lines | |||
| 31 | FFLIBS-$(CONFIG_AVDEVICE) += avdevice | 31 | FFLIBS-$(CONFIG_AVDEVICE) += avdevice |
| 32 | FFLIBS-$(CONFIG_AVFILTER) += avfilter | 32 | FFLIBS-$(CONFIG_AVFILTER) += avfilter |
| 33 | FFLIBS-$(CONFIG_AVFORMAT) += avformat | 33 | FFLIBS-$(CONFIG_AVFORMAT) += avformat |
| 34 | FFLIBS-$(CONFIG_AVRESAMPLE) += avresample | ||
| 34 | FFLIBS-$(CONFIG_AVCODEC) += avcodec | 35 | FFLIBS-$(CONFIG_AVCODEC) += avcodec |
| 35 | FFLIBS-$(CONFIG_POSTPROC) += postproc | 36 | FFLIBS-$(CONFIG_POSTPROC) += postproc |
| 36 | FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample | 37 | FFLIBS-$(CONFIG_SWRESAMPLE)+= swresample |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | |||
| 32 | #include "libavformat/avformat.h" | 32 | #include "libavformat/avformat.h" |
| 33 | #include "libavfilter/avfilter.h" | 33 | #include "libavfilter/avfilter.h" |
| 34 | #include "libavdevice/avdevice.h" | 34 | #include "libavdevice/avdevice.h" |
| 35 | #include "libavresample/avresample.h" | ||
| 35 | #include "libswscale/swscale.h" | 36 | #include "libswscale/swscale.h" |
| 36 | #include "libswresample/swresample.h" | 37 | #include "libswresample/swresample.h" |
| 37 | #if CONFIG_POSTPROC | 38 | #if CONFIG_POSTPROC |
| @@ -633,7 +634,8 @@ static int warned_cfg = 0; · 595 unmodified lines | |||
| 633 | const char *indent = flags & INDENT? " " : ""; \ | 634 | const char *indent = flags & INDENT? " " : ""; \ |
| 634 | if (flags & SHOW_VERSION) { \ | 635 | if (flags & SHOW_VERSION) { \ |
| 635 | unsigned int version = libname##_version(); \ | 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 | indent, #libname, \ | 639 | indent, #libname, \ |
| 638 | LIB##LIBNAME##_VERSION_MAJOR, \ | 640 | LIB##LIBNAME##_VERSION_MAJOR, \ |
| 639 | LIB##LIBNAME##_VERSION_MINOR, \ | 641 | LIB##LIBNAME##_VERSION_MINOR, \ |
| @@ -662,6 +664,7 @@ static void print_all_libs_info(int flags, int level) · 22 unmodified lines | |||
| 662 | PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); | 664 | PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); |
| 663 | PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); | 665 | PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); |
| 664 | PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); | 666 | PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); |
| 667 | // PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level); | ||
| 665 | PRINT_LIB_INFO(swscale, SWSCALE, flags, level); | 668 | PRINT_LIB_INFO(swscale, SWSCALE, flags, level); |
| 666 | PRINT_LIB_INFO(swresample,SWRESAMPLE, flags, level); | 669 | PRINT_LIB_INFO(swresample,SWRESAMPLE, flags, level); |
| 667 | #if CONFIG_POSTPROC | 670 | #if CONFIG_POSTPROC |
| @@ -20,7 +20,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR)))) · 19 unmodified lines | |||
| 20 | $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) | 20 | $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) |
| 21 | endif | 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 | # NASM requires -I path terminated with / | 25 | # NASM requires -I path terminated with / |
| 26 | IFLAGS := -I. -I$(SRC_PATH)/ | 26 | IFLAGS := -I. -I$(SRC_PATH)/ |
| @@ -112,6 +112,7 @@ Component options: · 111 unmodified lines | |||
| 112 | --disable-swscale disable libswscale build | 112 | --disable-swscale disable libswscale build |
| 113 | --disable-postproc disable libpostproc build | 113 | --disable-postproc disable libpostproc build |
| 114 | --disable-avfilter disable video filter support [no] | 114 | --disable-avfilter disable video filter support [no] |
| 115 | --disable-avresample disable libavresample build [no] | ||
| 115 | --disable-pthreads disable pthreads [auto] | 116 | --disable-pthreads disable pthreads [auto] |
| 116 | --disable-w32threads disable Win32 threads [auto] | 117 | --disable-w32threads disable Win32 threads [auto] |
| 117 | --disable-os2threads disable OS/2 threads [auto] | 118 | --disable-os2threads disable OS/2 threads [auto] |
| @@ -1013,6 +1014,7 @@ CONFIG_LIST=" · 895 unmodified lines | |||
| 1013 | avdevice | 1014 | avdevice |
| 1014 | avfilter | 1015 | avfilter |
| 1015 | avformat | 1016 | avformat |
| 1017 | avresample | ||
| 1016 | avisynth | 1018 | avisynth |
| 1017 | bzlib | 1019 | bzlib |
| 1018 | crystalhd | 1020 | crystalhd |
| @@ -1870,6 +1872,7 @@ enable avcodec · 851 unmodified lines | |||
| 1870 | enable avdevice | 1872 | enable avdevice |
| 1871 | enable avfilter | 1873 | enable avfilter |
| 1872 | enable avformat | 1874 | enable avformat |
| 1875 | enable avresample | ||
| 1873 | enable avutil | 1876 | enable avutil |
| 1874 | enable postproc | 1877 | enable postproc |
| 1875 | enable stripping | 1878 | enable stripping |
| @@ -3724,6 +3727,7 @@ get_version LIBAVCODEC libavcodec/version.h · 1848 unmodified lines | |||
| 3724 | get_version LIBAVDEVICE libavdevice/avdevice.h | 3727 | get_version LIBAVDEVICE libavdevice/avdevice.h |
| 3725 | get_version LIBAVFILTER libavfilter/version.h | 3728 | get_version LIBAVFILTER libavfilter/version.h |
| 3726 | get_version LIBAVFORMAT libavformat/version.h | 3729 | get_version LIBAVFORMAT libavformat/version.h |
| 3730 | get_version LIBAVRESAMPLE libavresample/version.h | ||
| 3727 | get_version LIBAVUTIL libavutil/avutil.h | 3731 | get_version LIBAVUTIL libavutil/avutil.h |
| 3728 | get_version LIBPOSTPROC libpostproc/postprocess.h | 3732 | get_version LIBPOSTPROC libpostproc/postprocess.h |
| 3729 | get_version LIBSWRESAMPLE libswresample/swresample.h | 3733 | get_version LIBSWRESAMPLE libswresample/swresample.h |
| @@ -3869,5 +3873,6 @@ pkgconfig_generate libavformat "FFmpeg container format library" "$LIBAVFORMAT_V · 139 unmodified lines | |||
| 3869 | pkgconfig_generate libavdevice "FFmpeg device handling library" "$LIBAVDEVICE_VERSION" "$extralibs" "$libavdevice_pc_deps" | 3873 | pkgconfig_generate libavdevice "FFmpeg device handling library" "$LIBAVDEVICE_VERSION" "$extralibs" "$libavdevice_pc_deps" |
| 3870 | pkgconfig_generate libavfilter "FFmpeg video filtering library" "$LIBAVFILTER_VERSION" "$extralibs" "$libavfilter_pc_deps" | 3874 | pkgconfig_generate libavfilter "FFmpeg video filtering library" "$LIBAVFILTER_VERSION" "$extralibs" "$libavfilter_pc_deps" |
| 3871 | pkgconfig_generate libpostproc "FFmpeg postprocessing library" "$LIBPOSTPROC_VERSION" "" "libavutil = $LIBAVUTIL_VERSION" | 3875 | pkgconfig_generate libpostproc "FFmpeg postprocessing library" "$LIBPOSTPROC_VERSION" "" "libavutil = $LIBAVUTIL_VERSION" |
| 3876 | pkgconfig_generate libavresample "Libav audio resampling library" "$LIBAVRESAMPLE_VERSION" "$extralibs" | ||
| 3872 | pkgconfig_generate libswscale "FFmpeg image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" | 3877 | pkgconfig_generate libswscale "FFmpeg image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" |
| 3873 | pkgconfig_generate libswresample "FFmpeg audio rescaling library" "$LIBSWRESAMPLE_VERSION" "$LIBM" "libavutil = $LIBAVUTIL_VERSION" | 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 | libavdevice: 2011-04-18 | 6 | libavdevice: 2011-04-18 |
| 7 | libavfilter: 2011-04-18 | 7 | libavfilter: 2011-04-18 |
| 8 | libavformat: 2012-01-27 | 8 | libavformat: 2012-01-27 |
| 9 | libavresample: 2012-xx-xx | ||
| 9 | libpostproc: 2011-04-18 | 10 | libpostproc: 2011-04-18 |
| 10 | libswscale: 2011-06-20 | 11 | libswscale: 2011-06-20 |
| 11 | libavutil: 2011-04-18 | 12 | libavutil: 2011-04-18 |
| @@ -22,6 +23,9 @@ API changes, most recent first: · 10 unmodified lines | |||
| 22 | 2012-03-26 - a67d9cf - lavfi 2.66.100 | 23 | 2012-03-26 - a67d9cf - lavfi 2.66.100 |
| 23 | Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions. | 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 | 2012-xx-xx - xxxxxxx - lavu 51.28.0 - audio_fifo.h | 29 | 2012-xx-xx - xxxxxxx - lavu 51.28.0 - audio_fifo.h |
| 26 | Add audio FIFO functions: | 30 | Add audio FIFO functions: |
| 27 | av_audio_fifo_free() | 31 | av_audio_fifo_free() |
| @@ -36,7 +36,6 @@ · 35 unmodified lines | |||
| 36 | #include "libavdevice/avdevice.h" | 36 | #include "libavdevice/avdevice.h" |
| 37 | #include "libswscale/swscale.h" | 37 | #include "libswscale/swscale.h" |
| 38 | #include "libavutil/opt.h" | 38 | #include "libavutil/opt.h" |
| 39 | #include "libavcodec/audioconvert.h" | ||
| 40 | #include "libavutil/audioconvert.h" | 39 | #include "libavutil/audioconvert.h" |
| 41 | #include "libavutil/parseutils.h" | 40 | #include "libavutil/parseutils.h" |
| 42 | #include "libavutil/samplefmt.h" | 41 | #include "libavutil/samplefmt.h" |
| @@ -300,6 +299,7 @@ typedef struct OutputStream { · 257 unmodified lines | |||
| 300 | int audio_channels_mapped; ///< number of channels in audio_channels_map | 299 | int audio_channels_mapped; ///< number of channels in audio_channels_map |
| 301 | int resample_sample_fmt; | 300 | int resample_sample_fmt; |
| 302 | int resample_channels; | 301 | int resample_channels; |
| 302 | uint64_t resample_channel_layout; | ||
| 303 | int resample_sample_rate; | 303 | int resample_sample_rate; |
| 304 | float rematrix_volume; | 304 | float rematrix_volume; |
| 305 | AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ | 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 | static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, | 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 | int64_t audio_buf_samples; | 1530 | int64_t audio_buf_samples; |
| 1531 | int audio_buf_size; | 1531 | int audio_buf_size; |
| @@ -1538,7 +1538,7 @@ static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, · 6 unmodified lines | |||
| 1538 | if (audio_buf_samples > INT_MAX) | 1538 | if (audio_buf_samples > INT_MAX) |
| 1539 | return AVERROR(EINVAL); | 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 | audio_buf_samples, | 1542 | audio_buf_samples, |
| 1543 | enc->sample_fmt, 0); | 1543 | enc->sample_fmt, 0); |
| 1544 | if (audio_buf_size < 0) | 1544 | if (audio_buf_size < 0) |
| @@ -1557,7 +1557,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 12 unmodified lines | |||
| 1557 | uint8_t *buftmp; | 1557 | uint8_t *buftmp; |
| 1558 | int64_t size_out; | 1558 | int64_t size_out; |
| 1559 | 1559 | ||
| 1560 | int frame_bytes, resample_changed; | 1560 | int frame_bytes, resample_changed, ret; |
| 1561 | AVCodecContext *enc = ost->st->codec; | 1561 | AVCodecContext *enc = ost->st->codec; |
| 1562 | AVCodecContext *dec = ist->st->codec; | 1562 | AVCodecContext *dec = ist->st->codec; |
| 1563 | int osize = av_get_bytes_per_sample(enc->sample_fmt); | 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 | int size = decoded_frame->nb_samples * dec->channels * isize; | 1566 | int size = decoded_frame->nb_samples * dec->channels * isize; |
| 1567 | int planes = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1; | 1567 | int planes = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1; |
| 1568 | int i; | 1568 | int i; |
| 1569 | int out_linesize = 0; | ||
| 1570 | int buf_linesize = decoded_frame->linesize[0]; | ||
| 1569 | 1571 | ||
| 1570 | av_assert0(planes <= AV_NUM_DATA_POINTERS); | 1572 | av_assert0(planes <= AV_NUM_DATA_POINTERS); |
| 1571 | 1573 | ||
| 1572 | for(i=0; i<planes; i++) | 1574 | for(i=0; i<planes; i++) |
| 1573 | buf[i]= decoded_frame->data[i]; | 1575 | buf[i]= decoded_frame->data[i]; |
| 1574 | 1576 | ||
| 1577 | |||
| 1575 | get_default_channel_layouts(ost, ist); | 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 | av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); | 1581 | av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); |
| 1579 | exit_program(1); | 1582 | exit_program(1); |
| 1580 | } | 1583 | } |
| 1581 | 1584 | ||
| 1582 | if (enc->channels != dec->channels | 1585 | if (audio_sync_method > 1 || |
| 1583 | || enc->sample_fmt != dec->sample_fmt | 1586 | enc->channels != dec->channels || |
| 1584 | || enc->sample_rate!= dec->sample_rate | 1587 | enc->channel_layout != dec->channel_layout || |
| 1585 | ) | 1588 | enc->sample_rate != dec->sample_rate || |
| 1589 | dec->sample_fmt != enc->sample_fmt) | ||
| 1586 | ost->audio_resample = 1; | 1590 | ost->audio_resample = 1; |
| 1587 | 1591 | ||
| 1588 | resample_changed = ost->resample_sample_fmt != dec->sample_fmt || | 1592 | resample_changed = ost->resample_sample_fmt != dec->sample_fmt || |
| 1589 | ost->resample_channels != dec->channels || | 1593 | ost->resample_channels != dec->channels || |
| 1594 | ost->resample_channel_layout != dec->channel_layout || | ||
| 1590 | ost->resample_sample_rate != dec->sample_rate; | 1595 | ost->resample_sample_rate != dec->sample_rate; |
| 1591 | 1596 | ||
| 1592 | if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) { | 1597 | if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) { |
| 1598 | |||
| 1593 | if (resample_changed) { | 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 | ist->file_index, ist->st->index, | 1601 | ist->file_index, ist->st->index, |
| 1596 | ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), ost->resample_channels, | 1602 | ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), |
| 1597 | dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels); | 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 | ost->resample_sample_fmt = dec->sample_fmt; | 1606 | ost->resample_sample_fmt = dec->sample_fmt; |
| 1599 | ost->resample_channels = dec->channels; | 1607 | ost->resample_channels = dec->channels; |
| 1608 | ost->resample_channel_layout = dec->channel_layout; | ||
| 1600 | ost->resample_sample_rate = dec->sample_rate; | 1609 | ost->resample_sample_rate = dec->sample_rate; |
| 1601 | swr_free(&ost->swr); | 1610 | swr_free(&ost->swr); |
| 1602 | } | 1611 | } |
| @@ -1604,6 +1613,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 1 unmodified line | |||
| 1604 | if (audio_sync_method <= 1 && !ost->audio_channels_mapped && | 1613 | if (audio_sync_method <= 1 && !ost->audio_channels_mapped && |
| 1605 | ost->resample_sample_fmt == enc->sample_fmt && | 1614 | ost->resample_sample_fmt == enc->sample_fmt && |
| 1606 | ost->resample_channels == enc->channels && | 1615 | ost->resample_channels == enc->channels && |
| 1616 | ost->resample_channel_layout == enc->channel_layout && | ||
| 1607 | ost->resample_sample_rate == enc->sample_rate) { | 1617 | ost->resample_sample_rate == enc->sample_rate) { |
| 1608 | //ost->swr = NULL; | 1618 | //ost->swr = NULL; |
| 1609 | ost->audio_resample = 0; | 1619 | ost->audio_resample = 0; |
| @@ -1673,7 +1683,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 63 unmodified lines | |||
| 1673 | exit_program(1); | 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 | av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); | 1687 | av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); |
| 1678 | exit_program(1); | 1688 | exit_program(1); |
| 1679 | } | 1689 | } |
| @@ -1686,11 +1696,11 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost, · 6 unmodified lines | |||
| 1686 | buf[i] = t; | 1696 | buf[i] = t; |
| 1687 | } | 1697 | } |
| 1688 | size += byte_delta; | 1698 | size += byte_delta; |
| 1699 | buf_linesize = allocated_async_buf_size; | ||
| 1689 | av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); | 1700 | av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); |
| 1690 | } | 1701 | } |
| 1691 | } else if (audio_sync_method > 1) { | 1702 | } else if (audio_sync_method > 1) { |
| 1692 | int comp = av_clip(delta, -audio_sync_method, audio_sync_method); | 1703 | int comp = av_clip(delta, -audio_sync_method, audio_sync_method); |
| 1693 | av_assert0(ost->audio_resample); | ||
| 1694 | av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", | 1704 | av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", |
| 1695 | delta, comp, enc->sample_rate); | 1705 | delta, comp, enc->sample_rate); |
| 1696 | // 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)); | 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 | if (ost->audio_resample || ost->audio_channels_mapped) { | 1714 | if (ost->audio_resample || ost->audio_channels_mapped) { |
| 1705 | buftmp = audio_buf; | 1715 | buftmp = audio_buf; |
| 1706 | size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, allocated_audio_buf_size / (enc->channels * osize), | 1716 | size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, |
| 1707 | buf, size / (dec->channels * isize)); | 1717 | allocated_audio_buf_size / (enc->channels * osize), |
| 1718 | buf, | ||
| 1719 | size / (dec->channels * isize)); | ||
| 1708 | if (size_out < 0) { | 1720 | if (size_out < 0) { |
| 1709 | av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n"); | 1721 | av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n"); |
| 1710 | exit_program(1); | 1722 | exit_program(1); |
| @@ -3078,6 +3090,7 @@ static int transcode_init(void) · 1367 unmodified lines | |||
| 3078 | if (!ost->fifo) { | 3090 | if (!ost->fifo) { |
| 3079 | return AVERROR(ENOMEM); | 3091 | return AVERROR(ENOMEM); |
| 3080 | } | 3092 | } |
| 3093 | |||
| 3081 | if (!codec->sample_rate) | 3094 | if (!codec->sample_rate) |
| 3082 | codec->sample_rate = icodec->sample_rate; | 3095 | codec->sample_rate = icodec->sample_rate; |
| 3083 | choose_sample_rate(ost->st, ost->enc); | 3096 | choose_sample_rate(ost->st, ost->enc); |
| @@ -3110,13 +3123,15 @@ static int transcode_init(void) · 26 unmodified lines | |||
| 3110 | if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) | 3123 | if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) |
| 3111 | codec->channel_layout = 0; | 3124 | codec->channel_layout = 0; |
| 3112 | 3125 | ||
| 3113 | ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; | 3126 | |
| 3114 | ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt | 3127 | // ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; |
| 3115 | || codec->channel_layout != icodec->channel_layout; | 3128 | // ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt |
| 3116 | icodec->request_channels = codec->channels; | 3129 | // || codec->channel_layout != icodec->channel_layout; |
| 3130 | icodec->request_channels = codec-> channels; | ||
| 3117 | ost->resample_sample_fmt = icodec->sample_fmt; | 3131 | ost->resample_sample_fmt = icodec->sample_fmt; |
| 3118 | ost->resample_sample_rate = icodec->sample_rate; | 3132 | ost->resample_sample_rate = icodec->sample_rate; |
| 3119 | ost->resample_channels = icodec->channels; | 3133 | ost->resample_channels = icodec->channels; |
| 3134 | ost->resample_channel_layout = icodec->channel_layout; | ||
| 3120 | break; | 3135 | break; |
| 3121 | case AVMEDIA_TYPE_VIDEO: | 3136 | case AVMEDIA_TYPE_VIDEO: |
| 3122 | if (!ost->filter) { | 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 | pminsd %1, %3 | 585 | pminsd %1, %3 |
| 586 | pmaxsd %1, %2 | 586 | pmaxsd %1, %2 |
| 587 | %endmacro | 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 | fate-aac-ap05_48: REF = $(SAMPLES)/aac/ap05_48.s16 | 55 | fate-aac-ap05_48: REF = $(SAMPLES)/aac/ap05_48.s16 |
| 56 | 56 | ||
| 57 | FATE_AAC += fate-aac-latm_stereo_to_51 | 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 | 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.s16 | 59 | fate-aac-latm_stereo_to_51: REF = $(SAMPLES)/aac/latm_stereo_to_51_ref.s16 |
| 60 | 60 | ||
| 61 | fate-aac-ct%: CMD = pcm -i $(SAMPLES)/aac/CT_DecoderCheck/$(@:fate-aac-ct-%=%) | 61 | fate-aac-ct%: CMD = pcm -i $(SAMPLES)/aac/CT_DecoderCheck/$(@:fate-aac-ct-%=%) |
| 62 | fate-aac-ct%: REF = $(SAMPLES)/aac/CT_DecoderCheck/aacPlusv2.wav | 62 | fate-aac-ct%: REF = $(SAMPLES)/aac/CT_DecoderCheck/aacPlusv2.wav |
| @@ -118,7 +118,7 @@ fi · 117 unmodified lines | |||
| 118 | if [ -n "$do_dv_fmt" ] ; then | 118 | if [ -n "$do_dv_fmt" ] ; then |
| 119 | do_lavf_timecode_nodrop dv "-ar 48000 -r 25 -s pal -ac 2" | 119 | do_lavf_timecode_nodrop dv "-ar 48000 -r 25 -s pal -ac 2" |
| 120 | do_lavf_timecode_drop dv "-ar 48000 -pix_fmt yuv411p -s ntsc -ac 2" | 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 | fi | 122 | fi |
| 123 | 123 | ||
| 124 | if [ -n "$do_gxf" ] ; then | 124 | if [ -n "$do_gxf" ] ; then |
| @@ -4,6 +4,6 @@ · 3 unmodified lines | |||
| 4 | cc33ae4f9e6828914dea0f09d1241b7e *./tests/data/lavf/lavf.dv | 4 | cc33ae4f9e6828914dea0f09d1241b7e *./tests/data/lavf/lavf.dv |
| 5 | 3480000 ./tests/data/lavf/lavf.dv | 5 | 3480000 ./tests/data/lavf/lavf.dv |
| 6 | ./tests/data/lavf/lavf.dv CRC=0x8d5e9e8f | 6 | ./tests/data/lavf/lavf.dv CRC=0x8d5e9e8f |
| 7 | b36c83cd0ba0ebe719f09f885c4bbcd3 *./tests/data/lavf/lavf.dv | 7 | 87d3b20f656235671383a7eaa2f66330 *./tests/data/lavf/lavf.dv |
| 8 | 3600000 ./tests/data/lavf/lavf.dv | 8 | 3600000 ./tests/data/lavf/lavf.dv |
| 9 | ./tests/data/lavf/lavf.dv CRC=0x2bc2ae3a | 9 | ./tests/data/lavf/lavf.dv CRC=0x0e868a82 |