summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog2
-rw-r--r--doc/APIchanges2
-rw-r--r--doc/filters.texi70
-rw-r--r--libavcodec/x86/cavsdsp_mmx.c6
-rw-r--r--libavcodec/x86/dsputil_mmx.c31
-rw-r--r--libavcodec/x86/dsputil_mmx.h102
-rw-r--r--libavcodec/x86/h264dsp_mmx.c2
-rw-r--r--libavfilter/Makefile2
-rw-r--r--libavfilter/af_aconvert.c4
-rw-r--r--libavfilter/af_aformat.c3
-rw-r--r--libavfilter/af_amerge.c2
-rw-r--r--libavfilter/af_anull.c3
-rw-r--r--libavfilter/af_aresample.c4
-rw-r--r--libavfilter/af_asetnsamples.c2
-rw-r--r--libavfilter/af_astreamsync.c2
-rw-r--r--libavfilter/af_atempo.c2
-rw-r--r--libavfilter/af_channelmap.c402
-rw-r--r--libavfilter/af_join.c500
-rw-r--r--libavfilter/af_pan.c2
-rw-r--r--libavfilter/allfilters.c2
-rw-r--r--libavfilter/audio.c26
-rw-r--r--libavfilter/audio.h6
-rw-r--r--libavfilter/avf_showwaves.c2
-rw-r--r--libavfilter/avfilter.h32
-rw-r--r--libavfilter/avfiltergraph.c44
-rw-r--r--libavfilter/avfiltergraph.h2
-rw-r--r--libavfilter/buffersink.c81
-rw-r--r--libavfilter/defaults.c21
-rw-r--r--libavfilter/fifo.c159
-rw-r--r--libavfilter/formats.c5
-rw-r--r--libavfilter/internal.h8
-rw-r--r--libavfilter/libmpcodecs/vf_uspp.c2
-rw-r--r--libavfilter/sink_buffer.c2
-rw-r--r--libavfilter/version.h4
-rw-r--r--libavfilter/vf_blackdetect.c2
-rw-r--r--libavfilter/vf_idet.c4
-rw-r--r--libavfilter/vf_mp.c15
-rw-r--r--libavfilter/vf_thumbnail.c4
-rw-r--r--libavfilter/vf_tile.c3
-rw-r--r--libavfilter/vf_tinterlace.c4
-rw-r--r--libavfilter/video.c9
-rw-r--r--libavutil/cpu.c4
-rw-r--r--libavutil/cpu.h7
-rw-r--r--libavutil/x86/cpu.c2
44 files changed, 1314 insertions, 279 deletions
diff --git a/Changelog b/Changelog
index b1dc7fa53f..5fc460bc43 100644
--- a/Changelog
+++ b/Changelog
@@ -12,6 +12,8 @@ version next:
- RTMPT protocol support
- iLBC encoding/decoding via libilbc
- Microsoft Screen 1 decoder
+- join audio filter
+- audio channel mapping filter
- showwaves filter
- LucasArts SMUSH playback support
diff --git a/doc/APIchanges b/doc/APIchanges
index 0b5ccc9216..2703610639 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -4,7 +4,7 @@ since the last major version increase.
The last version increases were:
libavcodec: 2012-01-27
libavdevice: 2011-04-18
-libavfilter: 2011-04-18
+libavfilter: 2012-06-22
libavformat: 2012-01-27
libavresample: 2012-04-24
libpostproc: 2011-04-18
diff --git a/doc/filters.texi b/doc/filters.texi
index bf7b12b610..0a5bea6299 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -649,6 +649,76 @@ front_center.wav -map '[LFE]' lfe.wav -map '[SL]' side_left.wav -map '[SR]'
side_right.wav
@end example
+@section channelmap
+Remap input channels to new locations.
+
+This filter accepts the following named parameters:
+@table @option
+@item channel_layout
+Channel layout of the output stream.
+
+@item map
+Map channels from input to output. The argument is a comma-separated list of
+mappings, each in the @code{@var{in_channel}-@var{out_channel}} or
+@var{in_channel} form. @var{in_channel} can be either the name of the input
+channel (e.g. FL for front left) or its index in the input channel layout.
+@var{out_channel} is the name of the output channel or its index in the output
+channel layout. If @var{out_channel} is not given then it is implicitly an
+index, starting with zero and increasing by one for each mapping.
+@end table
+
+If no mapping is present, the filter will implicitly map input channels to
+output channels preserving index.
+
+For example, assuming a 5.1+downmix input MOV file
+@example
+ffmpeg -i in.mov -filter 'channelmap=map=DL-FL\,DR-FR' out.wav
+@end example
+will create an output WAV file tagged as stereo from the downmix channels of
+the input.
+
+To fix a 5.1 WAV improperly encoded in AAC's native channel order
+@example
+ffmpeg -i in.wav -filter 'channelmap=1\,2\,0\,5\,3\,4:channel_layout=5.1' out.wav
+@end example
+
+@section join
+Join multiple input streams into one multi-channel stream.
+
+The filter accepts the following named parameters:
+@table @option
+
+@item inputs
+Number of input streams. Defaults to 2.
+
+@item channel_layout
+Desired output channel layout. Defaults to stereo.
+
+@item map
+Map channels from inputs to output. The argument is a comma-separated list of
+mappings, each in the @code{@var{input_idx}.@var{in_channel}-@var{out_channel}}
+form. @var{input_idx} is the 0-based index of the input stream. @var{in_channel}
+can be either the name of the input channel (e.g. FR for front left) or its
+index in the specified input stream. @var{out_channel} is the name of the output
+channel.
+@end table
+
+The filter will attempt to guess the mappings when those are not specified
+explicitly. It does so by first trying to find an unused matching input channel
+and if that fails it picks the first unused input channel.
+
+E.g. to join 3 inputs (with properly set channel layouts)
+@example
+ffmpeg -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex join=inputs=3 OUTPUT
+@end example
+
+To build a 5.1 output from 6 single-channel streams:
+@example
+ffmpeg -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex
+'join=inputs=6:channel_layout=5.1:map=0.0-FL\,1.0-FR\,2.0-FC\,3.0-SL\,4.0-SR\,5.0-LFE'
+out
+@end example
+
@section resample
Convert the audio sample format, sample rate and channel layout. This filter is
not meant to be used directly.
diff --git a/libavcodec/x86/cavsdsp_mmx.c b/libavcodec/x86/cavsdsp_mmx.c
index 0f5fdaa53d..37b34a82d5 100644
--- a/libavcodec/x86/cavsdsp_mmx.c
+++ b/libavcodec/x86/cavsdsp_mmx.c
@@ -29,6 +29,12 @@
#include "libavcodec/cavsdsp.h"
#include "dsputil_mmx.h"
+/* in/out: mma=mma+mmb, mmb=mmb-mma */
+#define SUMSUB_BA( a, b ) \
+ "paddw "#b", "#a" \n\t"\
+ "paddw "#b", "#b" \n\t"\
+ "psubw "#a", "#b" \n\t"
+
/*****************************************************************************
*
* inverse transform
diff --git a/libavcodec/x86/dsputil_mmx.c b/libavcodec/x86/dsputil_mmx.c
index 31277d547b..e829bbd8b6 100644
--- a/libavcodec/x86/dsputil_mmx.c
+++ b/libavcodec/x86/dsputil_mmx.c
@@ -631,6 +631,34 @@ static void add_hfyu_median_prediction_cmov(uint8_t *dst, const uint8_t *top,
}
#endif
+static inline void transpose4x4(uint8_t *dst, uint8_t *src, x86_reg dst_stride, x86_reg src_stride){
+ __asm__ volatile( //FIXME could save 1 instruction if done as 8x4 ...
+ "movd (%1), %%mm0 \n\t"
+ "add %3, %1 \n\t"
+ "movd (%1), %%mm1 \n\t"
+ "movd (%1,%3,1), %%mm2 \n\t"
+ "movd (%1,%3,2), %%mm3 \n\t"
+ "punpcklbw %%mm1, %%mm0 \n\t"
+ "punpcklbw %%mm3, %%mm2 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+ "punpcklwd %%mm2, %%mm0 \n\t"
+ "punpckhwd %%mm2, %%mm1 \n\t"
+ "movd %%mm0, (%0) \n\t"
+ "add %2, %0 \n\t"
+ "punpckhdq %%mm0, %%mm0 \n\t"
+ "movd %%mm0, (%0) \n\t"
+ "movd %%mm1, (%0,%2,1) \n\t"
+ "punpckhdq %%mm1, %%mm1 \n\t"
+ "movd %%mm1, (%0,%2,2) \n\t"
+
+ : "+&r" (dst),
+ "+&r" (src)
+ : "r" (dst_stride),
+ "r" (src_stride)
+ : "memory"
+ );
+}
+
#define H263_LOOP_FILTER \
"pxor %%mm7, %%mm7 \n\t" \
"movq %0, %%mm0 \n\t" \
@@ -2902,7 +2930,8 @@ static void dsputil_init_3dnow(DSPContext *c, AVCodecContext *avctx,
c->vorbis_inverse_coupling = vorbis_inverse_coupling_3dnow;
#if HAVE_7REGS
- c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov;
+ if (mm_flags & AV_CPU_FLAG_CMOV)
+ c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov;
#endif
}
diff --git a/libavcodec/x86/dsputil_mmx.h b/libavcodec/x86/dsputil_mmx.h
index 91940f6ee8..d0b0344917 100644
--- a/libavcodec/x86/dsputil_mmx.h
+++ b/libavcodec/x86/dsputil_mmx.h
@@ -66,24 +66,6 @@ extern const xmm_reg ff_pb_FE;
extern const double ff_pd_1[2];
extern const double ff_pd_2[2];
-#define LOAD4(stride,in,a,b,c,d)\
- "movq 0*"#stride"+"#in", "#a"\n\t"\
- "movq 1*"#stride"+"#in", "#b"\n\t"\
- "movq 2*"#stride"+"#in", "#c"\n\t"\
- "movq 3*"#stride"+"#in", "#d"\n\t"
-
-#define STORE4(stride,out,a,b,c,d)\
- "movq "#a", 0*"#stride"+"#out"\n\t"\
- "movq "#b", 1*"#stride"+"#out"\n\t"\
- "movq "#c", 2*"#stride"+"#out"\n\t"\
- "movq "#d", 3*"#stride"+"#out"\n\t"
-
-/* in/out: mma=mma+mmb, mmb=mmb-mma */
-#define SUMSUB_BA( a, b ) \
- "paddw "#b", "#a" \n\t"\
- "paddw "#b", "#b" \n\t"\
- "psubw "#a", "#b" \n\t"
-
#define SBUTTERFLY(a,b,t,n,m)\
"mov" #m " " #a ", " #t " \n\t" /* abcd */\
"punpckl" #n " " #b ", " #a " \n\t" /* aebf */\
@@ -95,90 +77,6 @@ extern const double ff_pd_2[2];
SBUTTERFLY(a,c,d,dq,q) /* a=aeim d=bfjn */\
SBUTTERFLY(t,b,c,dq,q) /* t=cgko c=dhlp */
-static inline void transpose4x4(uint8_t *dst, uint8_t *src, x86_reg dst_stride, x86_reg src_stride){
- __asm__ volatile( //FIXME could save 1 instruction if done as 8x4 ...
- "movd (%1), %%mm0 \n\t"
- "add %3, %1 \n\t"
- "movd (%1), %%mm1 \n\t"
- "movd (%1,%3,1), %%mm2 \n\t"
- "movd (%1,%3,2), %%mm3 \n\t"
- "punpcklbw %%mm1, %%mm0 \n\t"
- "punpcklbw %%mm3, %%mm2 \n\t"
- "movq %%mm0, %%mm1 \n\t"
- "punpcklwd %%mm2, %%mm0 \n\t"
- "punpckhwd %%mm2, %%mm1 \n\t"
- "movd %%mm0, (%0) \n\t"
- "add %2, %0 \n\t"
- "punpckhdq %%mm0, %%mm0 \n\t"
- "movd %%mm0, (%0) \n\t"
- "movd %%mm1, (%0,%2,1) \n\t"
- "punpckhdq %%mm1, %%mm1 \n\t"
- "movd %%mm1, (%0,%2,2) \n\t"
-
- : "+&r" (dst),
- "+&r" (src)
- : "r" (dst_stride),
- "r" (src_stride)
- : "memory"
- );
-}
-
-// e,f,g,h can be memory
-// out: a,d,t,c
-#define TRANSPOSE8x4(a,b,c,d,e,f,g,h,t)\
- "punpcklbw " #e ", " #a " \n\t" /* a0 e0 a1 e1 a2 e2 a3 e3 */\
- "punpcklbw " #f ", " #b " \n\t" /* b0 f0 b1 f1 b2 f2 b3 f3 */\
- "punpcklbw " #g ", " #c " \n\t" /* c0 g0 c1 g1 c2 g2 d3 g3 */\
- "punpcklbw " #h ", " #d " \n\t" /* d0 h0 d1 h1 d2 h2 d3 h3 */\
- SBUTTERFLY(a, b, t, bw, q) /* a= a0 b0 e0 f0 a1 b1 e1 f1 */\
- /* t= a2 b2 e2 f2 a3 b3 e3 f3 */\
- SBUTTERFLY(c, d, b, bw, q) /* c= c0 d0 g0 h0 c1 d1 g1 h1 */\
- /* b= c2 d2 g2 h2 c3 d3 g3 h3 */\
- SBUTTERFLY(a, c, d, wd, q) /* a= a0 b0 c0 d0 e0 f0 g0 h0 */\
- /* d= a1 b1 c1 d1 e1 f1 g1 h1 */\
- SBUTTERFLY(t, b, c, wd, q) /* t= a2 b2 c2 d2 e2 f2 g2 h2 */\
- /* c= a3 b3 c3 d3 e3 f3 g3 h3 */
-
-#if ARCH_X86_64
-// permutes 01234567 -> 05736421
-#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\
- SBUTTERFLY(a,b,%%xmm8,wd,dqa)\
- SBUTTERFLY(c,d,b,wd,dqa)\
- SBUTTERFLY(e,f,d,wd,dqa)\
- SBUTTERFLY(g,h,f,wd,dqa)\
- SBUTTERFLY(a,c,h,dq,dqa)\
- SBUTTERFLY(%%xmm8,b,c,dq,dqa)\
- SBUTTERFLY(e,g,b,dq,dqa)\
- SBUTTERFLY(d,f,g,dq,dqa)\
- SBUTTERFLY(a,e,f,qdq,dqa)\
- SBUTTERFLY(%%xmm8,d,e,qdq,dqa)\
- SBUTTERFLY(h,b,d,qdq,dqa)\
- SBUTTERFLY(c,g,b,qdq,dqa)\
- "movdqa %%xmm8, "#g" \n\t"
-#else
-#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\
- "movdqa "#h", "#t" \n\t"\
- SBUTTERFLY(a,b,h,wd,dqa)\
- "movdqa "#h", 16"#t" \n\t"\
- "movdqa "#t", "#h" \n\t"\
- SBUTTERFLY(c,d,b,wd,dqa)\
- SBUTTERFLY(e,f,d,wd,dqa)\
- SBUTTERFLY(g,h,f,wd,dqa)\
- SBUTTERFLY(a,c,h,dq,dqa)\
- "movdqa "#h", "#t" \n\t"\
- "movdqa 16"#t", "#h" \n\t"\
- SBUTTERFLY(h,b,c,dq,dqa)\
- SBUTTERFLY(e,g,b,dq,dqa)\
- SBUTTERFLY(d,f,g,dq,dqa)\
- SBUTTERFLY(a,e,f,qdq,dqa)\
- SBUTTERFLY(h,d,e,qdq,dqa)\
- "movdqa "#h", 16"#t" \n\t"\
- "movdqa "#t", "#h" \n\t"\
- SBUTTERFLY(h,b,d,qdq,dqa)\
- SBUTTERFLY(c,g,b,qdq,dqa)\
- "movdqa 16"#t", "#g" \n\t"
-#endif
-
#define MOVQ_WONE(regd) \
__asm__ volatile ( \
"pcmpeqd %%" #regd ", %%" #regd " \n\t" \
diff --git a/libavcodec/x86/h264dsp_mmx.c b/libavcodec/x86/h264dsp_mmx.c
index 367995c6cb..be7224aed4 100644
--- a/libavcodec/x86/h264dsp_mmx.c
+++ b/libavcodec/x86/h264dsp_mmx.c
@@ -362,7 +362,7 @@ void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth, const int chrom
c->h264_idct_add8 = ff_h264_idct_add8_8_mmx;
c->h264_idct_add16intra = ff_h264_idct_add16intra_8_mmx;
if (mm_flags & AV_CPU_FLAG_CMOV)
- c->h264_luma_dc_dequant_idct= ff_h264_luma_dc_dequant_idct_mmx;
+ c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_mmx;
if (mm_flags & AV_CPU_FLAG_MMX2) {
c->h264_idct_dc_add = ff_h264_idct_dc_add_8_mmx2;
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 088ab8f6a4..5d2c81babf 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -59,8 +59,10 @@ OBJS-$(CONFIG_ASPLIT_FILTER) += split.o
OBJS-$(CONFIG_ASTREAMSYNC_FILTER) += af_astreamsync.o
OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o
OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o
+OBJS-$(CONFIG_CHANNELMAP_FILTER) += af_channelmap.o
OBJS-$(CONFIG_CHANNELSPLIT_FILTER) += af_channelsplit.o
OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o
+OBJS-$(CONFIG_JOIN_FILTER) += af_join.o
OBJS-$(CONFIG_PAN_FILTER) += af_pan.o
OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o
OBJS-$(CONFIG_SILENCEDETECT_FILTER) += af_silencedetect.o
diff --git a/libavfilter/af_aconvert.c b/libavfilter/af_aconvert.c
index 3cf593b723..53d6b87cdd 100644
--- a/libavfilter/af_aconvert.c
+++ b/libavfilter/af_aconvert.c
@@ -75,14 +75,14 @@ static int query_formats(AVFilterContext *ctx)
AVFilterLink *outlink = ctx->outputs[0];
AVFilterChannelLayouts *layouts;
- ff_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
+ ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
&inlink->out_formats);
if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) {
formats = NULL;
ff_add_format(&formats, aconvert->out_sample_fmt);
ff_formats_ref(formats, &outlink->in_formats);
} else
- ff_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
+ ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
&outlink->in_formats);
ff_channel_layouts_ref(ff_all_channel_layouts(),
diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
index 68a38f2189..b8df111063 100644
--- a/libavfilter/af_aformat.c
+++ b/libavfilter/af_aformat.c
@@ -134,8 +134,7 @@ AVFilter avfilter_af_aformat = {
.priv_size = sizeof(AFormatContext),
.inputs = (AVFilterPad[]) {{ .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .filter_samples = ff_null_filter_samples },
+ .type = AVMEDIA_TYPE_AUDIO, },
{ .name = NULL}},
.outputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO},
diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c
index e71c55f8bd..f90412c16b 100644
--- a/libavfilter/af_amerge.c
+++ b/libavfilter/af_amerge.c
@@ -169,7 +169,7 @@ static int request_frame(AVFilterLink *outlink)
for (i = 0; i < am->nb_inputs; i++)
if (!am->in[i].nb_samples)
- if ((ret = avfilter_request_frame(ctx->inputs[i])) < 0)
+ if ((ret = ff_request_frame(ctx->inputs[i])) < 0)
return ret;
return 0;
}
diff --git a/libavfilter/af_anull.c b/libavfilter/af_anull.c
index 81d1bf8a25..f52db1e56d 100644
--- a/libavfilter/af_anull.c
+++ b/libavfilter/af_anull.c
@@ -34,8 +34,7 @@ AVFilter avfilter_af_anull = {
.inputs = (const AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
- .filter_samples = ff_null_filter_samples },
+ .get_audio_buffer = ff_null_get_audio_buffer, },
{ .name = NULL}},
.outputs = (const AVFilterPad[]) {{ .name = "default",
diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
index 81f326ff47..fdbc828b6b 100644
--- a/libavfilter/af_aresample.c
+++ b/libavfilter/af_aresample.c
@@ -112,7 +112,7 @@ static int query_formats(AVFilterContext *ctx)
if(out_format != AV_SAMPLE_FMT_NONE) {
out_formats = ff_make_format_list((int[]){ out_format, -1 });
} else
- out_formats = avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO);
+ out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
ff_formats_ref(out_formats, &outlink->in_formats);
if(out_layout) {
@@ -211,7 +211,7 @@ static int request_frame(AVFilterLink *outlink)
aresample->req_fullfilled = 0;
do{
- ret = avfilter_request_frame(ctx->inputs[0]);
+ ret = ff_request_frame(ctx->inputs[0]);
}while(!aresample->req_fullfilled && ret>=0);
if (ret == AVERROR_EOF) {
diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c
index b373fc254e..d371c98340 100644
--- a/libavfilter/af_asetnsamples.c
+++ b/libavfilter/af_asetnsamples.c
@@ -164,7 +164,7 @@ static int request_frame(AVFilterLink *outlink)
asns->req_fullfilled = 0;
do {
- ret = avfilter_request_frame(inlink);
+ ret = ff_request_frame(inlink);
} while (!asns->req_fullfilled && ret >= 0);
if (ret == AVERROR_EOF)
diff --git a/libavfilter/af_astreamsync.c b/libavfilter/af_astreamsync.c
index 18a2fe6217..ff3f3c2ce0 100644
--- a/libavfilter/af_astreamsync.c
+++ b/libavfilter/af_astreamsync.c
@@ -157,7 +157,7 @@ static int request_frame(AVFilterLink *outlink)
send_next(ctx);
} else {
as->eof |= 1 << as->next_out;
- avfilter_request_frame(ctx->inputs[as->next_out]);
+ ff_request_frame(ctx->inputs[as->next_out]);
if (as->eof & (1 << as->next_out))
as->next_out = !as->next_out;
}
diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c
index 92390cf217..445843968a 100644
--- a/libavfilter/af_atempo.c
+++ b/libavfilter/af_atempo.c
@@ -1083,7 +1083,7 @@ static int request_frame(AVFilterLink *outlink)
atempo->request_fulfilled = 0;
do {
- ret = avfilter_request_frame(ctx->inputs[0]);
+ ret = ff_request_frame(ctx->inputs[0]);
}
while (!atempo->request_fulfilled && ret >= 0);
diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c
new file mode 100644
index 0000000000..fe766fdf11
--- /dev/null
+++ b/libavfilter/af_channelmap.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2012 Google, Inc.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio channel mapping filter
+ */
+
+#include <ctype.h>
+
+#include "libavutil/audioconvert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
+
+#include "audio.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+struct ChannelMap {
+ uint64_t in_channel;
+ uint64_t out_channel;
+ int in_channel_idx;
+ int out_channel_idx;
+};
+
+enum MappingMode {
+ MAP_NONE,
+ MAP_ONE_INT,
+ MAP_ONE_STR,
+ MAP_PAIR_INT_INT,
+ MAP_PAIR_INT_STR,
+ MAP_PAIR_STR_INT,
+ MAP_PAIR_STR_STR
+};
+
+#define MAX_CH 64
+typedef struct ChannelMapContext {
+ const AVClass *class;
+ AVFilterChannelLayouts *channel_layouts;
+ char *mapping_str;
+ char *channel_layout_str;
+ uint64_t output_layout;
+ struct ChannelMap map[MAX_CH];
+ int nch;
+ enum MappingMode mode;
+} ChannelMapContext;
+
+#define OFFSET(x) offsetof(ChannelMapContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM
+static const AVOption options[] = {
+ { "map", "A comma-separated list of input channel numbers in output order.",
+ OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A },
+ { "channel_layout", "Output channel layout.",
+ OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A },
+ { NULL },
+};
+
+static const AVClass channelmap_class = {
+ .class_name = "channel map filter",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static char* split(char *message, char delim) {
+ char *next = strchr(message, delim);
+ if (next)
+ *next++ = '\0';
+ return next;
+}
+
+static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
+{
+ char *next = split(*map, delim);
+ int len;
+ int n = 0;
+ if (!next && delim == '-')
+ return AVERROR(EINVAL);
+ len = strlen(*map);
+ sscanf(*map, "%d%n", ch, &n);
+ if (n != len)
+ return AVERROR(EINVAL);
+ if (*ch < 0 || *ch > max_ch)
+ return AVERROR(EINVAL);
+ *map = next;
+ return 0;
+}
+
+static int get_channel(char **map, uint64_t *ch, char delim)
+{
+ char *next = split(*map, delim);
+ if (!next && delim == '-')
+ return AVERROR(EINVAL);
+ *ch = av_get_channel_layout(*map);
+ if (av_get_channel_layout_nb_channels(*ch) != 1)
+ return AVERROR(EINVAL);
+ *map = next;
+ return 0;
+}
+
+static av_cold int channelmap_init(AVFilterContext *ctx, const char *args,
+ void *opaque)
+{
+ ChannelMapContext *s = ctx->priv;
+ int ret;
+ char *mapping;
+ enum mode;
+ int map_entries = 0;
+ char buf[256];
+ enum MappingMode mode;
+ uint64_t out_ch_mask = 0;
+ int i;
+
+ if (!args) {
+ av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->class = &channelmap_class;
+ av_opt_set_defaults(s);
+
+ if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
+ return ret;
+ }
+
+ mapping = s->mapping_str;
+
+ if (!mapping) {
+ mode = MAP_NONE;
+ } else {
+ char *dash = strchr(mapping, '-');
+ if (!dash) { // short mapping
+ if (isdigit(*mapping))
+ mode = MAP_ONE_INT;
+ else
+ mode = MAP_ONE_STR;
+ } else if (isdigit(*mapping)) {
+ if (isdigit(*(dash+1)))
+ mode = MAP_PAIR_INT_INT;
+ else
+ mode = MAP_PAIR_INT_STR;
+ } else {
+ if (isdigit(*(dash+1)))
+ mode = MAP_PAIR_STR_INT;
+ else
+ mode = MAP_PAIR_STR_STR;
+ }
+ }
+
+ if (mode != MAP_NONE) {
+ char *comma = mapping;
+ map_entries = 1;
+ while ((comma = strchr(comma, ','))) {
+ if (*++comma) // Allow trailing comma
+ map_entries++;
+ }
+ }
+
+ if (map_entries > MAX_CH) {
+ av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ for (i = 0; i < map_entries; i++) {
+ int in_ch_idx = -1, out_ch_idx = -1;
+ uint64_t in_ch = 0, out_ch = 0;
+ static const char err[] = "Failed to parse channel map\n";
+ switch (mode) {
+ case MAP_ONE_INT:
+ if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) {
+ ret = AVERROR(EINVAL);
+ av_log(ctx, AV_LOG_ERROR, err);
+ goto fail;
+ }
+ s->map[i].in_channel_idx = in_ch_idx;
+ s->map[i].out_channel_idx = i;
+ break;
+ case MAP_ONE_STR:
+ if (!get_channel(&mapping, &in_ch, ',')) {
+ av_log(ctx, AV_LOG_ERROR, err);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ s->map[i].in_channel = in_ch;
+ s->map[i].out_channel_idx = i;
+ break;
+ case MAP_PAIR_INT_INT:
+ if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
+ get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
+ av_log(ctx, AV_LOG_ERROR, err);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ s->map[i].in_channel_idx = in_ch_idx;
+ s->map[i].out_channel_idx = out_ch_idx;
+ break;
+ case MAP_PAIR_INT_STR:
+ if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
+ get_channel(&mapping, &out_ch, ',') < 0 ||
+ out_ch & out_ch_mask) {
+ av_log(ctx, AV_LOG_ERROR, err);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ s->map[i].in_channel_idx = in_ch_idx;
+ s->map[i].out_channel = out_ch;
+ out_ch_mask |= out_ch;
+ break;
+ case MAP_PAIR_STR_INT:
+ if (get_channel(&mapping, &in_ch, '-') < 0 ||
+ get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
+ av_log(ctx, AV_LOG_ERROR, err);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ s->map[i].in_channel = in_ch;
+ s->map[i].out_channel_idx = out_ch_idx;
+ break;
+ case MAP_PAIR_STR_STR:
+ if (get_channel(&mapping, &in_ch, '-') < 0 ||
+ get_channel(&mapping, &out_ch, ',') < 0 ||
+ out_ch & out_ch_mask) {
+ av_log(ctx, AV_LOG_ERROR, err);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ s->map[i].in_channel = in_ch;
+ s->map[i].out_channel = out_ch;
+ out_ch_mask |= out_ch;
+ break;
+ }
+ }
+ s->mode = mode;
+ s->nch = map_entries;
+ s->output_layout = out_ch_mask ? out_ch_mask :
+ av_get_default_channel_layout(map_entries);
+
+ if (s->channel_layout_str) {
+ uint64_t fmt;
+ if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
+ s->channel_layout_str);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ if (mode == MAP_NONE) {
+ int i;
+ s->nch = av_get_channel_layout_nb_channels(fmt);
+ for (i = 0; i < s->nch; i++) {
+ s->map[i].in_channel_idx = i;
+ s->map[i].out_channel_idx = i;
+ }
+ } else if (out_ch_mask && out_ch_mask != fmt) {
+ av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
+ av_log(ctx, AV_LOG_ERROR,
+ "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
+ s->channel_layout_str, buf);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Output channel layout %s does not match the number of channels mapped %d.\n",
+ s->channel_layout_str, s->nch);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ s->output_layout = fmt;
+ }
+ ff_add_channel_layout(&s->channel_layouts, s->output_layout);
+
+ if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
+ for (i = 0; i < s->nch; i++) {
+ s->map[i].out_channel_idx = av_get_channel_layout_channel_index(
+ s->output_layout, s->map[i].out_channel);
+ }
+ }
+
+fail:
+ av_opt_free(s);
+ return ret;
+}
+
+static int channelmap_query_formats(AVFilterContext *ctx)
+{
+ ChannelMapContext *s = ctx->priv;
+
+ ff_set_common_formats(ctx, ff_planar_sample_fmts());
+ ff_set_common_samplerates(ctx, ff_all_samplerates());
+ ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts);
+ ff_channel_layouts_ref(s->channel_layouts, &ctx->outputs[0]->in_channel_layouts);
+
+ return 0;
+}
+
+static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const ChannelMapContext *s = ctx->priv;
+ const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout);
+ const int nch_out = s->nch;
+ int ch;
+ uint8_t *source_planes[MAX_CH];
+
+ memcpy(source_planes, buf->extended_data,
+ nch_in * sizeof(source_planes[0]));
+
+ if (nch_out > nch_in) {
+ if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
+ uint8_t **new_extended_data =
+ av_mallocz(nch_out * sizeof(*buf->extended_data));
+ if (!new_extended_data)
+ return;
+ if (buf->extended_data == buf->data) {
+ buf->extended_data = new_extended_data;
+ } else {
+ buf->extended_data = new_extended_data;
+ av_free(buf->extended_data);
+ }
+ } else if (buf->extended_data != buf->data) {
+ av_free(buf->extended_data);
+ buf->extended_data = buf->data;
+ }
+ }
+
+ for (ch = 0; ch < nch_out; ch++) {
+ buf->extended_data[s->map[ch].out_channel_idx] =
+ source_planes[s->map[ch].in_channel_idx];
+ }
+
+ if (buf->data != buf->extended_data)
+ memcpy(buf->data, buf->extended_data,
+ FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
+
+ ff_filter_samples(outlink, buf);
+}
+
+static int channelmap_config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ChannelMapContext *s = ctx->priv;
+ int i, err = 0;
+ const char *channel_name;
+ char layout_name[256];
+
+ if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
+ for (i = 0; i < s->nch; i++) {
+ s->map[i].in_channel_idx = av_get_channel_layout_channel_index(
+ inlink->channel_layout, s->map[i].in_channel);
+ if (s->map[i].in_channel_idx < 0) {
+ channel_name = av_get_channel_name(s->map[i].in_channel);
+ av_get_channel_layout_string(layout_name, sizeof(layout_name),
+ 0, inlink->channel_layout);
+ av_log(ctx, AV_LOG_ERROR,
+ "input channel '%s' not available from input layout '%s'\n",
+ channel_name, layout_name);
+ err = AVERROR(EINVAL);
+ }
+ }
+ }
+
+ return err;
+}
+
+AVFilter avfilter_af_channelmap = {
+ .name = "channelmap",
+ .description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
+ .init = channelmap_init,
+ .query_formats = channelmap_query_formats,
+ .priv_size = sizeof(ChannelMapContext),
+
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_samples = channelmap_filter_samples,
+ .config_props = channelmap_config_input },
+ { .name = NULL }},
+ .outputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO },
+ { .name = NULL }},
+};
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
new file mode 100644
index 0000000000..ab5e9055b3
--- /dev/null
+++ b/libavfilter/af_join.c
@@ -0,0 +1,500 @@
+/*
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Audio join filter
+ *
+ * Join multiple audio inputs as different channels in
+ * a single output
+ */
+
+#include "libavutil/audioconvert.h"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+
+#include "audio.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+typedef struct ChannelMap {
+ int input; ///< input stream index
+ int in_channel_idx; ///< index of in_channel in the input stream data
+ uint64_t in_channel; ///< layout describing the input channel
+ uint64_t out_channel; ///< layout describing the output channel
+} ChannelMap;
+
+typedef struct JoinContext {
+ const AVClass *class;
+
+ int inputs;
+ char *map;
+ char *channel_layout_str;
+ uint64_t channel_layout;
+
+ int nb_channels;
+ ChannelMap *channels;
+
+ /**
+ * Temporary storage for input frames, until we get one on each input.
+ */
+ AVFilterBufferRef **input_frames;
+
+ /**
+ * Temporary storage for data pointers, for assembling the output buffer.
+ */
+ uint8_t **data;
+} JoinContext;
+
+/**
+ * To avoid copying the data from input buffers, this filter creates
+ * a custom output buffer that stores references to all inputs and
+ * unrefs them on free.
+ */
+typedef struct JoinBufferPriv {
+ AVFilterBufferRef **in_buffers;
+ int nb_in_buffers;
+} JoinBufferPriv;
+
+#define OFFSET(x) offsetof(JoinContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM
+static const AVOption join_options[] = {
+ { "inputs", "Number of input streams.", OFFSET(inputs), AV_OPT_TYPE_INT, { 2 }, 1, INT_MAX, A },
+ { "channel_layout", "Channel layout of the "
+ "output stream.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, A },
+ { "map", "A comma-separated list of channels maps in the format "
+ "'input_stream.input_channel-output_channel.",
+ OFFSET(map), AV_OPT_TYPE_STRING, .flags = A },
+ { NULL },
+};
+
+static const AVClass join_class = {
+ .class_name = "join filter",
+ .item_name = av_default_item_name,
+ .option = join_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
+{
+ AVFilterContext *ctx = link->dst;
+ JoinContext *s = ctx->priv;
+ int i;
+
+ for (i = 0; i < ctx->nb_inputs; i++)
+ if (link == ctx->inputs[i])
+ break;
+ av_assert0(i < ctx->nb_inputs);
+ av_assert0(!s->input_frames[i]);
+ s->input_frames[i] = buf;
+}
+
+static int parse_maps(AVFilterContext *ctx)
+{
+ JoinContext *s = ctx->priv;
+ char *cur = s->map;
+
+ while (cur && *cur) {
+ char *sep, *next, *p;
+ uint64_t in_channel = 0, out_channel = 0;
+ int input_idx, out_ch_idx, in_ch_idx;
+
+ next = strchr(cur, ',');
+ if (next)
+ *next++ = 0;
+
+ /* split the map into input and output parts */
+ if (!(sep = strchr(cur, '-'))) {
+ av_log(ctx, AV_LOG_ERROR, "Missing separator '-' in channel "
+ "map '%s'\n", cur);
+ return AVERROR(EINVAL);
+ }
+ *sep++ = 0;
+
+#define PARSE_CHANNEL(str, var, inout) \
+ if (!(var = av_get_channel_layout(str))) { \
+ av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
+ return AVERROR(EINVAL); \
+ } \
+ if (av_get_channel_layout_nb_channels(var) != 1) { \
+ av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one " \
+ inout " channel.\n"); \
+ return AVERROR(EINVAL); \
+ }
+
+ /* parse output channel */
+ PARSE_CHANNEL(sep, out_channel, "output");
+ if (!(out_channel & s->channel_layout)) {
+ av_log(ctx, AV_LOG_ERROR, "Output channel '%s' is not present in "
+ "requested channel layout.\n", sep);
+ return AVERROR(EINVAL);
+ }
+
+ out_ch_idx = av_get_channel_layout_channel_index(s->channel_layout,
+ out_channel);
+ if (s->channels[out_ch_idx].input >= 0) {
+ av_log(ctx, AV_LOG_ERROR, "Multiple maps for output channel "
+ "'%s'.\n", sep);
+ return AVERROR(EINVAL);
+ }
+
+ /* parse input channel */
+ input_idx = strtol(cur, &cur, 0);
+ if (input_idx < 0 || input_idx >= s->inputs) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid input stream index: %d.\n",
+ input_idx);
+ return AVERROR(EINVAL);
+ }
+
+ if (*cur)
+ cur++;
+
+ in_ch_idx = strtol(cur, &p, 0);
+ if (p == cur) {
+ /* channel specifier is not a number,
+ * try to parse as channel name */
+ PARSE_CHANNEL(cur, in_channel, "input");
+ }
+
+ s->channels[out_ch_idx].input = input_idx;
+ if (in_channel)
+ s->channels[out_ch_idx].in_channel = in_channel;
+ else
+ s->channels[out_ch_idx].in_channel_idx = in_ch_idx;
+
+ cur = next;
+ }
+ return 0;
+}
+
+static int join_init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ JoinContext *s = ctx->priv;
+ int ret, i;
+
+ s->class = &join_class;
+ av_opt_set_defaults(s);
+ if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
+ return ret;
+ }
+
+ if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
+ av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
+ s->channel_layout_str);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ s->nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
+ s->channels = av_mallocz(sizeof(*s->channels) * s->nb_channels);
+ s->data = av_mallocz(sizeof(*s->data) * s->nb_channels);
+ s->input_frames = av_mallocz(sizeof(*s->input_frames) * s->inputs);
+ if (!s->channels || !s->data || !s->input_frames) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ for (i = 0; i < s->nb_channels; i++) {
+ s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i);
+ s->channels[i].input = -1;
+ }
+
+ if ((ret = parse_maps(ctx)) < 0)
+ goto fail;
+
+ for (i = 0; i < s->inputs; i++) {
+ char name[32];
+ AVFilterPad pad = { 0 };
+
+ snprintf(name, sizeof(name), "input%d", i);
+ pad.type = AVMEDIA_TYPE_AUDIO;
+ pad.name = av_strdup(name);
+ pad.filter_samples = filter_samples;
+
+ pad.needs_fifo = 1;
+
+ ff_insert_inpad(ctx, i, &pad);
+ }
+
+fail:
+ av_opt_free(s);
+ return ret;
+}
+
+static void join_uninit(AVFilterContext *ctx)
+{
+ JoinContext *s = ctx->priv;
+ int i;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ av_freep(&ctx->input_pads[i].name);
+ avfilter_unref_buffer(s->input_frames[i]);
+ }
+
+ av_freep(&s->channels);
+ av_freep(&s->data);
+ av_freep(&s->input_frames);
+}
+
+static int join_query_formats(AVFilterContext *ctx)
+{
+ JoinContext *s = ctx->priv;
+ AVFilterChannelLayouts *layouts = NULL;
+ int i;
+
+ ff_add_channel_layout(&layouts, s->channel_layout);
+ ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
+
+ for (i = 0; i < ctx->nb_inputs; i++)
+ ff_channel_layouts_ref(ff_all_channel_layouts(),
+ &ctx->inputs[i]->out_channel_layouts);
+
+ ff_set_common_formats (ctx, ff_planar_sample_fmts());
+ ff_set_common_samplerates(ctx, ff_all_samplerates());
+
+ return 0;
+}
+
+static void guess_map_matching(AVFilterContext *ctx, ChannelMap *ch,
+ uint64_t *inputs)
+{
+ int i;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ AVFilterLink *link = ctx->inputs[i];
+
+ if (ch->out_channel & link->channel_layout &&
+ !(ch->out_channel & inputs[i])) {
+ ch->input = i;
+ ch->in_channel = ch->out_channel;
+ inputs[i] |= ch->out_channel;
+ return;
+ }
+ }
+}
+
+static void guess_map_any(AVFilterContext *ctx, ChannelMap *ch,
+ uint64_t *inputs)
+{
+ int i;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ AVFilterLink *link = ctx->inputs[i];
+
+ if ((inputs[i] & link->channel_layout) != link->channel_layout) {
+ uint64_t unused = link->channel_layout & ~inputs[i];
+
+ ch->input = i;
+ ch->in_channel = av_channel_layout_extract_channel(unused, 0);
+ inputs[i] |= ch->in_channel;
+ return;
+ }
+ }
+}
+
+static int join_config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ JoinContext *s = ctx->priv;
+ uint64_t *inputs; // nth element tracks which channels are used from nth input
+ int i, ret = 0;
+
+ /* initialize inputs to user-specified mappings */
+ if (!(inputs = av_mallocz(sizeof(*inputs) * ctx->nb_inputs)))
+ return AVERROR(ENOMEM);
+ for (i = 0; i < s->nb_channels; i++) {
+ ChannelMap *ch = &s->channels[i];
+ AVFilterLink *inlink;
+
+ if (ch->input < 0)
+ continue;
+
+ inlink = ctx->inputs[ch->input];
+
+ if (!ch->in_channel)
+ ch->in_channel = av_channel_layout_extract_channel(inlink->channel_layout,
+ ch->in_channel_idx);
+
+ if (!(ch->in_channel & inlink->channel_layout)) {
+ av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
+ "input stream #%d.\n", av_get_channel_name(ch->in_channel),
+ ch->input);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ inputs[ch->input] |= ch->in_channel;
+ }
+
+ /* guess channel maps when not explicitly defined */
+ /* first try unused matching channels */
+ for (i = 0; i < s->nb_channels; i++) {
+ ChannelMap *ch = &s->channels[i];
+
+ if (ch->input < 0)
+ guess_map_matching(ctx, ch, inputs);
+ }
+
+ /* if the above failed, try to find _any_ unused input channel */
+ for (i = 0; i < s->nb_channels; i++) {
+ ChannelMap *ch = &s->channels[i];
+
+ if (ch->input < 0)
+ guess_map_any(ctx, ch, inputs);
+
+ if (ch->input < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Could not find input channel for "
+ "output channel '%s'.\n",
+ av_get_channel_name(ch->out_channel));
+ goto fail;
+ }
+
+ ch->in_channel_idx = av_get_channel_layout_channel_index(ctx->inputs[ch->input]->channel_layout,
+ ch->in_channel);
+ }
+
+ /* print mappings */
+ av_log(ctx, AV_LOG_VERBOSE, "mappings: ");
+ for (i = 0; i < s->nb_channels; i++) {
+ ChannelMap *ch = &s->channels[i];
+ av_log(ctx, AV_LOG_VERBOSE, "%d.%s => %s ", ch->input,
+ av_get_channel_name(ch->in_channel),
+ av_get_channel_name(ch->out_channel));
+ }
+ av_log(ctx, AV_LOG_VERBOSE, "\n");
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ if (!inputs[i])
+ av_log(ctx, AV_LOG_WARNING, "No channels are used from input "
+ "stream %d.\n", i);
+ }
+
+fail:
+ av_freep(&inputs);
+ return ret;
+}
+
+static void join_free_buffer(AVFilterBuffer *buf)
+{
+ JoinBufferPriv *priv = buf->priv;
+
+ if (priv) {
+ int i;
+
+ for (i = 0; i < priv->nb_in_buffers; i++)
+ avfilter_unref_buffer(priv->in_buffers[i]);
+
+ av_freep(&priv->in_buffers);
+ av_freep(&buf->priv);
+ }
+
+ if (buf->extended_data != buf->data)
+ av_freep(&buf->extended_data);
+ av_freep(&buf);
+}
+
+static int join_request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ JoinContext *s = ctx->priv;
+ AVFilterBufferRef *buf;
+ JoinBufferPriv *priv;
+ int linesize = INT_MAX;
+ int perms = ~0;
+ int nb_samples;
+ int i, j, ret;
+
+ /* get a frame on each input */
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ AVFilterLink *inlink = ctx->inputs[i];
+
+ if (!s->input_frames[i] &&
+ (ret = ff_request_frame(inlink)) < 0)
+ return ret;
+
+ /* request the same number of samples on all inputs */
+ if (i == 0) {
+ nb_samples = s->input_frames[0]->audio->nb_samples;
+
+ for (j = 1; !i && j < ctx->nb_inputs; j++)
+ ctx->inputs[j]->request_samples = nb_samples;
+ }
+ }
+
+ for (i = 0; i < s->nb_channels; i++) {
+ ChannelMap *ch = &s->channels[i];
+ AVFilterBufferRef *cur_buf = s->input_frames[ch->input];
+
+ s->data[i] = cur_buf->extended_data[ch->in_channel_idx];
+ linesize = FFMIN(linesize, cur_buf->linesize[0]);
+ perms &= cur_buf->perms;
+ }
+
+ buf = avfilter_get_audio_buffer_ref_from_arrays(s->data, linesize, perms,
+ nb_samples, outlink->format,
+ outlink->channel_layout);
+ if (!buf)
+ return AVERROR(ENOMEM);
+
+ buf->buf->free = join_free_buffer;
+ buf->pts = s->input_frames[0]->pts;
+
+ if (!(priv = av_mallocz(sizeof(*priv))))
+ goto fail;
+ if (!(priv->in_buffers = av_mallocz(sizeof(*priv->in_buffers) * ctx->nb_inputs)))
+ goto fail;
+
+ for (i = 0; i < ctx->nb_inputs; i++)
+ priv->in_buffers[i] = s->input_frames[i];
+ priv->nb_in_buffers = ctx->nb_inputs;
+ buf->buf->priv = priv;
+
+ ff_filter_samples(outlink, buf);
+
+ memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs);
+
+ return 0;
+
+fail:
+ avfilter_unref_buffer(buf);
+ if (priv)
+ av_freep(&priv->in_buffers);
+ av_freep(&priv);
+ return AVERROR(ENOMEM);
+}
+
+AVFilter avfilter_af_join = {
+ .name = "join",
+ .description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into "
+ "multi-channel output"),
+ .priv_size = sizeof(JoinContext),
+
+ .init = join_init,
+ .uninit = join_uninit,
+ .query_formats = join_query_formats,
+
+ .inputs = (const AVFilterPad[]){{ NULL }},
+ .outputs = (const AVFilterPad[]){{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = join_config_output,
+ .request_frame = join_request_frame, },
+ { NULL }},
+};
diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c
index aed59cd284..cda40a7cdf 100644
--- a/libavfilter/af_pan.c
+++ b/libavfilter/af_pan.c
@@ -217,7 +217,7 @@ static int query_formats(AVFilterContext *ctx)
pan->pure_gains = are_gains_pure(pan);
/* libswr supports any sample and packing formats */
- ff_set_common_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO));
+ ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO));
formats = ff_all_samplerates();
if (!formats)
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 3590b815a6..6458fc5fa7 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -47,8 +47,10 @@ void avfilter_register_all(void)
REGISTER_FILTER (ASTREAMSYNC, astreamsync, af);
REGISTER_FILTER (ASYNCTS, asyncts, af);
REGISTER_FILTER (ATEMPO, atempo, af);
+ REGISTER_FILTER (CHANNELMAP, channelmap, af);
REGISTER_FILTER (CHANNELSPLIT,channelsplit,af);
REGISTER_FILTER (EARWAX, earwax, af);
+ REGISTER_FILTER (JOIN, join, af);
REGISTER_FILTER (PAN, pan, af);
REGISTER_FILTER (SILENCEDETECT, silencedetect, af);
REGISTER_FILTER (VOLUME, volume, af);
diff --git a/libavfilter/audio.c b/libavfilter/audio.c
index d052ad9cf3..6a86597342 100644
--- a/libavfilter/audio.c
+++ b/libavfilter/audio.c
@@ -150,32 +150,12 @@ fail:
return NULL;
}
-void ff_null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
+static void default_filter_samples(AVFilterLink *link,
+ AVFilterBufferRef *samplesref)
{
ff_filter_samples(link->dst->outputs[0], samplesref);
}
-/* FIXME: samplesref is same as link->cur_buf. Need to consider removing the redundant parameter. */
-void ff_default_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref)
-{
- AVFilterLink *outlink = NULL;
-
- if (inlink->dst->nb_outputs)
- outlink = inlink->dst->outputs[0];
-
- if (outlink) {
- outlink->out_buf = ff_default_get_audio_buffer(inlink, AV_PERM_WRITE,
- samplesref->audio->nb_samples);
- outlink->out_buf->pts = samplesref->pts;
- outlink->out_buf->audio->sample_rate = samplesref->audio->sample_rate;
- ff_filter_samples(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
- avfilter_unref_buffer(outlink->out_buf);
- outlink->out_buf = NULL;
- }
- avfilter_unref_buffer(samplesref);
- inlink->cur_buf = NULL;
-}
-
void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
{
void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *);
@@ -186,7 +166,7 @@ void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
FF_TPRINTF_START(NULL, filter_samples); ff_tlog_link(NULL, link, 1);
if (!(filter_samples = dst->filter_samples))
- filter_samples = ff_default_filter_samples;
+ filter_samples = default_filter_samples;
/* prepare to copy the samples if the buffer has insufficient permissions */
if ((dst->min_perms & samplesref->perms) != dst->min_perms ||
diff --git a/libavfilter/audio.h b/libavfilter/audio.h
index e361edc5f8..d4282b59fe 100644
--- a/libavfilter/audio.h
+++ b/libavfilter/audio.h
@@ -63,12 +63,6 @@ AVFilterBufferRef *ff_null_get_audio_buffer(AVFilterLink *link, int perms,
AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms,
int nb_samples);
-/** default handler for filter_samples() for audio inputs */
-void ff_default_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
-
-/** filter_samples() handler for filters which simply pass audio along */
-void ff_null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
-
/**
* Send a buffer of audio samples to the next filter.
*
diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c
index 121f785c15..f6fa45458e 100644
--- a/libavfilter/avf_showwaves.c
+++ b/libavfilter/avf_showwaves.c
@@ -170,7 +170,7 @@ static int request_frame(AVFilterLink *outlink)
showwaves->req_fullfilled = 0;
do {
- ret = avfilter_request_frame(inlink);
+ ret = ff_request_frame(inlink);
} while (!showwaves->req_fullfilled && ret >= 0);
if (ret == AVERROR_EOF && showwaves->outpicref)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 3c7af2d83d..d0a259c22e 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -211,7 +211,6 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask);
*/
void avfilter_unref_buffer(AVFilterBufferRef *ref);
-#if FF_API_FILTERS_PUBLIC
/**
* Remove a reference to a buffer and set the pointer to NULL.
* If this is the last reference to the buffer, the buffer itself
@@ -221,6 +220,7 @@ void avfilter_unref_buffer(AVFilterBufferRef *ref);
*/
void avfilter_unref_bufferp(AVFilterBufferRef **ref);
+#if FF_API_FILTERS_PUBLIC
/**
* A list of supported formats for one end of a filter link. This is used
* during the format negotiation process to try to pick the best format to
@@ -291,7 +291,7 @@ AVFilterFormats *avfilter_make_format_list(const int *fmts);
*
* @return a non negative value in case of success, or a negative
* value corresponding to an AVERROR code in case of error
- * @deprecated Use avfilter_make_all_formats() instead.
+ * @deprecated Use ff_all_formats() instead.
*/
attribute_deprecated
int avfilter_add_format(AVFilterFormats **avff, int64_t fmt);
@@ -479,7 +479,7 @@ struct AVFilterPad {
* Frame request callback. A call to this should result in at least one
* frame being output over the given link. This should return zero on
* success, and another value on error.
- * See avfilter_request_frame() for the error codes with a specific
+ * See ff_request_frame() for the error codes with a specific
* meaning.
*
* Output pads only.
@@ -504,6 +504,14 @@ struct AVFilterPad {
* and another value on error.
*/
int (*config_props)(AVFilterLink *link);
+
+ /**
+ * The filter expects a fifo to be inserted on its input link,
+ * typically because it has a delay.
+ *
+ * input pads only.
+ */
+ int needs_fifo;
};
#endif
@@ -529,6 +537,10 @@ const char *avfilter_pad_get_name(AVFilterPad *pads, int pad_idx);
*/
enum AVMediaType avfilter_pad_get_type(AVFilterPad *pads, int pad_idx);
+/** default handler for end_frame() for video inputs */
+attribute_deprecated
+void avfilter_default_end_frame(AVFilterLink *link);
+
#if FF_API_FILTERS_PUBLIC
/** default handler for start_frame() for video inputs */
attribute_deprecated
@@ -538,10 +550,6 @@ void avfilter_default_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
attribute_deprecated
void avfilter_default_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
-/** default handler for end_frame() for video inputs */
-attribute_deprecated
-void avfilter_default_end_frame(AVFilterLink *link);
-
/** default handler for get_video_buffer() for video inputs */
attribute_deprecated
AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link,
@@ -756,6 +764,15 @@ struct AVFilterLink {
struct AVFilterChannelLayouts *in_channel_layouts;
struct AVFilterChannelLayouts *out_channel_layouts;
+ /**
+ * Audio only, the destination filter sets this to a non-zero value to
+ * request that buffers with the given number of samples should be sent to
+ * it. AVFilterPad.needs_fifo must also be set on the corresponding input
+ * pad.
+ * Last buffer before EOF will be padded with silence.
+ */
+ int request_samples;
+
struct AVFilterPool *pool;
/**
@@ -785,7 +802,6 @@ struct AVFilterLink {
* It is similar to the r_frae_rate field in AVStream.
*/
AVRational frame_rate;
-
};
/**
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index a4ad4da3ce..8892e9decd 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -187,7 +187,7 @@ static int filter_query_formats(AVFilterContext *ctx)
if ((ret = ctx->filter->query_formats(ctx)) < 0)
return ret;
- formats = avfilter_make_all_formats(type);
+ formats = ff_all_formats(type);
if (!formats)
return AVERROR(ENOMEM);
ff_set_common_formats(ctx, formats);
@@ -815,12 +815,52 @@ static int ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
return 0;
}
+static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx)
+{
+ AVFilterContext *f;
+ int i, j, ret;
+ int fifo_count = 0;
+
+ for (i = 0; i < graph->filter_count; i++) {
+ f = graph->filters[i];
+
+ for (j = 0; j < f->nb_inputs; j++) {
+ AVFilterLink *link = f->inputs[j];
+ AVFilterContext *fifo_ctx;
+ AVFilter *fifo;
+ char name[32];
+
+ if (!link->dstpad->needs_fifo)
+ continue;
+
+ fifo = f->inputs[j]->type == AVMEDIA_TYPE_VIDEO ?
+ avfilter_get_by_name("fifo") :
+ avfilter_get_by_name("afifo");
+
+ snprintf(name, sizeof(name), "auto-inserted fifo %d", fifo_count++);
+
+ ret = avfilter_graph_create_filter(&fifo_ctx, fifo, name, NULL,
+ NULL, graph);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_insert_filter(link, fifo_ctx, 0, 0);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
{
int ret;
if ((ret = graph_check_validity(graphctx, log_ctx)))
return ret;
+ if ((ret = graph_insert_fifos(graphctx, log_ctx)) < 0)
+ return ret;
if ((ret = graph_config_formats(graphctx, log_ctx)))
return ret;
if ((ret = graph_config_links(graphctx, log_ctx)))
@@ -939,7 +979,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
{
while (graph->sink_links_count) {
AVFilterLink *oldest = graph->sink_links[0];
- int r = avfilter_request_frame(oldest);
+ int r = ff_request_frame(oldest);
if (r != AVERROR_EOF)
return r;
/* EOF: remove the link from the heap */
diff --git a/libavfilter/avfiltergraph.h b/libavfilter/avfiltergraph.h
index 7e47566129..f983bf8469 100644
--- a/libavfilter/avfiltergraph.h
+++ b/libavfilter/avfiltergraph.h
@@ -257,7 +257,7 @@ char *avfilter_graph_dump(AVFilterGraph *graph, const char *options);
* of a filtergraph, only a convenience function to help drain a filtergraph
* in a balanced way under normal circumstances.
*
- * @return the return value of avfilter_request_frame,
+ * @return the return value of ff_request_frame,
* or AVERROR_EOF of all links returned AVERROR_EOF.
*/
int avfilter_graph_request_oldest(AVFilterGraph *graph);
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index bd693baca8..642350080b 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -25,7 +25,7 @@
#include "libavutil/audio_fifo.h"
#include "libavutil/audioconvert.h"
-#include "libavutil/fifo.h"
+#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "audio.h"
@@ -34,86 +34,45 @@
#include "internal.h"
typedef struct {
- AVFifoBuffer *fifo; ///< FIFO buffer of frame references
-
+ AVFilterBufferRef *cur_buf; ///< last buffer delivered on the sink
AVAudioFifo *audio_fifo; ///< FIFO for audio samples
int64_t next_pts; ///< interpolating audio pts
} BufferSinkContext;
-#define FIFO_INIT_SIZE 8
-
static av_cold void uninit(AVFilterContext *ctx)
{
BufferSinkContext *sink = ctx->priv;
- while (sink->fifo && av_fifo_size(sink->fifo)) {
- AVFilterBufferRef *buf;
- av_fifo_generic_read(sink->fifo, &buf, sizeof(buf), NULL);
- avfilter_unref_buffer(buf);
- }
- av_fifo_free(sink->fifo);
-
if (sink->audio_fifo)
av_audio_fifo_free(sink->audio_fifo);
}
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
-{
- BufferSinkContext *sink = ctx->priv;
-
- if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) {
- av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
- return AVERROR(ENOMEM);
- }
-
- return 0;
-}
-
-static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *buf)
{
- BufferSinkContext *sink = ctx->priv;
-
- if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
- (av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) {
- av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n");
- return;
- }
+ BufferSinkContext *s = link->dst->priv;
- av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL);
-}
-
-static void end_frame(AVFilterLink *link)
-{
- write_buf(link->dst, link->cur_buf);
+// av_assert0(!s->cur_buf);
+ s->cur_buf = buf;
link->cur_buf = NULL;
-}
-
-static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
-{
- write_buf(link->dst, buf);
-}
+};
int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
{
- BufferSinkContext *sink = ctx->priv;
+ BufferSinkContext *s = ctx->priv;
AVFilterLink *link = ctx->inputs[0];
int ret;
- if (!buf) {
- if (av_fifo_size(sink->fifo))
- return av_fifo_size(sink->fifo)/sizeof(*buf);
- else
- return ff_poll_frame(ctx->inputs[0]);
- }
+ if (!buf)
+ return ff_poll_frame(ctx->inputs[0]);
- if (!av_fifo_size(sink->fifo) &&
- (ret = ff_request_frame(link)) < 0)
+ if ((ret = ff_request_frame(link)) < 0)
return ret;
- if (!av_fifo_size(sink->fifo))
+ if (!s->cur_buf)
return AVERROR(EINVAL);
- av_fifo_generic_read(sink->fifo, buf, sizeof(*buf), NULL);
+ *buf = s->cur_buf;
+ s->cur_buf = NULL;
return 0;
}
@@ -182,13 +141,13 @@ AVFilter avfilter_vsink_buffer = {
.name = "buffersink_old",
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
.priv_size = sizeof(BufferSinkContext),
- .init = init,
.uninit = uninit,
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_VIDEO,
- .end_frame = end_frame,
- .min_perms = AV_PERM_READ, },
+ .start_frame = start_frame,
+ .min_perms = AV_PERM_READ,
+ .needs_fifo = 1 },
{ .name = NULL }},
.outputs = (AVFilterPad[]) {{ .name = NULL }},
};
@@ -197,13 +156,13 @@ AVFilter avfilter_asink_abuffer = {
.name = "abuffersink_old",
.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
.priv_size = sizeof(BufferSinkContext),
- .init = init,
.uninit = uninit,
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
- .filter_samples = filter_samples,
- .min_perms = AV_PERM_READ, },
+ .filter_samples = start_frame,
+ .min_perms = AV_PERM_READ,
+ .needs_fifo = 1 },
{ .name = NULL }},
.outputs = (AVFilterPad[]) {{ .name = NULL }},
};
diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c
index c18eacd23a..aa1231db69 100644
--- a/libavfilter/defaults.c
+++ b/libavfilter/defaults.c
@@ -47,27 +47,6 @@ static void set_common_formats(AVFilterContext *ctx, AVFilterFormats *fmts,
}
}
-void avfilter_set_common_pixel_formats(AVFilterContext *ctx, AVFilterFormats *formats)
-{
- set_common_formats(ctx, formats, AVMEDIA_TYPE_VIDEO,
- offsetof(AVFilterLink, in_formats),
- offsetof(AVFilterLink, out_formats));
-}
-
-void avfilter_set_common_sample_formats(AVFilterContext *ctx, AVFilterFormats *formats)
-{
- set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
- offsetof(AVFilterLink, in_formats),
- offsetof(AVFilterLink, out_formats));
-}
-
-void avfilter_set_common_channel_layouts(AVFilterContext *ctx, AVFilterFormats *formats)
-{
- set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
- offsetof(AVFilterLink, in_channel_layouts),
- offsetof(AVFilterLink, out_channel_layouts));
-}
-
#if FF_API_PACKING
void avfilter_set_common_packing_formats(AVFilterContext *ctx, AVFilterFormats *formats)
{
diff --git a/libavfilter/fifo.c b/libavfilter/fifo.c
index da5aa648f6..540dea648a 100644
--- a/libavfilter/fifo.c
+++ b/libavfilter/fifo.c
@@ -23,6 +23,11 @@
* FIFO buffering filter
*/
+#include "libavutil/avassert.h"
+#include "libavutil/audioconvert.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/samplefmt.h"
+
#include "audio.h"
#include "avfilter.h"
#include "internal.h"
@@ -36,6 +41,13 @@ typedef struct Buf {
typedef struct {
Buf root;
Buf *last; ///< last buffered frame
+
+ /**
+ * When a specific number of output samples is requested, the partial
+ * buffer is stored here
+ */
+ AVFilterBufferRef *buf_out;
+ int allocated_samples; ///< number of samples buf_out was allocated for
} FifoContext;
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
@@ -57,6 +69,8 @@ static av_cold void uninit(AVFilterContext *ctx)
avfilter_unref_buffer(buf->buf);
av_free(buf);
}
+
+ avfilter_unref_buffer(fifo->buf_out);
}
static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
@@ -68,14 +82,143 @@ static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
fifo->last->buf = buf;
}
+static void queue_pop(FifoContext *s)
+{
+ Buf *tmp = s->root.next->next;
+ if (s->last == s->root.next)
+ s->last = &s->root;
+ av_freep(&s->root.next);
+ s->root.next = tmp;
+}
+
static void end_frame(AVFilterLink *inlink) { }
static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) { }
+/**
+ * Move data pointers and pts offset samples forward.
+ */
+static void buffer_offset(AVFilterLink *link, AVFilterBufferRef *buf,
+ int offset)
+{
+ int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
+ int planar = av_sample_fmt_is_planar(link->format);
+ int planes = planar ? nb_channels : 1;
+ int block_align = av_get_bytes_per_sample(link->format) * (planar ? 1 : nb_channels);
+ int i;
+
+ av_assert0(buf->audio->nb_samples > offset);
+
+ for (i = 0; i < planes; i++)
+ buf->extended_data[i] += block_align*offset;
+ if (buf->data != buf->extended_data)
+ memcpy(buf->data, buf->extended_data,
+ FFMIN(planes, FF_ARRAY_ELEMS(buf->data)) * sizeof(*buf->data));
+ buf->linesize[0] -= block_align*offset;
+ buf->audio->nb_samples -= offset;
+
+ if (buf->pts != AV_NOPTS_VALUE) {
+ buf->pts += av_rescale_q(offset, (AVRational){1, link->sample_rate},
+ link->time_base);
+ }
+}
+
+static int calc_ptr_alignment(AVFilterBufferRef *buf)
+{
+ int planes = av_sample_fmt_is_planar(buf->format) ?
+ av_get_channel_layout_nb_channels(buf->audio->channel_layout) : 1;
+ int min_align = 128;
+ int p;
+
+ for (p = 0; p < planes; p++) {
+ int cur_align = 128;
+ while ((intptr_t)buf->extended_data[p] % cur_align)
+ cur_align >>= 1;
+ if (cur_align < min_align)
+ min_align = cur_align;
+ }
+ return min_align;
+}
+
+static int return_audio_frame(AVFilterContext *ctx)
+{
+ AVFilterLink *link = ctx->outputs[0];
+ FifoContext *s = ctx->priv;
+ AVFilterBufferRef *head = s->root.next->buf;
+ AVFilterBufferRef *buf_out;
+ int ret;
+
+ if (!s->buf_out &&
+ head->audio->nb_samples >= link->request_samples &&
+ calc_ptr_alignment(head) >= 32) {
+ if (head->audio->nb_samples == link->request_samples) {
+ buf_out = head;
+ queue_pop(s);
+ } else {
+ buf_out = avfilter_ref_buffer(head, AV_PERM_READ);
+ buf_out->audio->nb_samples = link->request_samples;
+ buffer_offset(link, head, link->request_samples);
+ }
+ } else {
+ int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
+
+ if (!s->buf_out) {
+ s->buf_out = ff_get_audio_buffer(link, AV_PERM_WRITE,
+ link->request_samples);
+ if (!s->buf_out)
+ return AVERROR(ENOMEM);
+
+ s->buf_out->audio->nb_samples = 0;
+ s->buf_out->pts = head->pts;
+ s->allocated_samples = link->request_samples;
+ } else if (link->request_samples != s->allocated_samples) {
+ av_log(ctx, AV_LOG_ERROR, "request_samples changed before the "
+ "buffer was returned.\n");
+ return AVERROR(EINVAL);
+ }
+
+ while (s->buf_out->audio->nb_samples < s->allocated_samples) {
+ int len = FFMIN(s->allocated_samples - s->buf_out->audio->nb_samples,
+ head->audio->nb_samples);
+
+ av_samples_copy(s->buf_out->extended_data, head->extended_data,
+ s->buf_out->audio->nb_samples, 0, len, nb_channels,
+ link->format);
+ s->buf_out->audio->nb_samples += len;
+
+ if (len == head->audio->nb_samples) {
+ avfilter_unref_buffer(head);
+ queue_pop(s);
+
+ if (!s->root.next &&
+ (ret = ff_request_frame(ctx->inputs[0])) < 0) {
+ if (ret == AVERROR_EOF) {
+ av_samples_set_silence(s->buf_out->extended_data,
+ s->buf_out->audio->nb_samples,
+ s->allocated_samples -
+ s->buf_out->audio->nb_samples,
+ nb_channels, link->format);
+ s->buf_out->audio->nb_samples = s->allocated_samples;
+ break;
+ }
+ return ret;
+ }
+ head = s->root.next->buf;
+ } else {
+ buffer_offset(link, head, len);
+ }
+ }
+ buf_out = s->buf_out;
+ s->buf_out = NULL;
+ }
+ ff_filter_samples(link, buf_out);
+
+ return 0;
+}
+
static int request_frame(AVFilterLink *outlink)
{
FifoContext *fifo = outlink->src->priv;
- Buf *tmp;
int ret;
if (!fifo->root.next) {
@@ -90,20 +233,20 @@ static int request_frame(AVFilterLink *outlink)
ff_start_frame(outlink, fifo->root.next->buf);
ff_draw_slice (outlink, 0, outlink->h, 1);
ff_end_frame (outlink);
+ queue_pop(fifo);
break;
case AVMEDIA_TYPE_AUDIO:
- ff_filter_samples(outlink, fifo->root.next->buf);
+ if (outlink->request_samples) {
+ return return_audio_frame(outlink->src);
+ } else {
+ ff_filter_samples(outlink, fifo->root.next->buf);
+ queue_pop(fifo);
+ }
break;
default:
return AVERROR(EINVAL);
}
- if (fifo->last == fifo->root.next)
- fifo->last = &fifo->root;
- tmp = fifo->root.next->next;
- av_free(fifo->root.next);
- fifo->root.next = tmp;
-
return 0;
}
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index 8cdd3bee9a..c23f24d6d3 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -262,11 +262,6 @@ int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
AVFilterFormats *ff_all_formats(enum AVMediaType type)
{
- return avfilter_make_all_formats(type);
-}
-
-AVFilterFormats *avfilter_make_all_formats(enum AVMediaType type)
-{
AVFilterFormats *ret = NULL;
int fmt;
int num_formats = type == AVMEDIA_TYPE_VIDEO ? PIX_FMT_NB :
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 9a95da10f1..40ffef5721 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -173,6 +173,14 @@ struct AVFilterPad {
* and another value on error.
*/
int (*config_props)(AVFilterLink *link);
+
+ /**
+ * The filter expects a fifo to be inserted on its input link,
+ * typically because it has a delay.
+ *
+ * input pads only.
+ */
+ int needs_fifo;
};
#endif
diff --git a/libavfilter/libmpcodecs/vf_uspp.c b/libavfilter/libmpcodecs/vf_uspp.c
index d9c5de8fb1..ca9b17aad1 100644
--- a/libavfilter/libmpcodecs/vf_uspp.c
+++ b/libavfilter/libmpcodecs/vf_uspp.c
@@ -94,7 +94,7 @@ static const uint8_t offset[511][2]= {
{ 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 7, 3}, {15, 3}, { 7,11}, {15,11},
{ 7, 5}, {15, 5}, { 7,13}, {15,13}, { 7, 7}, {15, 7}, { 7,15}, {15,15},
-{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, { 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13}, { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9}, { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15}, { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11}, { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13}, { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9}, { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12}, { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8}, { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, { 1, 2}, { 9, 2}, { 1,10}, { 9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14}, { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10}, { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12}, { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
+{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, { 3, 1}, {11,1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13}, { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9}, { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15}, { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11}, { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13}, { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9}, { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12}, { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8}, { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, { 1, 2}, { 9, 2}, { 1,10}, {9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14}, { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10}, { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12}, { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
};
struct vf_priv_s {
diff --git a/libavfilter/sink_buffer.c b/libavfilter/sink_buffer.c
index 27f21b017d..ad516398b4 100644
--- a/libavfilter/sink_buffer.c
+++ b/libavfilter/sink_buffer.c
@@ -127,7 +127,7 @@ int av_buffersink_get_buffer_ref(AVFilterContext *ctx,
if (!av_fifo_size(buf->fifo)) {
if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
return AVERROR(EAGAIN);
- if ((ret = avfilter_request_frame(inlink)) < 0)
+ if ((ret = ff_request_frame(inlink)) < 0)
return ret;
}
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 221a0de041..ab32f29a03 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -28,8 +28,8 @@
#include "libavutil/avutil.h"
-#define LIBAVFILTER_VERSION_MAJOR 2
-#define LIBAVFILTER_VERSION_MINOR 82
+#define LIBAVFILTER_VERSION_MAJOR 3
+#define LIBAVFILTER_VERSION_MINOR 0
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c
index 28020a4134..9d29c4559d 100644
--- a/libavfilter/vf_blackdetect.c
+++ b/libavfilter/vf_blackdetect.c
@@ -136,7 +136,7 @@ static int request_frame(AVFilterLink *outlink)
AVFilterContext *ctx = outlink->src;
BlackDetectContext *blackdetect = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0];
- int ret = avfilter_request_frame(inlink);
+ int ret = ff_request_frame(inlink);
if (ret == AVERROR_EOF && blackdetect->black_started) {
// FIXME: black_end should be set to last_picref_pts + last_picref_duration
diff --git a/libavfilter/vf_idet.c b/libavfilter/vf_idet.c
index 48aad5f417..1dcf7da4dd 100644
--- a/libavfilter/vf_idet.c
+++ b/libavfilter/vf_idet.c
@@ -216,7 +216,7 @@ static int request_frame(AVFilterLink *link)
do {
int ret;
- if ((ret = avfilter_request_frame(link->src->inputs[0])))
+ if ((ret = ff_request_frame(link->src->inputs[0])))
return ret;
} while (!idet->cur);
@@ -231,7 +231,7 @@ static int poll_frame(AVFilterLink *link)
val = ff_poll_frame(link->src->inputs[0]);
if (val >= 1 && !idet->next) { //FIXME change API to not requre this red tape
- if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0)
+ if ((ret = ff_request_frame(link->src->inputs[0])) < 0)
return ret;
val = ff_poll_frame(link->src->inputs[0]);
}
diff --git a/libavfilter/vf_mp.c b/libavfilter/vf_mp.c
index bf3975af3d..43eecc3c91 100644
--- a/libavfilter/vf_mp.c
+++ b/libavfilter/vf_mp.c
@@ -25,6 +25,9 @@
*/
#include "avfilter.h"
+#include "video.h"
+#include "formats.h"
+#include "internal.h"
#include "libavutil/avassert.h"
#include "libavutil/pixdesc.h"
#include "libavutil/intreadwrite.h"
@@ -633,9 +636,9 @@ int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
if(pts != MP_NOPTS_VALUE)
picref->pts= pts * av_q2d(outlink->time_base);
- avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
- avfilter_draw_slice(outlink, 0, picref->video->h, 1);
- avfilter_end_frame(outlink);
+ ff_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
+ ff_draw_slice(outlink, 0, picref->video->h, 1);
+ ff_end_frame(outlink);
avfilter_unref_buffer(picref);
m->frame_returned++;
@@ -788,14 +791,14 @@ static int query_formats(AVFilterContext *ctx)
if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
if (conversion_map[i].pix_fmt != lastpixfmt) {
- avfilter_add_format(&avfmts, conversion_map[i].pix_fmt);
+ ff_add_format(&avfmts, conversion_map[i].pix_fmt);
lastpixfmt = conversion_map[i].pix_fmt;
}
}
}
//We assume all allowed input formats are also allowed output formats
- avfilter_set_common_pixel_formats(ctx, avfmts);
+ ff_set_common_formats(ctx, avfmts);
return 0;
}
@@ -836,7 +839,7 @@ static int request_frame(AVFilterLink *outlink)
av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
for(m->frame_returned=0; !m->frame_returned;){
- ret=avfilter_request_frame(outlink->src->inputs[0]);
+ ret=ff_request_frame(outlink->src->inputs[0]);
if(ret<0)
break;
}
diff --git a/libavfilter/vf_thumbnail.c b/libavfilter/vf_thumbnail.c
index 215f50a509..45238b6a77 100644
--- a/libavfilter/vf_thumbnail.c
+++ b/libavfilter/vf_thumbnail.c
@@ -178,7 +178,7 @@ static int request_frame(AVFilterLink *link)
/* loop until a frame thumbnail is available (when a frame is queued,
* thumb->n is reset to zero) */
do {
- int ret = avfilter_request_frame(link->src->inputs[0]);
+ int ret = ff_request_frame(link->src->inputs[0]);
if (ret < 0)
return ret;
} while (thumb->n);
@@ -203,7 +203,7 @@ static int poll_frame(AVFilterLink *link)
/* we have some frame(s) available in the input link, but not yet enough to
* output a thumbnail, so we request more */
- ret = avfilter_request_frame(inlink);
+ ret = ff_request_frame(inlink);
return ret < 0 ? ret : 0;
}
diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c
index e6971de9ee..83ee45dda0 100644
--- a/libavfilter/vf_tile.c
+++ b/libavfilter/vf_tile.c
@@ -28,6 +28,7 @@
#include "drawutils.h"
#include "formats.h"
#include "video.h"
+#include "internal.h"
typedef struct {
unsigned w, h;
@@ -170,7 +171,7 @@ static int request_frame(AVFilterLink *outlink)
int r;
while (1) {
- r = avfilter_request_frame(inlink);
+ r = ff_request_frame(inlink);
if (r < 0) {
if (r == AVERROR_EOF && tile->current)
end_last_frame(ctx);
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 8f9dc004fc..b0d04eb418 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -334,7 +334,7 @@ static int poll_frame(AVFilterLink *outlink)
val = ff_poll_frame(inlink);
if (val == 1 && !tinterlace->next) {
- if ((ret = avfilter_request_frame(inlink)) < 0)
+ if ((ret = ff_request_frame(inlink)) < 0)
return ret;
val = ff_poll_frame(inlink);
}
@@ -351,7 +351,7 @@ static int request_frame(AVFilterLink *outlink)
do {
int ret;
- if ((ret = avfilter_request_frame(inlink)) < 0)
+ if ((ret = ff_request_frame(inlink)) < 0)
return ret;
} while (!tinterlace->cur);
diff --git a/libavfilter/video.c b/libavfilter/video.c
index ab6e2cd5b8..561abbc531 100644
--- a/libavfilter/video.c
+++ b/libavfilter/video.c
@@ -321,6 +321,11 @@ void ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
draw_slice(link, y, h, slice_dir);
}
+void avfilter_default_end_frame(AVFilterLink *inlink)
+{
+ default_end_frame(inlink);
+}
+
#if FF_API_FILTERS_PUBLIC
AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
{
@@ -330,10 +335,6 @@ void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picre
{
default_start_frame(inlink, picref);
}
-void avfilter_default_end_frame(AVFilterLink *inlink)
-{
- default_end_frame(inlink);
-}
void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
{
default_draw_slice(inlink, y, h, slice_dir);
diff --git a/libavutil/cpu.c b/libavutil/cpu.c
index b911880cad..7a7a272c82 100644
--- a/libavutil/cpu.c
+++ b/libavutil/cpu.c
@@ -49,7 +49,7 @@ void av_set_cpu_flags_mask(int mask)
int av_parse_cpu_flags(const char *s)
{
-#define CPUFLAG_MMX2 (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMX2)
+#define CPUFLAG_MMX2 (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_CMOV)
#define CPUFLAG_3DNOW (AV_CPU_FLAG_3DNOW | AV_CPU_FLAG_MMX)
#define CPUFLAG_3DNOWEXT (AV_CPU_FLAG_3DNOWEXT | CPUFLAG_3DNOW)
#define CPUFLAG_SSE (AV_CPU_FLAG_SSE | CPUFLAG_MMX2)
@@ -84,6 +84,7 @@ int av_parse_cpu_flags(const char *s)
{ "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_FMA4 }, .unit = "flags" },
{ "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOW }, .unit = "flags" },
{ "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOWEXT }, .unit = "flags" },
+ { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_CMOV }, .unit = "flags" },
#elif ARCH_ARM
{ "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV5TE }, .unit = "flags" },
{ "armv6", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV6 }, .unit = "flags" },
@@ -188,6 +189,7 @@ static const struct {
{ AV_CPU_FLAG_FMA4, "fma4" },
{ AV_CPU_FLAG_3DNOW, "3dnow" },
{ AV_CPU_FLAG_3DNOWEXT, "3dnowext" },
+ { AV_CPU_FLAG_CMOV, "cmov" },
#endif
{ 0 }
};
diff --git a/libavutil/cpu.h b/libavutil/cpu.h
index dec0566d04..ee6705adef 100644
--- a/libavutil/cpu.h
+++ b/libavutil/cpu.h
@@ -40,9 +40,14 @@
#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions
#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions
#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used
-#define AV_CPU_FLAG_CMOV 0x1000000 ///< supports cmov instruction
#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions
#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions
+#if LIBAVUTIL_VERSION_MAJOR <52
+#define AV_CPU_FLAG_CMOV 0x1001000 ///< supports cmov instruction
+#else
+#define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction
+#endif
+
#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard
#define AV_CPU_FLAG_ARMV5TE (1 << 0)
diff --git a/libavutil/x86/cpu.c b/libavutil/x86/cpu.c
index b53379bbd3..5782ff73cf 100644
--- a/libavutil/x86/cpu.c
+++ b/libavutil/x86/cpu.c
@@ -83,7 +83,7 @@ int ff_get_cpu_flags_x86(void)
cpuid(1, eax, ebx, ecx, std_caps);
family = ((eax>>8)&0xf) + ((eax>>20)&0xff);
model = ((eax>>4)&0xf) + ((eax>>12)&0xf0);
- if (std_caps & (1<<15))
+ if (std_caps & (1 << 15))
rval |= AV_CPU_FLAG_CMOV;
if (std_caps & (1<<23))
rval |= AV_CPU_FLAG_MMX;