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