* qatar/master:
x86: Only use optimizations with cmov if the CPU supports the instruction
x86: Add CPU flag for the i686 cmov instruction
x86: remove unused inline asm macros from dsputil_mmx.h
x86: move some inline asm macros to the only places they are used
lavfi: Add the af_channelmap audio channel mapping filter.
lavfi: add join audio filter.
lavfi: allow audio filters to request a given number of samples.
lavfi: support automatically inserting the fifo filter when needed.
lavfi/audio: eliminate ff_default_filter_samples().
Conflicts:
Changelog
libavcodec/x86/h264dsp_mmx.c
libavfilter/Makefile
libavfilter/allfilters.c
libavfilter/avfilter.h
libavfilter/avfiltergraph.c
libavfilter/version.h
libavutil/x86/cpu.c
Merged-by: Michael Niedermayer <michaelni@gmx.at>
... | ... |
@@ -649,6 +649,76 @@ front_center.wav -map '[LFE]' lfe.wav -map '[SL]' side_left.wav -map '[SR]' |
649 | 649 |
side_right.wav |
650 | 650 |
@end example |
651 | 651 |
|
652 |
+@section channelmap |
|
653 |
+Remap input channels to new locations. |
|
654 |
+ |
|
655 |
+This filter accepts the following named parameters: |
|
656 |
+@table @option |
|
657 |
+@item channel_layout |
|
658 |
+Channel layout of the output stream. |
|
659 |
+ |
|
660 |
+@item map |
|
661 |
+Map channels from input to output. The argument is a comma-separated list of |
|
662 |
+mappings, each in the @code{@var{in_channel}-@var{out_channel}} or |
|
663 |
+@var{in_channel} form. @var{in_channel} can be either the name of the input |
|
664 |
+channel (e.g. FL for front left) or its index in the input channel layout. |
|
665 |
+@var{out_channel} is the name of the output channel or its index in the output |
|
666 |
+channel layout. If @var{out_channel} is not given then it is implicitly an |
|
667 |
+index, starting with zero and increasing by one for each mapping. |
|
668 |
+@end table |
|
669 |
+ |
|
670 |
+If no mapping is present, the filter will implicitly map input channels to |
|
671 |
+output channels preserving index. |
|
672 |
+ |
|
673 |
+For example, assuming a 5.1+downmix input MOV file |
|
674 |
+@example |
|
675 |
+ffmpeg -i in.mov -filter 'channelmap=map=DL-FL\,DR-FR' out.wav |
|
676 |
+@end example |
|
677 |
+will create an output WAV file tagged as stereo from the downmix channels of |
|
678 |
+the input. |
|
679 |
+ |
|
680 |
+To fix a 5.1 WAV improperly encoded in AAC's native channel order |
|
681 |
+@example |
|
682 |
+ffmpeg -i in.wav -filter 'channelmap=1\,2\,0\,5\,3\,4:channel_layout=5.1' out.wav |
|
683 |
+@end example |
|
684 |
+ |
|
685 |
+@section join |
|
686 |
+Join multiple input streams into one multi-channel stream. |
|
687 |
+ |
|
688 |
+The filter accepts the following named parameters: |
|
689 |
+@table @option |
|
690 |
+ |
|
691 |
+@item inputs |
|
692 |
+Number of input streams. Defaults to 2. |
|
693 |
+ |
|
694 |
+@item channel_layout |
|
695 |
+Desired output channel layout. Defaults to stereo. |
|
696 |
+ |
|
697 |
+@item map |
|
698 |
+Map channels from inputs to output. The argument is a comma-separated list of |
|
699 |
+mappings, each in the @code{@var{input_idx}.@var{in_channel}-@var{out_channel}} |
|
700 |
+form. @var{input_idx} is the 0-based index of the input stream. @var{in_channel} |
|
701 |
+can be either the name of the input channel (e.g. FR for front left) or its |
|
702 |
+index in the specified input stream. @var{out_channel} is the name of the output |
|
703 |
+channel. |
|
704 |
+@end table |
|
705 |
+ |
|
706 |
+The filter will attempt to guess the mappings when those are not specified |
|
707 |
+explicitly. It does so by first trying to find an unused matching input channel |
|
708 |
+and if that fails it picks the first unused input channel. |
|
709 |
+ |
|
710 |
+E.g. to join 3 inputs (with properly set channel layouts) |
|
711 |
+@example |
|
712 |
+ffmpeg -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex join=inputs=3 OUTPUT |
|
713 |
+@end example |
|
714 |
+ |
|
715 |
+To build a 5.1 output from 6 single-channel streams: |
|
716 |
+@example |
|
717 |
+ffmpeg -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex |
|
718 |
+'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' |
|
719 |
+out |
|
720 |
+@end example |
|
721 |
+ |
|
652 | 722 |
@section resample |
653 | 723 |
Convert the audio sample format, sample rate and channel layout. This filter is |
654 | 724 |
not meant to be used directly. |
... | ... |
@@ -29,6 +29,12 @@ |
29 | 29 |
#include "libavcodec/cavsdsp.h" |
30 | 30 |
#include "dsputil_mmx.h" |
31 | 31 |
|
32 |
+/* in/out: mma=mma+mmb, mmb=mmb-mma */ |
|
33 |
+#define SUMSUB_BA( a, b ) \ |
|
34 |
+ "paddw "#b", "#a" \n\t"\ |
|
35 |
+ "paddw "#b", "#b" \n\t"\ |
|
36 |
+ "psubw "#a", "#b" \n\t" |
|
37 |
+ |
|
32 | 38 |
/***************************************************************************** |
33 | 39 |
* |
34 | 40 |
* inverse transform |
... | ... |
@@ -631,6 +631,34 @@ static void add_hfyu_median_prediction_cmov(uint8_t *dst, const uint8_t *top, |
631 | 631 |
} |
632 | 632 |
#endif |
633 | 633 |
|
634 |
+static inline void transpose4x4(uint8_t *dst, uint8_t *src, x86_reg dst_stride, x86_reg src_stride){ |
|
635 |
+ __asm__ volatile( //FIXME could save 1 instruction if done as 8x4 ... |
|
636 |
+ "movd (%1), %%mm0 \n\t" |
|
637 |
+ "add %3, %1 \n\t" |
|
638 |
+ "movd (%1), %%mm1 \n\t" |
|
639 |
+ "movd (%1,%3,1), %%mm2 \n\t" |
|
640 |
+ "movd (%1,%3,2), %%mm3 \n\t" |
|
641 |
+ "punpcklbw %%mm1, %%mm0 \n\t" |
|
642 |
+ "punpcklbw %%mm3, %%mm2 \n\t" |
|
643 |
+ "movq %%mm0, %%mm1 \n\t" |
|
644 |
+ "punpcklwd %%mm2, %%mm0 \n\t" |
|
645 |
+ "punpckhwd %%mm2, %%mm1 \n\t" |
|
646 |
+ "movd %%mm0, (%0) \n\t" |
|
647 |
+ "add %2, %0 \n\t" |
|
648 |
+ "punpckhdq %%mm0, %%mm0 \n\t" |
|
649 |
+ "movd %%mm0, (%0) \n\t" |
|
650 |
+ "movd %%mm1, (%0,%2,1) \n\t" |
|
651 |
+ "punpckhdq %%mm1, %%mm1 \n\t" |
|
652 |
+ "movd %%mm1, (%0,%2,2) \n\t" |
|
653 |
+ |
|
654 |
+ : "+&r" (dst), |
|
655 |
+ "+&r" (src) |
|
656 |
+ : "r" (dst_stride), |
|
657 |
+ "r" (src_stride) |
|
658 |
+ : "memory" |
|
659 |
+ ); |
|
660 |
+} |
|
661 |
+ |
|
634 | 662 |
#define H263_LOOP_FILTER \ |
635 | 663 |
"pxor %%mm7, %%mm7 \n\t" \ |
636 | 664 |
"movq %0, %%mm0 \n\t" \ |
... | ... |
@@ -2902,7 +2930,8 @@ static void dsputil_init_3dnow(DSPContext *c, AVCodecContext *avctx, |
2902 | 2902 |
c->vorbis_inverse_coupling = vorbis_inverse_coupling_3dnow; |
2903 | 2903 |
|
2904 | 2904 |
#if HAVE_7REGS |
2905 |
- c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov; |
|
2905 |
+ if (mm_flags & AV_CPU_FLAG_CMOV) |
|
2906 |
+ c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov; |
|
2906 | 2907 |
#endif |
2907 | 2908 |
} |
2908 | 2909 |
|
... | ... |
@@ -66,24 +66,6 @@ extern const xmm_reg ff_pb_FE; |
66 | 66 |
extern const double ff_pd_1[2]; |
67 | 67 |
extern const double ff_pd_2[2]; |
68 | 68 |
|
69 |
-#define LOAD4(stride,in,a,b,c,d)\ |
|
70 |
- "movq 0*"#stride"+"#in", "#a"\n\t"\ |
|
71 |
- "movq 1*"#stride"+"#in", "#b"\n\t"\ |
|
72 |
- "movq 2*"#stride"+"#in", "#c"\n\t"\ |
|
73 |
- "movq 3*"#stride"+"#in", "#d"\n\t" |
|
74 |
- |
|
75 |
-#define STORE4(stride,out,a,b,c,d)\ |
|
76 |
- "movq "#a", 0*"#stride"+"#out"\n\t"\ |
|
77 |
- "movq "#b", 1*"#stride"+"#out"\n\t"\ |
|
78 |
- "movq "#c", 2*"#stride"+"#out"\n\t"\ |
|
79 |
- "movq "#d", 3*"#stride"+"#out"\n\t" |
|
80 |
- |
|
81 |
-/* in/out: mma=mma+mmb, mmb=mmb-mma */ |
|
82 |
-#define SUMSUB_BA( a, b ) \ |
|
83 |
- "paddw "#b", "#a" \n\t"\ |
|
84 |
- "paddw "#b", "#b" \n\t"\ |
|
85 |
- "psubw "#a", "#b" \n\t" |
|
86 |
- |
|
87 | 69 |
#define SBUTTERFLY(a,b,t,n,m)\ |
88 | 70 |
"mov" #m " " #a ", " #t " \n\t" /* abcd */\ |
89 | 71 |
"punpckl" #n " " #b ", " #a " \n\t" /* aebf */\ |
... | ... |
@@ -95,90 +77,6 @@ extern const double ff_pd_2[2]; |
95 | 95 |
SBUTTERFLY(a,c,d,dq,q) /* a=aeim d=bfjn */\ |
96 | 96 |
SBUTTERFLY(t,b,c,dq,q) /* t=cgko c=dhlp */ |
97 | 97 |
|
98 |
-static inline void transpose4x4(uint8_t *dst, uint8_t *src, x86_reg dst_stride, x86_reg src_stride){ |
|
99 |
- __asm__ volatile( //FIXME could save 1 instruction if done as 8x4 ... |
|
100 |
- "movd (%1), %%mm0 \n\t" |
|
101 |
- "add %3, %1 \n\t" |
|
102 |
- "movd (%1), %%mm1 \n\t" |
|
103 |
- "movd (%1,%3,1), %%mm2 \n\t" |
|
104 |
- "movd (%1,%3,2), %%mm3 \n\t" |
|
105 |
- "punpcklbw %%mm1, %%mm0 \n\t" |
|
106 |
- "punpcklbw %%mm3, %%mm2 \n\t" |
|
107 |
- "movq %%mm0, %%mm1 \n\t" |
|
108 |
- "punpcklwd %%mm2, %%mm0 \n\t" |
|
109 |
- "punpckhwd %%mm2, %%mm1 \n\t" |
|
110 |
- "movd %%mm0, (%0) \n\t" |
|
111 |
- "add %2, %0 \n\t" |
|
112 |
- "punpckhdq %%mm0, %%mm0 \n\t" |
|
113 |
- "movd %%mm0, (%0) \n\t" |
|
114 |
- "movd %%mm1, (%0,%2,1) \n\t" |
|
115 |
- "punpckhdq %%mm1, %%mm1 \n\t" |
|
116 |
- "movd %%mm1, (%0,%2,2) \n\t" |
|
117 |
- |
|
118 |
- : "+&r" (dst), |
|
119 |
- "+&r" (src) |
|
120 |
- : "r" (dst_stride), |
|
121 |
- "r" (src_stride) |
|
122 |
- : "memory" |
|
123 |
- ); |
|
124 |
-} |
|
125 |
- |
|
126 |
-// e,f,g,h can be memory |
|
127 |
-// out: a,d,t,c |
|
128 |
-#define TRANSPOSE8x4(a,b,c,d,e,f,g,h,t)\ |
|
129 |
- "punpcklbw " #e ", " #a " \n\t" /* a0 e0 a1 e1 a2 e2 a3 e3 */\ |
|
130 |
- "punpcklbw " #f ", " #b " \n\t" /* b0 f0 b1 f1 b2 f2 b3 f3 */\ |
|
131 |
- "punpcklbw " #g ", " #c " \n\t" /* c0 g0 c1 g1 c2 g2 d3 g3 */\ |
|
132 |
- "punpcklbw " #h ", " #d " \n\t" /* d0 h0 d1 h1 d2 h2 d3 h3 */\ |
|
133 |
- SBUTTERFLY(a, b, t, bw, q) /* a= a0 b0 e0 f0 a1 b1 e1 f1 */\ |
|
134 |
- /* t= a2 b2 e2 f2 a3 b3 e3 f3 */\ |
|
135 |
- SBUTTERFLY(c, d, b, bw, q) /* c= c0 d0 g0 h0 c1 d1 g1 h1 */\ |
|
136 |
- /* b= c2 d2 g2 h2 c3 d3 g3 h3 */\ |
|
137 |
- SBUTTERFLY(a, c, d, wd, q) /* a= a0 b0 c0 d0 e0 f0 g0 h0 */\ |
|
138 |
- /* d= a1 b1 c1 d1 e1 f1 g1 h1 */\ |
|
139 |
- SBUTTERFLY(t, b, c, wd, q) /* t= a2 b2 c2 d2 e2 f2 g2 h2 */\ |
|
140 |
- /* c= a3 b3 c3 d3 e3 f3 g3 h3 */ |
|
141 |
- |
|
142 |
-#if ARCH_X86_64 |
|
143 |
-// permutes 01234567 -> 05736421 |
|
144 |
-#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\ |
|
145 |
- SBUTTERFLY(a,b,%%xmm8,wd,dqa)\ |
|
146 |
- SBUTTERFLY(c,d,b,wd,dqa)\ |
|
147 |
- SBUTTERFLY(e,f,d,wd,dqa)\ |
|
148 |
- SBUTTERFLY(g,h,f,wd,dqa)\ |
|
149 |
- SBUTTERFLY(a,c,h,dq,dqa)\ |
|
150 |
- SBUTTERFLY(%%xmm8,b,c,dq,dqa)\ |
|
151 |
- SBUTTERFLY(e,g,b,dq,dqa)\ |
|
152 |
- SBUTTERFLY(d,f,g,dq,dqa)\ |
|
153 |
- SBUTTERFLY(a,e,f,qdq,dqa)\ |
|
154 |
- SBUTTERFLY(%%xmm8,d,e,qdq,dqa)\ |
|
155 |
- SBUTTERFLY(h,b,d,qdq,dqa)\ |
|
156 |
- SBUTTERFLY(c,g,b,qdq,dqa)\ |
|
157 |
- "movdqa %%xmm8, "#g" \n\t" |
|
158 |
-#else |
|
159 |
-#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\ |
|
160 |
- "movdqa "#h", "#t" \n\t"\ |
|
161 |
- SBUTTERFLY(a,b,h,wd,dqa)\ |
|
162 |
- "movdqa "#h", 16"#t" \n\t"\ |
|
163 |
- "movdqa "#t", "#h" \n\t"\ |
|
164 |
- SBUTTERFLY(c,d,b,wd,dqa)\ |
|
165 |
- SBUTTERFLY(e,f,d,wd,dqa)\ |
|
166 |
- SBUTTERFLY(g,h,f,wd,dqa)\ |
|
167 |
- SBUTTERFLY(a,c,h,dq,dqa)\ |
|
168 |
- "movdqa "#h", "#t" \n\t"\ |
|
169 |
- "movdqa 16"#t", "#h" \n\t"\ |
|
170 |
- SBUTTERFLY(h,b,c,dq,dqa)\ |
|
171 |
- SBUTTERFLY(e,g,b,dq,dqa)\ |
|
172 |
- SBUTTERFLY(d,f,g,dq,dqa)\ |
|
173 |
- SBUTTERFLY(a,e,f,qdq,dqa)\ |
|
174 |
- SBUTTERFLY(h,d,e,qdq,dqa)\ |
|
175 |
- "movdqa "#h", 16"#t" \n\t"\ |
|
176 |
- "movdqa "#t", "#h" \n\t"\ |
|
177 |
- SBUTTERFLY(h,b,d,qdq,dqa)\ |
|
178 |
- SBUTTERFLY(c,g,b,qdq,dqa)\ |
|
179 |
- "movdqa 16"#t", "#g" \n\t" |
|
180 |
-#endif |
|
181 |
- |
|
182 | 98 |
#define MOVQ_WONE(regd) \ |
183 | 99 |
__asm__ volatile ( \ |
184 | 100 |
"pcmpeqd %%" #regd ", %%" #regd " \n\t" \ |
... | ... |
@@ -362,7 +362,7 @@ void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth, const int chrom |
362 | 362 |
c->h264_idct_add8 = ff_h264_idct_add8_8_mmx; |
363 | 363 |
c->h264_idct_add16intra = ff_h264_idct_add16intra_8_mmx; |
364 | 364 |
if (mm_flags & AV_CPU_FLAG_CMOV) |
365 |
- c->h264_luma_dc_dequant_idct= ff_h264_luma_dc_dequant_idct_mmx; |
|
365 |
+ c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_mmx; |
|
366 | 366 |
|
367 | 367 |
if (mm_flags & AV_CPU_FLAG_MMX2) { |
368 | 368 |
c->h264_idct_dc_add = ff_h264_idct_dc_add_8_mmx2; |
... | ... |
@@ -59,8 +59,10 @@ OBJS-$(CONFIG_ASPLIT_FILTER) += split.o |
59 | 59 |
OBJS-$(CONFIG_ASTREAMSYNC_FILTER) += af_astreamsync.o |
60 | 60 |
OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o |
61 | 61 |
OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o |
62 |
+OBJS-$(CONFIG_CHANNELMAP_FILTER) += af_channelmap.o |
|
62 | 63 |
OBJS-$(CONFIG_CHANNELSPLIT_FILTER) += af_channelsplit.o |
63 | 64 |
OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o |
65 |
+OBJS-$(CONFIG_JOIN_FILTER) += af_join.o |
|
64 | 66 |
OBJS-$(CONFIG_PAN_FILTER) += af_pan.o |
65 | 67 |
OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o |
66 | 68 |
OBJS-$(CONFIG_SILENCEDETECT_FILTER) += af_silencedetect.o |
... | ... |
@@ -75,14 +75,14 @@ static int query_formats(AVFilterContext *ctx) |
75 | 75 |
AVFilterLink *outlink = ctx->outputs[0]; |
76 | 76 |
AVFilterChannelLayouts *layouts; |
77 | 77 |
|
78 |
- ff_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO), |
|
78 |
+ ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO), |
|
79 | 79 |
&inlink->out_formats); |
80 | 80 |
if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) { |
81 | 81 |
formats = NULL; |
82 | 82 |
ff_add_format(&formats, aconvert->out_sample_fmt); |
83 | 83 |
ff_formats_ref(formats, &outlink->in_formats); |
84 | 84 |
} else |
85 |
- ff_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO), |
|
85 |
+ ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO), |
|
86 | 86 |
&outlink->in_formats); |
87 | 87 |
|
88 | 88 |
ff_channel_layouts_ref(ff_all_channel_layouts(), |
... | ... |
@@ -134,8 +134,7 @@ AVFilter avfilter_af_aformat = { |
134 | 134 |
.priv_size = sizeof(AFormatContext), |
135 | 135 |
|
136 | 136 |
.inputs = (AVFilterPad[]) {{ .name = "default", |
137 |
- .type = AVMEDIA_TYPE_AUDIO, |
|
138 |
- .filter_samples = ff_null_filter_samples }, |
|
137 |
+ .type = AVMEDIA_TYPE_AUDIO, }, |
|
139 | 138 |
{ .name = NULL}}, |
140 | 139 |
.outputs = (AVFilterPad[]) {{ .name = "default", |
141 | 140 |
.type = AVMEDIA_TYPE_AUDIO}, |
... | ... |
@@ -169,7 +169,7 @@ static int request_frame(AVFilterLink *outlink) |
169 | 169 |
|
170 | 170 |
for (i = 0; i < am->nb_inputs; i++) |
171 | 171 |
if (!am->in[i].nb_samples) |
172 |
- if ((ret = avfilter_request_frame(ctx->inputs[i])) < 0) |
|
172 |
+ if ((ret = ff_request_frame(ctx->inputs[i])) < 0) |
|
173 | 173 |
return ret; |
174 | 174 |
return 0; |
175 | 175 |
} |
... | ... |
@@ -34,8 +34,7 @@ AVFilter avfilter_af_anull = { |
34 | 34 |
|
35 | 35 |
.inputs = (const AVFilterPad[]) {{ .name = "default", |
36 | 36 |
.type = AVMEDIA_TYPE_AUDIO, |
37 |
- .get_audio_buffer = ff_null_get_audio_buffer, |
|
38 |
- .filter_samples = ff_null_filter_samples }, |
|
37 |
+ .get_audio_buffer = ff_null_get_audio_buffer, }, |
|
39 | 38 |
{ .name = NULL}}, |
40 | 39 |
|
41 | 40 |
.outputs = (const AVFilterPad[]) {{ .name = "default", |
... | ... |
@@ -112,7 +112,7 @@ static int query_formats(AVFilterContext *ctx) |
112 | 112 |
if(out_format != AV_SAMPLE_FMT_NONE) { |
113 | 113 |
out_formats = ff_make_format_list((int[]){ out_format, -1 }); |
114 | 114 |
} else |
115 |
- out_formats = avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO); |
|
115 |
+ out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO); |
|
116 | 116 |
ff_formats_ref(out_formats, &outlink->in_formats); |
117 | 117 |
|
118 | 118 |
if(out_layout) { |
... | ... |
@@ -211,7 +211,7 @@ static int request_frame(AVFilterLink *outlink) |
211 | 211 |
|
212 | 212 |
aresample->req_fullfilled = 0; |
213 | 213 |
do{ |
214 |
- ret = avfilter_request_frame(ctx->inputs[0]); |
|
214 |
+ ret = ff_request_frame(ctx->inputs[0]); |
|
215 | 215 |
}while(!aresample->req_fullfilled && ret>=0); |
216 | 216 |
|
217 | 217 |
if (ret == AVERROR_EOF) { |
... | ... |
@@ -164,7 +164,7 @@ static int request_frame(AVFilterLink *outlink) |
164 | 164 |
|
165 | 165 |
asns->req_fullfilled = 0; |
166 | 166 |
do { |
167 |
- ret = avfilter_request_frame(inlink); |
|
167 |
+ ret = ff_request_frame(inlink); |
|
168 | 168 |
} while (!asns->req_fullfilled && ret >= 0); |
169 | 169 |
|
170 | 170 |
if (ret == AVERROR_EOF) |
... | ... |
@@ -157,7 +157,7 @@ static int request_frame(AVFilterLink *outlink) |
157 | 157 |
send_next(ctx); |
158 | 158 |
} else { |
159 | 159 |
as->eof |= 1 << as->next_out; |
160 |
- avfilter_request_frame(ctx->inputs[as->next_out]); |
|
160 |
+ ff_request_frame(ctx->inputs[as->next_out]); |
|
161 | 161 |
if (as->eof & (1 << as->next_out)) |
162 | 162 |
as->next_out = !as->next_out; |
163 | 163 |
} |
... | ... |
@@ -1083,7 +1083,7 @@ static int request_frame(AVFilterLink *outlink) |
1083 | 1083 |
|
1084 | 1084 |
atempo->request_fulfilled = 0; |
1085 | 1085 |
do { |
1086 |
- ret = avfilter_request_frame(ctx->inputs[0]); |
|
1086 |
+ ret = ff_request_frame(ctx->inputs[0]); |
|
1087 | 1087 |
} |
1088 | 1088 |
while (!atempo->request_fulfilled && ret >= 0); |
1089 | 1089 |
|
1090 | 1090 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,402 @@ |
0 |
+/* |
|
1 |
+ * Copyright (c) 2012 Google, Inc. |
|
2 |
+ * |
|
3 |
+ * This file is part of FFmpeg. |
|
4 |
+ * |
|
5 |
+ * FFmpeg 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 |
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+/** |
|
21 |
+ * @file |
|
22 |
+ * audio channel mapping filter |
|
23 |
+ */ |
|
24 |
+ |
|
25 |
+#include <ctype.h> |
|
26 |
+ |
|
27 |
+#include "libavutil/audioconvert.h" |
|
28 |
+#include "libavutil/avstring.h" |
|
29 |
+#include "libavutil/mathematics.h" |
|
30 |
+#include "libavutil/opt.h" |
|
31 |
+#include "libavutil/samplefmt.h" |
|
32 |
+ |
|
33 |
+#include "audio.h" |
|
34 |
+#include "avfilter.h" |
|
35 |
+#include "formats.h" |
|
36 |
+#include "internal.h" |
|
37 |
+ |
|
38 |
+struct ChannelMap { |
|
39 |
+ uint64_t in_channel; |
|
40 |
+ uint64_t out_channel; |
|
41 |
+ int in_channel_idx; |
|
42 |
+ int out_channel_idx; |
|
43 |
+}; |
|
44 |
+ |
|
45 |
+enum MappingMode { |
|
46 |
+ MAP_NONE, |
|
47 |
+ MAP_ONE_INT, |
|
48 |
+ MAP_ONE_STR, |
|
49 |
+ MAP_PAIR_INT_INT, |
|
50 |
+ MAP_PAIR_INT_STR, |
|
51 |
+ MAP_PAIR_STR_INT, |
|
52 |
+ MAP_PAIR_STR_STR |
|
53 |
+}; |
|
54 |
+ |
|
55 |
+#define MAX_CH 64 |
|
56 |
+typedef struct ChannelMapContext { |
|
57 |
+ const AVClass *class; |
|
58 |
+ AVFilterChannelLayouts *channel_layouts; |
|
59 |
+ char *mapping_str; |
|
60 |
+ char *channel_layout_str; |
|
61 |
+ uint64_t output_layout; |
|
62 |
+ struct ChannelMap map[MAX_CH]; |
|
63 |
+ int nch; |
|
64 |
+ enum MappingMode mode; |
|
65 |
+} ChannelMapContext; |
|
66 |
+ |
|
67 |
+#define OFFSET(x) offsetof(ChannelMapContext, x) |
|
68 |
+#define A AV_OPT_FLAG_AUDIO_PARAM |
|
69 |
+static const AVOption options[] = { |
|
70 |
+ { "map", "A comma-separated list of input channel numbers in output order.", |
|
71 |
+ OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A }, |
|
72 |
+ { "channel_layout", "Output channel layout.", |
|
73 |
+ OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A }, |
|
74 |
+ { NULL }, |
|
75 |
+}; |
|
76 |
+ |
|
77 |
+static const AVClass channelmap_class = { |
|
78 |
+ .class_name = "channel map filter", |
|
79 |
+ .item_name = av_default_item_name, |
|
80 |
+ .option = options, |
|
81 |
+ .version = LIBAVUTIL_VERSION_INT, |
|
82 |
+}; |
|
83 |
+ |
|
84 |
+static char* split(char *message, char delim) { |
|
85 |
+ char *next = strchr(message, delim); |
|
86 |
+ if (next) |
|
87 |
+ *next++ = '\0'; |
|
88 |
+ return next; |
|
89 |
+} |
|
90 |
+ |
|
91 |
+static int get_channel_idx(char **map, int *ch, char delim, int max_ch) |
|
92 |
+{ |
|
93 |
+ char *next = split(*map, delim); |
|
94 |
+ int len; |
|
95 |
+ int n = 0; |
|
96 |
+ if (!next && delim == '-') |
|
97 |
+ return AVERROR(EINVAL); |
|
98 |
+ len = strlen(*map); |
|
99 |
+ sscanf(*map, "%d%n", ch, &n); |
|
100 |
+ if (n != len) |
|
101 |
+ return AVERROR(EINVAL); |
|
102 |
+ if (*ch < 0 || *ch > max_ch) |
|
103 |
+ return AVERROR(EINVAL); |
|
104 |
+ *map = next; |
|
105 |
+ return 0; |
|
106 |
+} |
|
107 |
+ |
|
108 |
+static int get_channel(char **map, uint64_t *ch, char delim) |
|
109 |
+{ |
|
110 |
+ char *next = split(*map, delim); |
|
111 |
+ if (!next && delim == '-') |
|
112 |
+ return AVERROR(EINVAL); |
|
113 |
+ *ch = av_get_channel_layout(*map); |
|
114 |
+ if (av_get_channel_layout_nb_channels(*ch) != 1) |
|
115 |
+ return AVERROR(EINVAL); |
|
116 |
+ *map = next; |
|
117 |
+ return 0; |
|
118 |
+} |
|
119 |
+ |
|
120 |
+static av_cold int channelmap_init(AVFilterContext *ctx, const char *args, |
|
121 |
+ void *opaque) |
|
122 |
+{ |
|
123 |
+ ChannelMapContext *s = ctx->priv; |
|
124 |
+ int ret; |
|
125 |
+ char *mapping; |
|
126 |
+ enum mode; |
|
127 |
+ int map_entries = 0; |
|
128 |
+ char buf[256]; |
|
129 |
+ enum MappingMode mode; |
|
130 |
+ uint64_t out_ch_mask = 0; |
|
131 |
+ int i; |
|
132 |
+ |
|
133 |
+ if (!args) { |
|
134 |
+ av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n"); |
|
135 |
+ return AVERROR(EINVAL); |
|
136 |
+ } |
|
137 |
+ |
|
138 |
+ s->class = &channelmap_class; |
|
139 |
+ av_opt_set_defaults(s); |
|
140 |
+ |
|
141 |
+ if ((ret = av_set_options_string(s, args, "=", ":")) < 0) { |
|
142 |
+ av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args); |
|
143 |
+ return ret; |
|
144 |
+ } |
|
145 |
+ |
|
146 |
+ mapping = s->mapping_str; |
|
147 |
+ |
|
148 |
+ if (!mapping) { |
|
149 |
+ mode = MAP_NONE; |
|
150 |
+ } else { |
|
151 |
+ char *dash = strchr(mapping, '-'); |
|
152 |
+ if (!dash) { // short mapping |
|
153 |
+ if (isdigit(*mapping)) |
|
154 |
+ mode = MAP_ONE_INT; |
|
155 |
+ else |
|
156 |
+ mode = MAP_ONE_STR; |
|
157 |
+ } else if (isdigit(*mapping)) { |
|
158 |
+ if (isdigit(*(dash+1))) |
|
159 |
+ mode = MAP_PAIR_INT_INT; |
|
160 |
+ else |
|
161 |
+ mode = MAP_PAIR_INT_STR; |
|
162 |
+ } else { |
|
163 |
+ if (isdigit(*(dash+1))) |
|
164 |
+ mode = MAP_PAIR_STR_INT; |
|
165 |
+ else |
|
166 |
+ mode = MAP_PAIR_STR_STR; |
|
167 |
+ } |
|
168 |
+ } |
|
169 |
+ |
|
170 |
+ if (mode != MAP_NONE) { |
|
171 |
+ char *comma = mapping; |
|
172 |
+ map_entries = 1; |
|
173 |
+ while ((comma = strchr(comma, ','))) { |
|
174 |
+ if (*++comma) // Allow trailing comma |
|
175 |
+ map_entries++; |
|
176 |
+ } |
|
177 |
+ } |
|
178 |
+ |
|
179 |
+ if (map_entries > MAX_CH) { |
|
180 |
+ av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries); |
|
181 |
+ ret = AVERROR(EINVAL); |
|
182 |
+ goto fail; |
|
183 |
+ } |
|
184 |
+ |
|
185 |
+ for (i = 0; i < map_entries; i++) { |
|
186 |
+ int in_ch_idx = -1, out_ch_idx = -1; |
|
187 |
+ uint64_t in_ch = 0, out_ch = 0; |
|
188 |
+ static const char err[] = "Failed to parse channel map\n"; |
|
189 |
+ switch (mode) { |
|
190 |
+ case MAP_ONE_INT: |
|
191 |
+ if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) { |
|
192 |
+ ret = AVERROR(EINVAL); |
|
193 |
+ av_log(ctx, AV_LOG_ERROR, err); |
|
194 |
+ goto fail; |
|
195 |
+ } |
|
196 |
+ s->map[i].in_channel_idx = in_ch_idx; |
|
197 |
+ s->map[i].out_channel_idx = i; |
|
198 |
+ break; |
|
199 |
+ case MAP_ONE_STR: |
|
200 |
+ if (!get_channel(&mapping, &in_ch, ',')) { |
|
201 |
+ av_log(ctx, AV_LOG_ERROR, err); |
|
202 |
+ ret = AVERROR(EINVAL); |
|
203 |
+ goto fail; |
|
204 |
+ } |
|
205 |
+ s->map[i].in_channel = in_ch; |
|
206 |
+ s->map[i].out_channel_idx = i; |
|
207 |
+ break; |
|
208 |
+ case MAP_PAIR_INT_INT: |
|
209 |
+ if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || |
|
210 |
+ get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) { |
|
211 |
+ av_log(ctx, AV_LOG_ERROR, err); |
|
212 |
+ ret = AVERROR(EINVAL); |
|
213 |
+ goto fail; |
|
214 |
+ } |
|
215 |
+ s->map[i].in_channel_idx = in_ch_idx; |
|
216 |
+ s->map[i].out_channel_idx = out_ch_idx; |
|
217 |
+ break; |
|
218 |
+ case MAP_PAIR_INT_STR: |
|
219 |
+ if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || |
|
220 |
+ get_channel(&mapping, &out_ch, ',') < 0 || |
|
221 |
+ out_ch & out_ch_mask) { |
|
222 |
+ av_log(ctx, AV_LOG_ERROR, err); |
|
223 |
+ ret = AVERROR(EINVAL); |
|
224 |
+ goto fail; |
|
225 |
+ } |
|
226 |
+ s->map[i].in_channel_idx = in_ch_idx; |
|
227 |
+ s->map[i].out_channel = out_ch; |
|
228 |
+ out_ch_mask |= out_ch; |
|
229 |
+ break; |
|
230 |
+ case MAP_PAIR_STR_INT: |
|
231 |
+ if (get_channel(&mapping, &in_ch, '-') < 0 || |
|
232 |
+ get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) { |
|
233 |
+ av_log(ctx, AV_LOG_ERROR, err); |
|
234 |
+ ret = AVERROR(EINVAL); |
|
235 |
+ goto fail; |
|
236 |
+ } |
|
237 |
+ s->map[i].in_channel = in_ch; |
|
238 |
+ s->map[i].out_channel_idx = out_ch_idx; |
|
239 |
+ break; |
|
240 |
+ case MAP_PAIR_STR_STR: |
|
241 |
+ if (get_channel(&mapping, &in_ch, '-') < 0 || |
|
242 |
+ get_channel(&mapping, &out_ch, ',') < 0 || |
|
243 |
+ out_ch & out_ch_mask) { |
|
244 |
+ av_log(ctx, AV_LOG_ERROR, err); |
|
245 |
+ ret = AVERROR(EINVAL); |
|
246 |
+ goto fail; |
|
247 |
+ } |
|
248 |
+ s->map[i].in_channel = in_ch; |
|
249 |
+ s->map[i].out_channel = out_ch; |
|
250 |
+ out_ch_mask |= out_ch; |
|
251 |
+ break; |
|
252 |
+ } |
|
253 |
+ } |
|
254 |
+ s->mode = mode; |
|
255 |
+ s->nch = map_entries; |
|
256 |
+ s->output_layout = out_ch_mask ? out_ch_mask : |
|
257 |
+ av_get_default_channel_layout(map_entries); |
|
258 |
+ |
|
259 |
+ if (s->channel_layout_str) { |
|
260 |
+ uint64_t fmt; |
|
261 |
+ if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) { |
|
262 |
+ av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n", |
|
263 |
+ s->channel_layout_str); |
|
264 |
+ ret = AVERROR(EINVAL); |
|
265 |
+ goto fail; |
|
266 |
+ } |
|
267 |
+ if (mode == MAP_NONE) { |
|
268 |
+ int i; |
|
269 |
+ s->nch = av_get_channel_layout_nb_channels(fmt); |
|
270 |
+ for (i = 0; i < s->nch; i++) { |
|
271 |
+ s->map[i].in_channel_idx = i; |
|
272 |
+ s->map[i].out_channel_idx = i; |
|
273 |
+ } |
|
274 |
+ } else if (out_ch_mask && out_ch_mask != fmt) { |
|
275 |
+ av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask); |
|
276 |
+ av_log(ctx, AV_LOG_ERROR, |
|
277 |
+ "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n", |
|
278 |
+ s->channel_layout_str, buf); |
|
279 |
+ ret = AVERROR(EINVAL); |
|
280 |
+ goto fail; |
|
281 |
+ } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) { |
|
282 |
+ av_log(ctx, AV_LOG_ERROR, |
|
283 |
+ "Output channel layout %s does not match the number of channels mapped %d.\n", |
|
284 |
+ s->channel_layout_str, s->nch); |
|
285 |
+ ret = AVERROR(EINVAL); |
|
286 |
+ goto fail; |
|
287 |
+ } |
|
288 |
+ s->output_layout = fmt; |
|
289 |
+ } |
|
290 |
+ ff_add_channel_layout(&s->channel_layouts, s->output_layout); |
|
291 |
+ |
|
292 |
+ if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) { |
|
293 |
+ for (i = 0; i < s->nch; i++) { |
|
294 |
+ s->map[i].out_channel_idx = av_get_channel_layout_channel_index( |
|
295 |
+ s->output_layout, s->map[i].out_channel); |
|
296 |
+ } |
|
297 |
+ } |
|
298 |
+ |
|
299 |
+fail: |
|
300 |
+ av_opt_free(s); |
|
301 |
+ return ret; |
|
302 |
+} |
|
303 |
+ |
|
304 |
+static int channelmap_query_formats(AVFilterContext *ctx) |
|
305 |
+{ |
|
306 |
+ ChannelMapContext *s = ctx->priv; |
|
307 |
+ |
|
308 |
+ ff_set_common_formats(ctx, ff_planar_sample_fmts()); |
|
309 |
+ ff_set_common_samplerates(ctx, ff_all_samplerates()); |
|
310 |
+ ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts); |
|
311 |
+ ff_channel_layouts_ref(s->channel_layouts, &ctx->outputs[0]->in_channel_layouts); |
|
312 |
+ |
|
313 |
+ return 0; |
|
314 |
+} |
|
315 |
+ |
|
316 |
+static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) |
|
317 |
+{ |
|
318 |
+ AVFilterContext *ctx = inlink->dst; |
|
319 |
+ AVFilterLink *outlink = ctx->outputs[0]; |
|
320 |
+ const ChannelMapContext *s = ctx->priv; |
|
321 |
+ const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout); |
|
322 |
+ const int nch_out = s->nch; |
|
323 |
+ int ch; |
|
324 |
+ uint8_t *source_planes[MAX_CH]; |
|
325 |
+ |
|
326 |
+ memcpy(source_planes, buf->extended_data, |
|
327 |
+ nch_in * sizeof(source_planes[0])); |
|
328 |
+ |
|
329 |
+ if (nch_out > nch_in) { |
|
330 |
+ if (nch_out > FF_ARRAY_ELEMS(buf->data)) { |
|
331 |
+ uint8_t **new_extended_data = |
|
332 |
+ av_mallocz(nch_out * sizeof(*buf->extended_data)); |
|
333 |
+ if (!new_extended_data) |
|
334 |
+ return; |
|
335 |
+ if (buf->extended_data == buf->data) { |
|
336 |
+ buf->extended_data = new_extended_data; |
|
337 |
+ } else { |
|
338 |
+ buf->extended_data = new_extended_data; |
|
339 |
+ av_free(buf->extended_data); |
|
340 |
+ } |
|
341 |
+ } else if (buf->extended_data != buf->data) { |
|
342 |
+ av_free(buf->extended_data); |
|
343 |
+ buf->extended_data = buf->data; |
|
344 |
+ } |
|
345 |
+ } |
|
346 |
+ |
|
347 |
+ for (ch = 0; ch < nch_out; ch++) { |
|
348 |
+ buf->extended_data[s->map[ch].out_channel_idx] = |
|
349 |
+ source_planes[s->map[ch].in_channel_idx]; |
|
350 |
+ } |
|
351 |
+ |
|
352 |
+ if (buf->data != buf->extended_data) |
|
353 |
+ memcpy(buf->data, buf->extended_data, |
|
354 |
+ FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0])); |
|
355 |
+ |
|
356 |
+ ff_filter_samples(outlink, buf); |
|
357 |
+} |
|
358 |
+ |
|
359 |
+static int channelmap_config_input(AVFilterLink *inlink) |
|
360 |
+{ |
|
361 |
+ AVFilterContext *ctx = inlink->dst; |
|
362 |
+ ChannelMapContext *s = ctx->priv; |
|
363 |
+ int i, err = 0; |
|
364 |
+ const char *channel_name; |
|
365 |
+ char layout_name[256]; |
|
366 |
+ |
|
367 |
+ if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) { |
|
368 |
+ for (i = 0; i < s->nch; i++) { |
|
369 |
+ s->map[i].in_channel_idx = av_get_channel_layout_channel_index( |
|
370 |
+ inlink->channel_layout, s->map[i].in_channel); |
|
371 |
+ if (s->map[i].in_channel_idx < 0) { |
|
372 |
+ channel_name = av_get_channel_name(s->map[i].in_channel); |
|
373 |
+ av_get_channel_layout_string(layout_name, sizeof(layout_name), |
|
374 |
+ 0, inlink->channel_layout); |
|
375 |
+ av_log(ctx, AV_LOG_ERROR, |
|
376 |
+ "input channel '%s' not available from input layout '%s'\n", |
|
377 |
+ channel_name, layout_name); |
|
378 |
+ err = AVERROR(EINVAL); |
|
379 |
+ } |
|
380 |
+ } |
|
381 |
+ } |
|
382 |
+ |
|
383 |
+ return err; |
|
384 |
+} |
|
385 |
+ |
|
386 |
+AVFilter avfilter_af_channelmap = { |
|
387 |
+ .name = "channelmap", |
|
388 |
+ .description = NULL_IF_CONFIG_SMALL("Remap audio channels."), |
|
389 |
+ .init = channelmap_init, |
|
390 |
+ .query_formats = channelmap_query_formats, |
|
391 |
+ .priv_size = sizeof(ChannelMapContext), |
|
392 |
+ |
|
393 |
+ .inputs = (AVFilterPad[]) {{ .name = "default", |
|
394 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
395 |
+ .filter_samples = channelmap_filter_samples, |
|
396 |
+ .config_props = channelmap_config_input }, |
|
397 |
+ { .name = NULL }}, |
|
398 |
+ .outputs = (AVFilterPad[]) {{ .name = "default", |
|
399 |
+ .type = AVMEDIA_TYPE_AUDIO }, |
|
400 |
+ { .name = NULL }}, |
|
401 |
+}; |
0 | 402 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,500 @@ |
0 |
+/* |
|
1 |
+ * |
|
2 |
+ * This file is part of Libav. |
|
3 |
+ * |
|
4 |
+ * Libav is free software; you can redistribute it and/or |
|
5 |
+ * modify it under the terms of the GNU Lesser General Public |
|
6 |
+ * License as published by the Free Software Foundation; either |
|
7 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
8 |
+ * |
|
9 |
+ * Libav is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 |
+ * Lesser General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU Lesser General Public |
|
15 |
+ * License along with Libav; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
17 |
+ */ |
|
18 |
+ |
|
19 |
+/** |
|
20 |
+ * @file |
|
21 |
+ * Audio join filter |
|
22 |
+ * |
|
23 |
+ * Join multiple audio inputs as different channels in |
|
24 |
+ * a single output |
|
25 |
+ */ |
|
26 |
+ |
|
27 |
+#include "libavutil/audioconvert.h" |
|
28 |
+#include "libavutil/avassert.h" |
|
29 |
+#include "libavutil/opt.h" |
|
30 |
+ |
|
31 |
+#include "audio.h" |
|
32 |
+#include "avfilter.h" |
|
33 |
+#include "formats.h" |
|
34 |
+#include "internal.h" |
|
35 |
+ |
|
36 |
+typedef struct ChannelMap { |
|
37 |
+ int input; ///< input stream index |
|
38 |
+ int in_channel_idx; ///< index of in_channel in the input stream data |
|
39 |
+ uint64_t in_channel; ///< layout describing the input channel |
|
40 |
+ uint64_t out_channel; ///< layout describing the output channel |
|
41 |
+} ChannelMap; |
|
42 |
+ |
|
43 |
+typedef struct JoinContext { |
|
44 |
+ const AVClass *class; |
|
45 |
+ |
|
46 |
+ int inputs; |
|
47 |
+ char *map; |
|
48 |
+ char *channel_layout_str; |
|
49 |
+ uint64_t channel_layout; |
|
50 |
+ |
|
51 |
+ int nb_channels; |
|
52 |
+ ChannelMap *channels; |
|
53 |
+ |
|
54 |
+ /** |
|
55 |
+ * Temporary storage for input frames, until we get one on each input. |
|
56 |
+ */ |
|
57 |
+ AVFilterBufferRef **input_frames; |
|
58 |
+ |
|
59 |
+ /** |
|
60 |
+ * Temporary storage for data pointers, for assembling the output buffer. |
|
61 |
+ */ |
|
62 |
+ uint8_t **data; |
|
63 |
+} JoinContext; |
|
64 |
+ |
|
65 |
+/** |
|
66 |
+ * To avoid copying the data from input buffers, this filter creates |
|
67 |
+ * a custom output buffer that stores references to all inputs and |
|
68 |
+ * unrefs them on free. |
|
69 |
+ */ |
|
70 |
+typedef struct JoinBufferPriv { |
|
71 |
+ AVFilterBufferRef **in_buffers; |
|
72 |
+ int nb_in_buffers; |
|
73 |
+} JoinBufferPriv; |
|
74 |
+ |
|
75 |
+#define OFFSET(x) offsetof(JoinContext, x) |
|
76 |
+#define A AV_OPT_FLAG_AUDIO_PARAM |
|
77 |
+static const AVOption join_options[] = { |
|
78 |
+ { "inputs", "Number of input streams.", OFFSET(inputs), AV_OPT_TYPE_INT, { 2 }, 1, INT_MAX, A }, |
|
79 |
+ { "channel_layout", "Channel layout of the " |
|
80 |
+ "output stream.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, A }, |
|
81 |
+ { "map", "A comma-separated list of channels maps in the format " |
|
82 |
+ "'input_stream.input_channel-output_channel.", |
|
83 |
+ OFFSET(map), AV_OPT_TYPE_STRING, .flags = A }, |
|
84 |
+ { NULL }, |
|
85 |
+}; |
|
86 |
+ |
|
87 |
+static const AVClass join_class = { |
|
88 |
+ .class_name = "join filter", |
|
89 |
+ .item_name = av_default_item_name, |
|
90 |
+ .option = join_options, |
|
91 |
+ .version = LIBAVUTIL_VERSION_INT, |
|
92 |
+}; |
|
93 |
+ |
|
94 |
+static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) |
|
95 |
+{ |
|
96 |
+ AVFilterContext *ctx = link->dst; |
|
97 |
+ JoinContext *s = ctx->priv; |
|
98 |
+ int i; |
|
99 |
+ |
|
100 |
+ for (i = 0; i < ctx->nb_inputs; i++) |
|
101 |
+ if (link == ctx->inputs[i]) |
|
102 |
+ break; |
|
103 |
+ av_assert0(i < ctx->nb_inputs); |
|
104 |
+ av_assert0(!s->input_frames[i]); |
|
105 |
+ s->input_frames[i] = buf; |
|
106 |
+} |
|
107 |
+ |
|
108 |
+static int parse_maps(AVFilterContext *ctx) |
|
109 |
+{ |
|
110 |
+ JoinContext *s = ctx->priv; |
|
111 |
+ char *cur = s->map; |
|
112 |
+ |
|
113 |
+ while (cur && *cur) { |
|
114 |
+ char *sep, *next, *p; |
|
115 |
+ uint64_t in_channel = 0, out_channel = 0; |
|
116 |
+ int input_idx, out_ch_idx, in_ch_idx; |
|
117 |
+ |
|
118 |
+ next = strchr(cur, ','); |
|
119 |
+ if (next) |
|
120 |
+ *next++ = 0; |
|
121 |
+ |
|
122 |
+ /* split the map into input and output parts */ |
|
123 |
+ if (!(sep = strchr(cur, '-'))) { |
|
124 |
+ av_log(ctx, AV_LOG_ERROR, "Missing separator '-' in channel " |
|
125 |
+ "map '%s'\n", cur); |
|
126 |
+ return AVERROR(EINVAL); |
|
127 |
+ } |
|
128 |
+ *sep++ = 0; |
|
129 |
+ |
|
130 |
+#define PARSE_CHANNEL(str, var, inout) \ |
|
131 |
+ if (!(var = av_get_channel_layout(str))) { \ |
|
132 |
+ av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\ |
|
133 |
+ return AVERROR(EINVAL); \ |
|
134 |
+ } \ |
|
135 |
+ if (av_get_channel_layout_nb_channels(var) != 1) { \ |
|
136 |
+ av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one " \ |
|
137 |
+ inout " channel.\n"); \ |
|
138 |
+ return AVERROR(EINVAL); \ |
|
139 |
+ } |
|
140 |
+ |
|
141 |
+ /* parse output channel */ |
|
142 |
+ PARSE_CHANNEL(sep, out_channel, "output"); |
|
143 |
+ if (!(out_channel & s->channel_layout)) { |
|
144 |
+ av_log(ctx, AV_LOG_ERROR, "Output channel '%s' is not present in " |
|
145 |
+ "requested channel layout.\n", sep); |
|
146 |
+ return AVERROR(EINVAL); |
|
147 |
+ } |
|
148 |
+ |
|
149 |
+ out_ch_idx = av_get_channel_layout_channel_index(s->channel_layout, |
|
150 |
+ out_channel); |
|
151 |
+ if (s->channels[out_ch_idx].input >= 0) { |
|
152 |
+ av_log(ctx, AV_LOG_ERROR, "Multiple maps for output channel " |
|
153 |
+ "'%s'.\n", sep); |
|
154 |
+ return AVERROR(EINVAL); |
|
155 |
+ } |
|
156 |
+ |
|
157 |
+ /* parse input channel */ |
|
158 |
+ input_idx = strtol(cur, &cur, 0); |
|
159 |
+ if (input_idx < 0 || input_idx >= s->inputs) { |
|
160 |
+ av_log(ctx, AV_LOG_ERROR, "Invalid input stream index: %d.\n", |
|
161 |
+ input_idx); |
|
162 |
+ return AVERROR(EINVAL); |
|
163 |
+ } |
|
164 |
+ |
|
165 |
+ if (*cur) |
|
166 |
+ cur++; |
|
167 |
+ |
|
168 |
+ in_ch_idx = strtol(cur, &p, 0); |
|
169 |
+ if (p == cur) { |
|
170 |
+ /* channel specifier is not a number, |
|
171 |
+ * try to parse as channel name */ |
|
172 |
+ PARSE_CHANNEL(cur, in_channel, "input"); |
|
173 |
+ } |
|
174 |
+ |
|
175 |
+ s->channels[out_ch_idx].input = input_idx; |
|
176 |
+ if (in_channel) |
|
177 |
+ s->channels[out_ch_idx].in_channel = in_channel; |
|
178 |
+ else |
|
179 |
+ s->channels[out_ch_idx].in_channel_idx = in_ch_idx; |
|
180 |
+ |
|
181 |
+ cur = next; |
|
182 |
+ } |
|
183 |
+ return 0; |
|
184 |
+} |
|
185 |
+ |
|
186 |
+static int join_init(AVFilterContext *ctx, const char *args, void *opaque) |
|
187 |
+{ |
|
188 |
+ JoinContext *s = ctx->priv; |
|
189 |
+ int ret, i; |
|
190 |
+ |
|
191 |
+ s->class = &join_class; |
|
192 |
+ av_opt_set_defaults(s); |
|
193 |
+ if ((ret = av_set_options_string(s, args, "=", ":")) < 0) { |
|
194 |
+ av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args); |
|
195 |
+ return ret; |
|
196 |
+ } |
|
197 |
+ |
|
198 |
+ if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) { |
|
199 |
+ av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n", |
|
200 |
+ s->channel_layout_str); |
|
201 |
+ ret = AVERROR(EINVAL); |
|
202 |
+ goto fail; |
|
203 |
+ } |
|
204 |
+ |
|
205 |
+ s->nb_channels = av_get_channel_layout_nb_channels(s->channel_layout); |
|
206 |
+ s->channels = av_mallocz(sizeof(*s->channels) * s->nb_channels); |
|
207 |
+ s->data = av_mallocz(sizeof(*s->data) * s->nb_channels); |
|
208 |
+ s->input_frames = av_mallocz(sizeof(*s->input_frames) * s->inputs); |
|
209 |
+ if (!s->channels || !s->data || !s->input_frames) { |
|
210 |
+ ret = AVERROR(ENOMEM); |
|
211 |
+ goto fail; |
|
212 |
+ } |
|
213 |
+ |
|
214 |
+ for (i = 0; i < s->nb_channels; i++) { |
|
215 |
+ s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i); |
|
216 |
+ s->channels[i].input = -1; |
|
217 |
+ } |
|
218 |
+ |
|
219 |
+ if ((ret = parse_maps(ctx)) < 0) |
|
220 |
+ goto fail; |
|
221 |
+ |
|
222 |
+ for (i = 0; i < s->inputs; i++) { |
|
223 |
+ char name[32]; |
|
224 |
+ AVFilterPad pad = { 0 }; |
|
225 |
+ |
|
226 |
+ snprintf(name, sizeof(name), "input%d", i); |
|
227 |
+ pad.type = AVMEDIA_TYPE_AUDIO; |
|
228 |
+ pad.name = av_strdup(name); |
|
229 |
+ pad.filter_samples = filter_samples; |
|
230 |
+ |
|
231 |
+ pad.needs_fifo = 1; |
|
232 |
+ |
|
233 |
+ ff_insert_inpad(ctx, i, &pad); |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+fail: |
|
237 |
+ av_opt_free(s); |
|
238 |
+ return ret; |
|
239 |
+} |
|
240 |
+ |
|
241 |
+static void join_uninit(AVFilterContext *ctx) |
|
242 |
+{ |
|
243 |
+ JoinContext *s = ctx->priv; |
|
244 |
+ int i; |
|
245 |
+ |
|
246 |
+ for (i = 0; i < ctx->nb_inputs; i++) { |
|
247 |
+ av_freep(&ctx->input_pads[i].name); |
|
248 |
+ avfilter_unref_buffer(s->input_frames[i]); |
|
249 |
+ } |
|
250 |
+ |
|
251 |
+ av_freep(&s->channels); |
|
252 |
+ av_freep(&s->data); |
|
253 |
+ av_freep(&s->input_frames); |
|
254 |
+} |
|
255 |
+ |
|
256 |
+static int join_query_formats(AVFilterContext *ctx) |
|
257 |
+{ |
|
258 |
+ JoinContext *s = ctx->priv; |
|
259 |
+ AVFilterChannelLayouts *layouts = NULL; |
|
260 |
+ int i; |
|
261 |
+ |
|
262 |
+ ff_add_channel_layout(&layouts, s->channel_layout); |
|
263 |
+ ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts); |
|
264 |
+ |
|
265 |
+ for (i = 0; i < ctx->nb_inputs; i++) |
|
266 |
+ ff_channel_layouts_ref(ff_all_channel_layouts(), |
|
267 |
+ &ctx->inputs[i]->out_channel_layouts); |
|
268 |
+ |
|
269 |
+ ff_set_common_formats (ctx, ff_planar_sample_fmts()); |
|
270 |
+ ff_set_common_samplerates(ctx, ff_all_samplerates()); |
|
271 |
+ |
|
272 |
+ return 0; |
|
273 |
+} |
|
274 |
+ |
|
275 |
+static void guess_map_matching(AVFilterContext *ctx, ChannelMap *ch, |
|
276 |
+ uint64_t *inputs) |
|
277 |
+{ |
|
278 |
+ int i; |
|
279 |
+ |
|
280 |
+ for (i = 0; i < ctx->nb_inputs; i++) { |
|
281 |
+ AVFilterLink *link = ctx->inputs[i]; |
|
282 |
+ |
|
283 |
+ if (ch->out_channel & link->channel_layout && |
|
284 |
+ !(ch->out_channel & inputs[i])) { |
|
285 |
+ ch->input = i; |
|
286 |
+ ch->in_channel = ch->out_channel; |
|
287 |
+ inputs[i] |= ch->out_channel; |
|
288 |
+ return; |
|
289 |
+ } |
|
290 |
+ } |
|
291 |
+} |
|
292 |
+ |
|
293 |
+static void guess_map_any(AVFilterContext *ctx, ChannelMap *ch, |
|
294 |
+ uint64_t *inputs) |
|
295 |
+{ |
|
296 |
+ int i; |
|
297 |
+ |
|
298 |
+ for (i = 0; i < ctx->nb_inputs; i++) { |
|
299 |
+ AVFilterLink *link = ctx->inputs[i]; |
|
300 |
+ |
|
301 |
+ if ((inputs[i] & link->channel_layout) != link->channel_layout) { |
|
302 |
+ uint64_t unused = link->channel_layout & ~inputs[i]; |
|
303 |
+ |
|
304 |
+ ch->input = i; |
|
305 |
+ ch->in_channel = av_channel_layout_extract_channel(unused, 0); |
|
306 |
+ inputs[i] |= ch->in_channel; |
|
307 |
+ return; |
|
308 |
+ } |
|
309 |
+ } |
|
310 |
+} |
|
311 |
+ |
|
312 |
+static int join_config_output(AVFilterLink *outlink) |
|
313 |
+{ |
|
314 |
+ AVFilterContext *ctx = outlink->src; |
|
315 |
+ JoinContext *s = ctx->priv; |
|
316 |
+ uint64_t *inputs; // nth element tracks which channels are used from nth input |
|
317 |
+ int i, ret = 0; |
|
318 |
+ |
|
319 |
+ /* initialize inputs to user-specified mappings */ |
|
320 |
+ if (!(inputs = av_mallocz(sizeof(*inputs) * ctx->nb_inputs))) |
|
321 |
+ return AVERROR(ENOMEM); |
|
322 |
+ for (i = 0; i < s->nb_channels; i++) { |
|
323 |
+ ChannelMap *ch = &s->channels[i]; |
|
324 |
+ AVFilterLink *inlink; |
|
325 |
+ |
|
326 |
+ if (ch->input < 0) |
|
327 |
+ continue; |
|
328 |
+ |
|
329 |
+ inlink = ctx->inputs[ch->input]; |
|
330 |
+ |
|
331 |
+ if (!ch->in_channel) |
|
332 |
+ ch->in_channel = av_channel_layout_extract_channel(inlink->channel_layout, |
|
333 |
+ ch->in_channel_idx); |
|
334 |
+ |
|
335 |
+ if (!(ch->in_channel & inlink->channel_layout)) { |
|
336 |
+ av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in " |
|
337 |
+ "input stream #%d.\n", av_get_channel_name(ch->in_channel), |
|
338 |
+ ch->input); |
|
339 |
+ ret = AVERROR(EINVAL); |
|
340 |
+ goto fail; |
|
341 |
+ } |
|
342 |
+ |
|
343 |
+ inputs[ch->input] |= ch->in_channel; |
|
344 |
+ } |
|
345 |
+ |
|
346 |
+ /* guess channel maps when not explicitly defined */ |
|
347 |
+ /* first try unused matching channels */ |
|
348 |
+ for (i = 0; i < s->nb_channels; i++) { |
|
349 |
+ ChannelMap *ch = &s->channels[i]; |
|
350 |
+ |
|
351 |
+ if (ch->input < 0) |
|
352 |
+ guess_map_matching(ctx, ch, inputs); |
|
353 |
+ } |
|
354 |
+ |
|
355 |
+ /* if the above failed, try to find _any_ unused input channel */ |
|
356 |
+ for (i = 0; i < s->nb_channels; i++) { |
|
357 |
+ ChannelMap *ch = &s->channels[i]; |
|
358 |
+ |
|
359 |
+ if (ch->input < 0) |
|
360 |
+ guess_map_any(ctx, ch, inputs); |
|
361 |
+ |
|
362 |
+ if (ch->input < 0) { |
|
363 |
+ av_log(ctx, AV_LOG_ERROR, "Could not find input channel for " |
|
364 |
+ "output channel '%s'.\n", |
|
365 |
+ av_get_channel_name(ch->out_channel)); |
|
366 |
+ goto fail; |
|
367 |
+ } |
|
368 |
+ |
|
369 |
+ ch->in_channel_idx = av_get_channel_layout_channel_index(ctx->inputs[ch->input]->channel_layout, |
|
370 |
+ ch->in_channel); |
|
371 |
+ } |
|
372 |
+ |
|
373 |
+ /* print mappings */ |
|
374 |
+ av_log(ctx, AV_LOG_VERBOSE, "mappings: "); |
|
375 |
+ for (i = 0; i < s->nb_channels; i++) { |
|
376 |
+ ChannelMap *ch = &s->channels[i]; |
|
377 |
+ av_log(ctx, AV_LOG_VERBOSE, "%d.%s => %s ", ch->input, |
|
378 |
+ av_get_channel_name(ch->in_channel), |
|
379 |
+ av_get_channel_name(ch->out_channel)); |
|
380 |
+ } |
|
381 |
+ av_log(ctx, AV_LOG_VERBOSE, "\n"); |
|
382 |
+ |
|
383 |
+ for (i = 0; i < ctx->nb_inputs; i++) { |
|
384 |
+ if (!inputs[i]) |
|
385 |
+ av_log(ctx, AV_LOG_WARNING, "No channels are used from input " |
|
386 |
+ "stream %d.\n", i); |
|
387 |
+ } |
|
388 |
+ |
|
389 |
+fail: |
|
390 |
+ av_freep(&inputs); |
|
391 |
+ return ret; |
|
392 |
+} |
|
393 |
+ |
|
394 |
+static void join_free_buffer(AVFilterBuffer *buf) |
|
395 |
+{ |
|
396 |
+ JoinBufferPriv *priv = buf->priv; |
|
397 |
+ |
|
398 |
+ if (priv) { |
|
399 |
+ int i; |
|
400 |
+ |
|
401 |
+ for (i = 0; i < priv->nb_in_buffers; i++) |
|
402 |
+ avfilter_unref_buffer(priv->in_buffers[i]); |
|
403 |
+ |
|
404 |
+ av_freep(&priv->in_buffers); |
|
405 |
+ av_freep(&buf->priv); |
|
406 |
+ } |
|
407 |
+ |
|
408 |
+ if (buf->extended_data != buf->data) |
|
409 |
+ av_freep(&buf->extended_data); |
|
410 |
+ av_freep(&buf); |
|
411 |
+} |
|
412 |
+ |
|
413 |
+static int join_request_frame(AVFilterLink *outlink) |
|
414 |
+{ |
|
415 |
+ AVFilterContext *ctx = outlink->src; |
|
416 |
+ JoinContext *s = ctx->priv; |
|
417 |
+ AVFilterBufferRef *buf; |
|
418 |
+ JoinBufferPriv *priv; |
|
419 |
+ int linesize = INT_MAX; |
|
420 |
+ int perms = ~0; |
|
421 |
+ int nb_samples; |
|
422 |
+ int i, j, ret; |
|
423 |
+ |
|
424 |
+ /* get a frame on each input */ |
|
425 |
+ for (i = 0; i < ctx->nb_inputs; i++) { |
|
426 |
+ AVFilterLink *inlink = ctx->inputs[i]; |
|
427 |
+ |
|
428 |
+ if (!s->input_frames[i] && |
|
429 |
+ (ret = ff_request_frame(inlink)) < 0) |
|
430 |
+ return ret; |
|
431 |
+ |
|
432 |
+ /* request the same number of samples on all inputs */ |
|
433 |
+ if (i == 0) { |
|
434 |
+ nb_samples = s->input_frames[0]->audio->nb_samples; |
|
435 |
+ |
|
436 |
+ for (j = 1; !i && j < ctx->nb_inputs; j++) |
|
437 |
+ ctx->inputs[j]->request_samples = nb_samples; |
|
438 |
+ } |
|
439 |
+ } |
|
440 |
+ |
|
441 |
+ for (i = 0; i < s->nb_channels; i++) { |
|
442 |
+ ChannelMap *ch = &s->channels[i]; |
|
443 |
+ AVFilterBufferRef *cur_buf = s->input_frames[ch->input]; |
|
444 |
+ |
|
445 |
+ s->data[i] = cur_buf->extended_data[ch->in_channel_idx]; |
|
446 |
+ linesize = FFMIN(linesize, cur_buf->linesize[0]); |
|
447 |
+ perms &= cur_buf->perms; |
|
448 |
+ } |
|
449 |
+ |
|
450 |
+ buf = avfilter_get_audio_buffer_ref_from_arrays(s->data, linesize, perms, |
|
451 |
+ nb_samples, outlink->format, |
|
452 |
+ outlink->channel_layout); |
|
453 |
+ if (!buf) |
|
454 |
+ return AVERROR(ENOMEM); |
|
455 |
+ |
|
456 |
+ buf->buf->free = join_free_buffer; |
|
457 |
+ buf->pts = s->input_frames[0]->pts; |
|
458 |
+ |
|
459 |
+ if (!(priv = av_mallocz(sizeof(*priv)))) |
|
460 |
+ goto fail; |
|
461 |
+ if (!(priv->in_buffers = av_mallocz(sizeof(*priv->in_buffers) * ctx->nb_inputs))) |
|
462 |
+ goto fail; |
|
463 |
+ |
|
464 |
+ for (i = 0; i < ctx->nb_inputs; i++) |
|
465 |
+ priv->in_buffers[i] = s->input_frames[i]; |
|
466 |
+ priv->nb_in_buffers = ctx->nb_inputs; |
|
467 |
+ buf->buf->priv = priv; |
|
468 |
+ |
|
469 |
+ ff_filter_samples(outlink, buf); |
|
470 |
+ |
|
471 |
+ memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs); |
|
472 |
+ |
|
473 |
+ return 0; |
|
474 |
+ |
|
475 |
+fail: |
|
476 |
+ avfilter_unref_buffer(buf); |
|
477 |
+ if (priv) |
|
478 |
+ av_freep(&priv->in_buffers); |
|
479 |
+ av_freep(&priv); |
|
480 |
+ return AVERROR(ENOMEM); |
|
481 |
+} |
|
482 |
+ |
|
483 |
+AVFilter avfilter_af_join = { |
|
484 |
+ .name = "join", |
|
485 |
+ .description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into " |
|
486 |
+ "multi-channel output"), |
|
487 |
+ .priv_size = sizeof(JoinContext), |
|
488 |
+ |
|
489 |
+ .init = join_init, |
|
490 |
+ .uninit = join_uninit, |
|
491 |
+ .query_formats = join_query_formats, |
|
492 |
+ |
|
493 |
+ .inputs = (const AVFilterPad[]){{ NULL }}, |
|
494 |
+ .outputs = (const AVFilterPad[]){{ .name = "default", |
|
495 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
496 |
+ .config_props = join_config_output, |
|
497 |
+ .request_frame = join_request_frame, }, |
|
498 |
+ { NULL }}, |
|
499 |
+}; |
... | ... |
@@ -217,7 +217,7 @@ static int query_formats(AVFilterContext *ctx) |
217 | 217 |
|
218 | 218 |
pan->pure_gains = are_gains_pure(pan); |
219 | 219 |
/* libswr supports any sample and packing formats */ |
220 |
- ff_set_common_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO)); |
|
220 |
+ ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO)); |
|
221 | 221 |
|
222 | 222 |
formats = ff_all_samplerates(); |
223 | 223 |
if (!formats) |
... | ... |
@@ -47,8 +47,10 @@ void avfilter_register_all(void) |
47 | 47 |
REGISTER_FILTER (ASTREAMSYNC, astreamsync, af); |
48 | 48 |
REGISTER_FILTER (ASYNCTS, asyncts, af); |
49 | 49 |
REGISTER_FILTER (ATEMPO, atempo, af); |
50 |
+ REGISTER_FILTER (CHANNELMAP, channelmap, af); |
|
50 | 51 |
REGISTER_FILTER (CHANNELSPLIT,channelsplit,af); |
51 | 52 |
REGISTER_FILTER (EARWAX, earwax, af); |
53 |
+ REGISTER_FILTER (JOIN, join, af); |
|
52 | 54 |
REGISTER_FILTER (PAN, pan, af); |
53 | 55 |
REGISTER_FILTER (SILENCEDETECT, silencedetect, af); |
54 | 56 |
REGISTER_FILTER (VOLUME, volume, af); |
... | ... |
@@ -150,32 +150,12 @@ fail: |
150 | 150 |
return NULL; |
151 | 151 |
} |
152 | 152 |
|
153 |
-void ff_null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) |
|
153 |
+static void default_filter_samples(AVFilterLink *link, |
|
154 |
+ AVFilterBufferRef *samplesref) |
|
154 | 155 |
{ |
155 | 156 |
ff_filter_samples(link->dst->outputs[0], samplesref); |
156 | 157 |
} |
157 | 158 |
|
158 |
-/* FIXME: samplesref is same as link->cur_buf. Need to consider removing the redundant parameter. */ |
|
159 |
-void ff_default_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) |
|
160 |
-{ |
|
161 |
- AVFilterLink *outlink = NULL; |
|
162 |
- |
|
163 |
- if (inlink->dst->nb_outputs) |
|
164 |
- outlink = inlink->dst->outputs[0]; |
|
165 |
- |
|
166 |
- if (outlink) { |
|
167 |
- outlink->out_buf = ff_default_get_audio_buffer(inlink, AV_PERM_WRITE, |
|
168 |
- samplesref->audio->nb_samples); |
|
169 |
- outlink->out_buf->pts = samplesref->pts; |
|
170 |
- outlink->out_buf->audio->sample_rate = samplesref->audio->sample_rate; |
|
171 |
- ff_filter_samples(outlink, avfilter_ref_buffer(outlink->out_buf, ~0)); |
|
172 |
- avfilter_unref_buffer(outlink->out_buf); |
|
173 |
- outlink->out_buf = NULL; |
|
174 |
- } |
|
175 |
- avfilter_unref_buffer(samplesref); |
|
176 |
- inlink->cur_buf = NULL; |
|
177 |
-} |
|
178 |
- |
|
179 | 159 |
void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) |
180 | 160 |
{ |
181 | 161 |
void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *); |
... | ... |
@@ -186,7 +166,7 @@ void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) |
186 | 186 |
FF_TPRINTF_START(NULL, filter_samples); ff_tlog_link(NULL, link, 1); |
187 | 187 |
|
188 | 188 |
if (!(filter_samples = dst->filter_samples)) |
189 |
- filter_samples = ff_default_filter_samples; |
|
189 |
+ filter_samples = default_filter_samples; |
|
190 | 190 |
|
191 | 191 |
/* prepare to copy the samples if the buffer has insufficient permissions */ |
192 | 192 |
if ((dst->min_perms & samplesref->perms) != dst->min_perms || |
... | ... |
@@ -63,12 +63,6 @@ AVFilterBufferRef *ff_null_get_audio_buffer(AVFilterLink *link, int perms, |
63 | 63 |
AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms, |
64 | 64 |
int nb_samples); |
65 | 65 |
|
66 |
-/** default handler for filter_samples() for audio inputs */ |
|
67 |
-void ff_default_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref); |
|
68 |
- |
|
69 |
-/** filter_samples() handler for filters which simply pass audio along */ |
|
70 |
-void ff_null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref); |
|
71 |
- |
|
72 | 66 |
/** |
73 | 67 |
* Send a buffer of audio samples to the next filter. |
74 | 68 |
* |
... | ... |
@@ -170,7 +170,7 @@ static int request_frame(AVFilterLink *outlink) |
170 | 170 |
|
171 | 171 |
showwaves->req_fullfilled = 0; |
172 | 172 |
do { |
173 |
- ret = avfilter_request_frame(inlink); |
|
173 |
+ ret = ff_request_frame(inlink); |
|
174 | 174 |
} while (!showwaves->req_fullfilled && ret >= 0); |
175 | 175 |
|
176 | 176 |
if (ret == AVERROR_EOF && showwaves->outpicref) |
... | ... |
@@ -211,7 +211,6 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask); |
211 | 211 |
*/ |
212 | 212 |
void avfilter_unref_buffer(AVFilterBufferRef *ref); |
213 | 213 |
|
214 |
-#if FF_API_FILTERS_PUBLIC |
|
215 | 214 |
/** |
216 | 215 |
* Remove a reference to a buffer and set the pointer to NULL. |
217 | 216 |
* If this is the last reference to the buffer, the buffer itself |
... | ... |
@@ -221,6 +220,7 @@ void avfilter_unref_buffer(AVFilterBufferRef *ref); |
221 | 221 |
*/ |
222 | 222 |
void avfilter_unref_bufferp(AVFilterBufferRef **ref); |
223 | 223 |
|
224 |
+#if FF_API_FILTERS_PUBLIC |
|
224 | 225 |
/** |
225 | 226 |
* A list of supported formats for one end of a filter link. This is used |
226 | 227 |
* 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); |
291 | 291 |
* |
292 | 292 |
* @return a non negative value in case of success, or a negative |
293 | 293 |
* value corresponding to an AVERROR code in case of error |
294 |
- * @deprecated Use avfilter_make_all_formats() instead. |
|
294 |
+ * @deprecated Use ff_all_formats() instead. |
|
295 | 295 |
*/ |
296 | 296 |
attribute_deprecated |
297 | 297 |
int avfilter_add_format(AVFilterFormats **avff, int64_t fmt); |
... | ... |
@@ -479,7 +479,7 @@ struct AVFilterPad { |
479 | 479 |
* Frame request callback. A call to this should result in at least one |
480 | 480 |
* frame being output over the given link. This should return zero on |
481 | 481 |
* success, and another value on error. |
482 |
- * See avfilter_request_frame() for the error codes with a specific |
|
482 |
+ * See ff_request_frame() for the error codes with a specific |
|
483 | 483 |
* meaning. |
484 | 484 |
* |
485 | 485 |
* Output pads only. |
... | ... |
@@ -504,6 +504,14 @@ struct AVFilterPad { |
504 | 504 |
* and another value on error. |
505 | 505 |
*/ |
506 | 506 |
int (*config_props)(AVFilterLink *link); |
507 |
+ |
|
508 |
+ /** |
|
509 |
+ * The filter expects a fifo to be inserted on its input link, |
|
510 |
+ * typically because it has a delay. |
|
511 |
+ * |
|
512 |
+ * input pads only. |
|
513 |
+ */ |
|
514 |
+ int needs_fifo; |
|
507 | 515 |
}; |
508 | 516 |
#endif |
509 | 517 |
|
... | ... |
@@ -529,6 +537,10 @@ const char *avfilter_pad_get_name(AVFilterPad *pads, int pad_idx); |
529 | 529 |
*/ |
530 | 530 |
enum AVMediaType avfilter_pad_get_type(AVFilterPad *pads, int pad_idx); |
531 | 531 |
|
532 |
+/** default handler for end_frame() for video inputs */ |
|
533 |
+attribute_deprecated |
|
534 |
+void avfilter_default_end_frame(AVFilterLink *link); |
|
535 |
+ |
|
532 | 536 |
#if FF_API_FILTERS_PUBLIC |
533 | 537 |
/** default handler for start_frame() for video inputs */ |
534 | 538 |
attribute_deprecated |
... | ... |
@@ -538,10 +550,6 @@ void avfilter_default_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) |
538 | 538 |
attribute_deprecated |
539 | 539 |
void avfilter_default_draw_slice(AVFilterLink *link, int y, int h, int slice_dir); |
540 | 540 |
|
541 |
-/** default handler for end_frame() for video inputs */ |
|
542 |
-attribute_deprecated |
|
543 |
-void avfilter_default_end_frame(AVFilterLink *link); |
|
544 |
- |
|
545 | 541 |
/** default handler for get_video_buffer() for video inputs */ |
546 | 542 |
attribute_deprecated |
547 | 543 |
AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, |
... | ... |
@@ -756,6 +764,15 @@ struct AVFilterLink { |
756 | 756 |
struct AVFilterChannelLayouts *in_channel_layouts; |
757 | 757 |
struct AVFilterChannelLayouts *out_channel_layouts; |
758 | 758 |
|
759 |
+ /** |
|
760 |
+ * Audio only, the destination filter sets this to a non-zero value to |
|
761 |
+ * request that buffers with the given number of samples should be sent to |
|
762 |
+ * it. AVFilterPad.needs_fifo must also be set on the corresponding input |
|
763 |
+ * pad. |
|
764 |
+ * Last buffer before EOF will be padded with silence. |
|
765 |
+ */ |
|
766 |
+ int request_samples; |
|
767 |
+ |
|
759 | 768 |
struct AVFilterPool *pool; |
760 | 769 |
|
761 | 770 |
/** |
... | ... |
@@ -785,7 +802,6 @@ struct AVFilterLink { |
785 | 785 |
* It is similar to the r_frae_rate field in AVStream. |
786 | 786 |
*/ |
787 | 787 |
AVRational frame_rate; |
788 |
- |
|
789 | 788 |
}; |
790 | 789 |
|
791 | 790 |
/** |
... | ... |
@@ -187,7 +187,7 @@ static int filter_query_formats(AVFilterContext *ctx) |
187 | 187 |
if ((ret = ctx->filter->query_formats(ctx)) < 0) |
188 | 188 |
return ret; |
189 | 189 |
|
190 |
- formats = avfilter_make_all_formats(type); |
|
190 |
+ formats = ff_all_formats(type); |
|
191 | 191 |
if (!formats) |
192 | 192 |
return AVERROR(ENOMEM); |
193 | 193 |
ff_set_common_formats(ctx, formats); |
... | ... |
@@ -815,12 +815,52 @@ static int ff_avfilter_graph_config_pointers(AVFilterGraph *graph, |
815 | 815 |
return 0; |
816 | 816 |
} |
817 | 817 |
|
818 |
+static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx) |
|
819 |
+{ |
|
820 |
+ AVFilterContext *f; |
|
821 |
+ int i, j, ret; |
|
822 |
+ int fifo_count = 0; |
|
823 |
+ |
|
824 |
+ for (i = 0; i < graph->filter_count; i++) { |
|
825 |
+ f = graph->filters[i]; |
|
826 |
+ |
|
827 |
+ for (j = 0; j < f->nb_inputs; j++) { |
|
828 |
+ AVFilterLink *link = f->inputs[j]; |
|
829 |
+ AVFilterContext *fifo_ctx; |
|
830 |
+ AVFilter *fifo; |
|
831 |
+ char name[32]; |
|
832 |
+ |
|
833 |
+ if (!link->dstpad->needs_fifo) |
|
834 |
+ continue; |
|
835 |
+ |
|
836 |
+ fifo = f->inputs[j]->type == AVMEDIA_TYPE_VIDEO ? |
|
837 |
+ avfilter_get_by_name("fifo") : |
|
838 |
+ avfilter_get_by_name("afifo"); |
|
839 |
+ |
|
840 |
+ snprintf(name, sizeof(name), "auto-inserted fifo %d", fifo_count++); |
|
841 |
+ |
|
842 |
+ ret = avfilter_graph_create_filter(&fifo_ctx, fifo, name, NULL, |
|
843 |
+ NULL, graph); |
|
844 |
+ if (ret < 0) |
|
845 |
+ return ret; |
|
846 |
+ |
|
847 |
+ ret = avfilter_insert_filter(link, fifo_ctx, 0, 0); |
|
848 |
+ if (ret < 0) |
|
849 |
+ return ret; |
|
850 |
+ } |
|
851 |
+ } |
|
852 |
+ |
|
853 |
+ return 0; |
|
854 |
+} |
|
855 |
+ |
|
818 | 856 |
int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) |
819 | 857 |
{ |
820 | 858 |
int ret; |
821 | 859 |
|
822 | 860 |
if ((ret = graph_check_validity(graphctx, log_ctx))) |
823 | 861 |
return ret; |
862 |
+ if ((ret = graph_insert_fifos(graphctx, log_ctx)) < 0) |
|
863 |
+ return ret; |
|
824 | 864 |
if ((ret = graph_config_formats(graphctx, log_ctx))) |
825 | 865 |
return ret; |
826 | 866 |
if ((ret = graph_config_links(graphctx, log_ctx))) |
... | ... |
@@ -939,7 +979,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) |
939 | 939 |
{ |
940 | 940 |
while (graph->sink_links_count) { |
941 | 941 |
AVFilterLink *oldest = graph->sink_links[0]; |
942 |
- int r = avfilter_request_frame(oldest); |
|
942 |
+ int r = ff_request_frame(oldest); |
|
943 | 943 |
if (r != AVERROR_EOF) |
944 | 944 |
return r; |
945 | 945 |
/* EOF: remove the link from the heap */ |
... | ... |
@@ -257,7 +257,7 @@ char *avfilter_graph_dump(AVFilterGraph *graph, const char *options); |
257 | 257 |
* of a filtergraph, only a convenience function to help drain a filtergraph |
258 | 258 |
* in a balanced way under normal circumstances. |
259 | 259 |
* |
260 |
- * @return the return value of avfilter_request_frame, |
|
260 |
+ * @return the return value of ff_request_frame, |
|
261 | 261 |
* or AVERROR_EOF of all links returned AVERROR_EOF. |
262 | 262 |
*/ |
263 | 263 |
int avfilter_graph_request_oldest(AVFilterGraph *graph); |
... | ... |
@@ -25,7 +25,7 @@ |
25 | 25 |
|
26 | 26 |
#include "libavutil/audio_fifo.h" |
27 | 27 |
#include "libavutil/audioconvert.h" |
28 |
-#include "libavutil/fifo.h" |
|
28 |
+#include "libavutil/avassert.h" |
|
29 | 29 |
#include "libavutil/mathematics.h" |
30 | 30 |
|
31 | 31 |
#include "audio.h" |
... | ... |
@@ -34,86 +34,45 @@ |
34 | 34 |
#include "internal.h" |
35 | 35 |
|
36 | 36 |
typedef struct { |
37 |
- AVFifoBuffer *fifo; ///< FIFO buffer of frame references |
|
38 |
- |
|
37 |
+ AVFilterBufferRef *cur_buf; ///< last buffer delivered on the sink |
|
39 | 38 |
AVAudioFifo *audio_fifo; ///< FIFO for audio samples |
40 | 39 |
int64_t next_pts; ///< interpolating audio pts |
41 | 40 |
} BufferSinkContext; |
42 | 41 |
|
43 |
-#define FIFO_INIT_SIZE 8 |
|
44 |
- |
|
45 | 42 |
static av_cold void uninit(AVFilterContext *ctx) |
46 | 43 |
{ |
47 | 44 |
BufferSinkContext *sink = ctx->priv; |
48 | 45 |
|
49 |
- while (sink->fifo && av_fifo_size(sink->fifo)) { |
|
50 |
- AVFilterBufferRef *buf; |
|
51 |
- av_fifo_generic_read(sink->fifo, &buf, sizeof(buf), NULL); |
|
52 |
- avfilter_unref_buffer(buf); |
|
53 |
- } |
|
54 |
- av_fifo_free(sink->fifo); |
|
55 |
- |
|
56 | 46 |
if (sink->audio_fifo) |
57 | 47 |
av_audio_fifo_free(sink->audio_fifo); |
58 | 48 |
} |
59 | 49 |
|
60 |
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
|
61 |
-{ |
|
62 |
- BufferSinkContext *sink = ctx->priv; |
|
63 |
- |
|
64 |
- if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) { |
|
65 |
- av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n"); |
|
66 |
- return AVERROR(ENOMEM); |
|
67 |
- } |
|
68 |
- |
|
69 |
- return 0; |
|
70 |
-} |
|
71 |
- |
|
72 |
-static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf) |
|
50 |
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *buf) |
|
73 | 51 |
{ |
74 |
- BufferSinkContext *sink = ctx->priv; |
|
75 |
- |
|
76 |
- if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) && |
|
77 |
- (av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) { |
|
78 |
- av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n"); |
|
79 |
- return; |
|
80 |
- } |
|
52 |
+ BufferSinkContext *s = link->dst->priv; |
|
81 | 53 |
|
82 |
- av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL); |
|
83 |
-} |
|
84 |
- |
|
85 |
-static void end_frame(AVFilterLink *link) |
|
86 |
-{ |
|
87 |
- write_buf(link->dst, link->cur_buf); |
|
54 |
+// av_assert0(!s->cur_buf); |
|
55 |
+ s->cur_buf = buf; |
|
88 | 56 |
link->cur_buf = NULL; |
89 |
-} |
|
90 |
- |
|
91 |
-static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) |
|
92 |
-{ |
|
93 |
- write_buf(link->dst, buf); |
|
94 |
-} |
|
57 |
+}; |
|
95 | 58 |
|
96 | 59 |
int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) |
97 | 60 |
{ |
98 |
- BufferSinkContext *sink = ctx->priv; |
|
61 |
+ BufferSinkContext *s = ctx->priv; |
|
99 | 62 |
AVFilterLink *link = ctx->inputs[0]; |
100 | 63 |
int ret; |
101 | 64 |
|
102 |
- if (!buf) { |
|
103 |
- if (av_fifo_size(sink->fifo)) |
|
104 |
- return av_fifo_size(sink->fifo)/sizeof(*buf); |
|
105 |
- else |
|
106 |
- return ff_poll_frame(ctx->inputs[0]); |
|
107 |
- } |
|
65 |
+ if (!buf) |
|
66 |
+ return ff_poll_frame(ctx->inputs[0]); |
|
108 | 67 |
|
109 |
- if (!av_fifo_size(sink->fifo) && |
|
110 |
- (ret = ff_request_frame(link)) < 0) |
|
68 |
+ if ((ret = ff_request_frame(link)) < 0) |
|
111 | 69 |
return ret; |
112 | 70 |
|
113 |
- if (!av_fifo_size(sink->fifo)) |
|
71 |
+ if (!s->cur_buf) |
|
114 | 72 |
return AVERROR(EINVAL); |
115 | 73 |
|
116 |
- av_fifo_generic_read(sink->fifo, buf, sizeof(*buf), NULL); |
|
74 |
+ *buf = s->cur_buf; |
|
75 |
+ s->cur_buf = NULL; |
|
117 | 76 |
|
118 | 77 |
return 0; |
119 | 78 |
} |
... | ... |
@@ -182,13 +141,13 @@ AVFilter avfilter_vsink_buffer = { |
182 | 182 |
.name = "buffersink_old", |
183 | 183 |
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), |
184 | 184 |
.priv_size = sizeof(BufferSinkContext), |
185 |
- .init = init, |
|
186 | 185 |
.uninit = uninit, |
187 | 186 |
|
188 | 187 |
.inputs = (AVFilterPad[]) {{ .name = "default", |
189 | 188 |
.type = AVMEDIA_TYPE_VIDEO, |
190 |
- .end_frame = end_frame, |
|
191 |
- .min_perms = AV_PERM_READ, }, |
|
189 |
+ .start_frame = start_frame, |
|
190 |
+ .min_perms = AV_PERM_READ, |
|
191 |
+ .needs_fifo = 1 }, |
|
192 | 192 |
{ .name = NULL }}, |
193 | 193 |
.outputs = (AVFilterPad[]) {{ .name = NULL }}, |
194 | 194 |
}; |
... | ... |
@@ -197,13 +156,13 @@ AVFilter avfilter_asink_abuffer = { |
197 | 197 |
.name = "abuffersink_old", |
198 | 198 |
.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), |
199 | 199 |
.priv_size = sizeof(BufferSinkContext), |
200 |
- .init = init, |
|
201 | 200 |
.uninit = uninit, |
202 | 201 |
|
203 | 202 |
.inputs = (AVFilterPad[]) {{ .name = "default", |
204 | 203 |
.type = AVMEDIA_TYPE_AUDIO, |
205 |
- .filter_samples = filter_samples, |
|
206 |
- .min_perms = AV_PERM_READ, }, |
|
204 |
+ .filter_samples = start_frame, |
|
205 |
+ .min_perms = AV_PERM_READ, |
|
206 |
+ .needs_fifo = 1 }, |
|
207 | 207 |
{ .name = NULL }}, |
208 | 208 |
.outputs = (AVFilterPad[]) {{ .name = NULL }}, |
209 | 209 |
}; |
... | ... |
@@ -47,27 +47,6 @@ static void set_common_formats(AVFilterContext *ctx, AVFilterFormats *fmts, |
47 | 47 |
} |
48 | 48 |
} |
49 | 49 |
|
50 |
-void avfilter_set_common_pixel_formats(AVFilterContext *ctx, AVFilterFormats *formats) |
|
51 |
-{ |
|
52 |
- set_common_formats(ctx, formats, AVMEDIA_TYPE_VIDEO, |
|
53 |
- offsetof(AVFilterLink, in_formats), |
|
54 |
- offsetof(AVFilterLink, out_formats)); |
|
55 |
-} |
|
56 |
- |
|
57 |
-void avfilter_set_common_sample_formats(AVFilterContext *ctx, AVFilterFormats *formats) |
|
58 |
-{ |
|
59 |
- set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO, |
|
60 |
- offsetof(AVFilterLink, in_formats), |
|
61 |
- offsetof(AVFilterLink, out_formats)); |
|
62 |
-} |
|
63 |
- |
|
64 |
-void avfilter_set_common_channel_layouts(AVFilterContext *ctx, AVFilterFormats *formats) |
|
65 |
-{ |
|
66 |
- set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO, |
|
67 |
- offsetof(AVFilterLink, in_channel_layouts), |
|
68 |
- offsetof(AVFilterLink, out_channel_layouts)); |
|
69 |
-} |
|
70 |
- |
|
71 | 50 |
#if FF_API_PACKING |
72 | 51 |
void avfilter_set_common_packing_formats(AVFilterContext *ctx, AVFilterFormats *formats) |
73 | 52 |
{ |
... | ... |
@@ -23,6 +23,11 @@ |
23 | 23 |
* FIFO buffering filter |
24 | 24 |
*/ |
25 | 25 |
|
26 |
+#include "libavutil/avassert.h" |
|
27 |
+#include "libavutil/audioconvert.h" |
|
28 |
+#include "libavutil/mathematics.h" |
|
29 |
+#include "libavutil/samplefmt.h" |
|
30 |
+ |
|
26 | 31 |
#include "audio.h" |
27 | 32 |
#include "avfilter.h" |
28 | 33 |
#include "internal.h" |
... | ... |
@@ -36,6 +41,13 @@ typedef struct Buf { |
36 | 36 |
typedef struct { |
37 | 37 |
Buf root; |
38 | 38 |
Buf *last; ///< last buffered frame |
39 |
+ |
|
40 |
+ /** |
|
41 |
+ * When a specific number of output samples is requested, the partial |
|
42 |
+ * buffer is stored here |
|
43 |
+ */ |
|
44 |
+ AVFilterBufferRef *buf_out; |
|
45 |
+ int allocated_samples; ///< number of samples buf_out was allocated for |
|
39 | 46 |
} FifoContext; |
40 | 47 |
|
41 | 48 |
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
... | ... |
@@ -57,6 +69,8 @@ static av_cold void uninit(AVFilterContext *ctx) |
57 | 57 |
avfilter_unref_buffer(buf->buf); |
58 | 58 |
av_free(buf); |
59 | 59 |
} |
60 |
+ |
|
61 |
+ avfilter_unref_buffer(fifo->buf_out); |
|
60 | 62 |
} |
61 | 63 |
|
62 | 64 |
static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf) |
... | ... |
@@ -68,14 +82,143 @@ static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf) |
68 | 68 |
fifo->last->buf = buf; |
69 | 69 |
} |
70 | 70 |
|
71 |
+static void queue_pop(FifoContext *s) |
|
72 |
+{ |
|
73 |
+ Buf *tmp = s->root.next->next; |
|
74 |
+ if (s->last == s->root.next) |
|
75 |
+ s->last = &s->root; |
|
76 |
+ av_freep(&s->root.next); |
|
77 |
+ s->root.next = tmp; |
|
78 |
+} |
|
79 |
+ |
|
71 | 80 |
static void end_frame(AVFilterLink *inlink) { } |
72 | 81 |
|
73 | 82 |
static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) { } |
74 | 83 |
|
84 |
+/** |
|
85 |
+ * Move data pointers and pts offset samples forward. |
|
86 |
+ */ |
|
87 |
+static void buffer_offset(AVFilterLink *link, AVFilterBufferRef *buf, |
|
88 |
+ int offset) |
|
89 |
+{ |
|
90 |
+ int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout); |
|
91 |
+ int planar = av_sample_fmt_is_planar(link->format); |
|
92 |
+ int planes = planar ? nb_channels : 1; |
|
93 |
+ int block_align = av_get_bytes_per_sample(link->format) * (planar ? 1 : nb_channels); |
|
94 |
+ int i; |
|
95 |
+ |
|
96 |
+ av_assert0(buf->audio->nb_samples > offset); |
|
97 |
+ |
|
98 |
+ for (i = 0; i < planes; i++) |
|
99 |
+ buf->extended_data[i] += block_align*offset; |
|
100 |
+ if (buf->data != buf->extended_data) |
|
101 |
+ memcpy(buf->data, buf->extended_data, |
|
102 |
+ FFMIN(planes, FF_ARRAY_ELEMS(buf->data)) * sizeof(*buf->data)); |
|
103 |
+ buf->linesize[0] -= block_align*offset; |
|
104 |
+ buf->audio->nb_samples -= offset; |
|
105 |
+ |
|
106 |
+ if (buf->pts != AV_NOPTS_VALUE) { |
|
107 |
+ buf->pts += av_rescale_q(offset, (AVRational){1, link->sample_rate}, |
|
108 |
+ link->time_base); |
|
109 |
+ } |
|
110 |
+} |
|
111 |
+ |
|
112 |
+static int calc_ptr_alignment(AVFilterBufferRef *buf) |
|
113 |
+{ |
|
114 |
+ int planes = av_sample_fmt_is_planar(buf->format) ? |
|
115 |
+ av_get_channel_layout_nb_channels(buf->audio->channel_layout) : 1; |
|
116 |
+ int min_align = 128; |
|
117 |
+ int p; |
|
118 |
+ |
|
119 |
+ for (p = 0; p < planes; p++) { |
|
120 |
+ int cur_align = 128; |
|
121 |
+ while ((intptr_t)buf->extended_data[p] % cur_align) |
|
122 |
+ cur_align >>= 1; |
|
123 |
+ if (cur_align < min_align) |
|
124 |
+ min_align = cur_align; |
|
125 |
+ } |
|
126 |
+ return min_align; |
|
127 |
+} |
|
128 |
+ |
|
129 |
+static int return_audio_frame(AVFilterContext *ctx) |
|
130 |
+{ |
|
131 |
+ AVFilterLink *link = ctx->outputs[0]; |
|
132 |
+ FifoContext *s = ctx->priv; |
|
133 |
+ AVFilterBufferRef *head = s->root.next->buf; |
|
134 |
+ AVFilterBufferRef *buf_out; |
|
135 |
+ int ret; |
|
136 |
+ |
|
137 |
+ if (!s->buf_out && |
|
138 |
+ head->audio->nb_samples >= link->request_samples && |
|
139 |
+ calc_ptr_alignment(head) >= 32) { |
|
140 |
+ if (head->audio->nb_samples == link->request_samples) { |
|
141 |
+ buf_out = head; |
|
142 |
+ queue_pop(s); |
|
143 |
+ } else { |
|
144 |
+ buf_out = avfilter_ref_buffer(head, AV_PERM_READ); |
|
145 |
+ buf_out->audio->nb_samples = link->request_samples; |
|
146 |
+ buffer_offset(link, head, link->request_samples); |
|
147 |
+ } |
|
148 |
+ } else { |
|
149 |
+ int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout); |
|
150 |
+ |
|
151 |
+ if (!s->buf_out) { |
|
152 |
+ s->buf_out = ff_get_audio_buffer(link, AV_PERM_WRITE, |
|
153 |
+ link->request_samples); |
|
154 |
+ if (!s->buf_out) |
|
155 |
+ return AVERROR(ENOMEM); |
|
156 |
+ |
|
157 |
+ s->buf_out->audio->nb_samples = 0; |
|
158 |
+ s->buf_out->pts = head->pts; |
|
159 |
+ s->allocated_samples = link->request_samples; |
|
160 |
+ } else if (link->request_samples != s->allocated_samples) { |
|
161 |
+ av_log(ctx, AV_LOG_ERROR, "request_samples changed before the " |
|
162 |
+ "buffer was returned.\n"); |
|
163 |
+ return AVERROR(EINVAL); |
|
164 |
+ } |
|
165 |
+ |
|
166 |
+ while (s->buf_out->audio->nb_samples < s->allocated_samples) { |
|
167 |
+ int len = FFMIN(s->allocated_samples - s->buf_out->audio->nb_samples, |
|
168 |
+ head->audio->nb_samples); |
|
169 |
+ |
|
170 |
+ av_samples_copy(s->buf_out->extended_data, head->extended_data, |
|
171 |
+ s->buf_out->audio->nb_samples, 0, len, nb_channels, |
|
172 |
+ link->format); |
|
173 |
+ s->buf_out->audio->nb_samples += len; |
|
174 |
+ |
|
175 |
+ if (len == head->audio->nb_samples) { |
|
176 |
+ avfilter_unref_buffer(head); |
|
177 |
+ queue_pop(s); |
|
178 |
+ |
|
179 |
+ if (!s->root.next && |
|
180 |
+ (ret = ff_request_frame(ctx->inputs[0])) < 0) { |
|
181 |
+ if (ret == AVERROR_EOF) { |
|
182 |
+ av_samples_set_silence(s->buf_out->extended_data, |
|
183 |
+ s->buf_out->audio->nb_samples, |
|
184 |
+ s->allocated_samples - |
|
185 |
+ s->buf_out->audio->nb_samples, |
|
186 |
+ nb_channels, link->format); |
|
187 |
+ s->buf_out->audio->nb_samples = s->allocated_samples; |
|
188 |
+ break; |
|
189 |
+ } |
|
190 |
+ return ret; |
|
191 |
+ } |
|
192 |
+ head = s->root.next->buf; |
|
193 |
+ } else { |
|
194 |
+ buffer_offset(link, head, len); |
|
195 |
+ } |
|
196 |
+ } |
|
197 |
+ buf_out = s->buf_out; |
|
198 |
+ s->buf_out = NULL; |
|
199 |
+ } |
|
200 |
+ ff_filter_samples(link, buf_out); |
|
201 |
+ |
|
202 |
+ return 0; |
|
203 |
+} |
|
204 |
+ |
|
75 | 205 |
static int request_frame(AVFilterLink *outlink) |
76 | 206 |
{ |
77 | 207 |
FifoContext *fifo = outlink->src->priv; |
78 |
- Buf *tmp; |
|
79 | 208 |
int ret; |
80 | 209 |
|
81 | 210 |
if (!fifo->root.next) { |
... | ... |
@@ -90,20 +233,20 @@ static int request_frame(AVFilterLink *outlink) |
90 | 90 |
ff_start_frame(outlink, fifo->root.next->buf); |
91 | 91 |
ff_draw_slice (outlink, 0, outlink->h, 1); |
92 | 92 |
ff_end_frame (outlink); |
93 |
+ queue_pop(fifo); |
|
93 | 94 |
break; |
94 | 95 |
case AVMEDIA_TYPE_AUDIO: |
95 |
- ff_filter_samples(outlink, fifo->root.next->buf); |
|
96 |
+ if (outlink->request_samples) { |
|
97 |
+ return return_audio_frame(outlink->src); |
|
98 |
+ } else { |
|
99 |
+ ff_filter_samples(outlink, fifo->root.next->buf); |
|
100 |
+ queue_pop(fifo); |
|
101 |
+ } |
|
96 | 102 |
break; |
97 | 103 |
default: |
98 | 104 |
return AVERROR(EINVAL); |
99 | 105 |
} |
100 | 106 |
|
101 |
- if (fifo->last == fifo->root.next) |
|
102 |
- fifo->last = &fifo->root; |
|
103 |
- tmp = fifo->root.next->next; |
|
104 |
- av_free(fifo->root.next); |
|
105 |
- fifo->root.next = tmp; |
|
106 |
- |
|
107 | 107 |
return 0; |
108 | 108 |
} |
109 | 109 |
|
... | ... |
@@ -262,11 +262,6 @@ int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout) |
262 | 262 |
|
263 | 263 |
AVFilterFormats *ff_all_formats(enum AVMediaType type) |
264 | 264 |
{ |
265 |
- return avfilter_make_all_formats(type); |
|
266 |
-} |
|
267 |
- |
|
268 |
-AVFilterFormats *avfilter_make_all_formats(enum AVMediaType type) |
|
269 |
-{ |
|
270 | 265 |
AVFilterFormats *ret = NULL; |
271 | 266 |
int fmt; |
272 | 267 |
int num_formats = type == AVMEDIA_TYPE_VIDEO ? PIX_FMT_NB : |
... | ... |
@@ -173,6 +173,14 @@ struct AVFilterPad { |
173 | 173 |
* and another value on error. |
174 | 174 |
*/ |
175 | 175 |
int (*config_props)(AVFilterLink *link); |
176 |
+ |
|
177 |
+ /** |
|
178 |
+ * The filter expects a fifo to be inserted on its input link, |
|
179 |
+ * typically because it has a delay. |
|
180 |
+ * |
|
181 |
+ * input pads only. |
|
182 |
+ */ |
|
183 |
+ int needs_fifo; |
|
176 | 184 |
}; |
177 | 185 |
#endif |
178 | 186 |
|
... | ... |
@@ -94,7 +94,7 @@ static const uint8_t offset[511][2]= { |
94 | 94 |
{ 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, |
95 | 95 |
{ 7, 5}, {15, 5}, { 7,13}, {15,13}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, |
96 | 96 |
|
97 |
-{ 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}, |
|
97 |
+{ 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}, |
|
98 | 98 |
}; |
99 | 99 |
|
100 | 100 |
struct vf_priv_s { |
... | ... |
@@ -127,7 +127,7 @@ int av_buffersink_get_buffer_ref(AVFilterContext *ctx, |
127 | 127 |
if (!av_fifo_size(buf->fifo)) { |
128 | 128 |
if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST) |
129 | 129 |
return AVERROR(EAGAIN); |
130 |
- if ((ret = avfilter_request_frame(inlink)) < 0) |
|
130 |
+ if ((ret = ff_request_frame(inlink)) < 0) |
|
131 | 131 |
return ret; |
132 | 132 |
} |
133 | 133 |
|
... | ... |
@@ -28,8 +28,8 @@ |
28 | 28 |
|
29 | 29 |
#include "libavutil/avutil.h" |
30 | 30 |
|
31 |
-#define LIBAVFILTER_VERSION_MAJOR 2 |
|
32 |
-#define LIBAVFILTER_VERSION_MINOR 82 |
|
31 |
+#define LIBAVFILTER_VERSION_MAJOR 3 |
|
32 |
+#define LIBAVFILTER_VERSION_MINOR 0 |
|
33 | 33 |
#define LIBAVFILTER_VERSION_MICRO 100 |
34 | 34 |
|
35 | 35 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
... | ... |
@@ -136,7 +136,7 @@ static int request_frame(AVFilterLink *outlink) |
136 | 136 |
AVFilterContext *ctx = outlink->src; |
137 | 137 |
BlackDetectContext *blackdetect = ctx->priv; |
138 | 138 |
AVFilterLink *inlink = ctx->inputs[0]; |
139 |
- int ret = avfilter_request_frame(inlink); |
|
139 |
+ int ret = ff_request_frame(inlink); |
|
140 | 140 |
|
141 | 141 |
if (ret == AVERROR_EOF && blackdetect->black_started) { |
142 | 142 |
// FIXME: black_end should be set to last_picref_pts + last_picref_duration |
... | ... |
@@ -216,7 +216,7 @@ static int request_frame(AVFilterLink *link) |
216 | 216 |
do { |
217 | 217 |
int ret; |
218 | 218 |
|
219 |
- if ((ret = avfilter_request_frame(link->src->inputs[0]))) |
|
219 |
+ if ((ret = ff_request_frame(link->src->inputs[0]))) |
|
220 | 220 |
return ret; |
221 | 221 |
} while (!idet->cur); |
222 | 222 |
|
... | ... |
@@ -231,7 +231,7 @@ static int poll_frame(AVFilterLink *link) |
231 | 231 |
val = ff_poll_frame(link->src->inputs[0]); |
232 | 232 |
|
233 | 233 |
if (val >= 1 && !idet->next) { //FIXME change API to not requre this red tape |
234 |
- if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0) |
|
234 |
+ if ((ret = ff_request_frame(link->src->inputs[0])) < 0) |
|
235 | 235 |
return ret; |
236 | 236 |
val = ff_poll_frame(link->src->inputs[0]); |
237 | 237 |
} |
... | ... |
@@ -25,6 +25,9 @@ |
25 | 25 |
*/ |
26 | 26 |
|
27 | 27 |
#include "avfilter.h" |
28 |
+#include "video.h" |
|
29 |
+#include "formats.h" |
|
30 |
+#include "internal.h" |
|
28 | 31 |
#include "libavutil/avassert.h" |
29 | 32 |
#include "libavutil/pixdesc.h" |
30 | 33 |
#include "libavutil/intreadwrite.h" |
... | ... |
@@ -633,9 +636,9 @@ int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){ |
633 | 633 |
if(pts != MP_NOPTS_VALUE) |
634 | 634 |
picref->pts= pts * av_q2d(outlink->time_base); |
635 | 635 |
|
636 |
- avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0)); |
|
637 |
- avfilter_draw_slice(outlink, 0, picref->video->h, 1); |
|
638 |
- avfilter_end_frame(outlink); |
|
636 |
+ ff_start_frame(outlink, avfilter_ref_buffer(picref, ~0)); |
|
637 |
+ ff_draw_slice(outlink, 0, picref->video->h, 1); |
|
638 |
+ ff_end_frame(outlink); |
|
639 | 639 |
avfilter_unref_buffer(picref); |
640 | 640 |
m->frame_returned++; |
641 | 641 |
|
... | ... |
@@ -788,14 +791,14 @@ static int query_formats(AVFilterContext *ctx) |
788 | 788 |
if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){ |
789 | 789 |
av_log(ctx, AV_LOG_DEBUG, "supported,adding\n"); |
790 | 790 |
if (conversion_map[i].pix_fmt != lastpixfmt) { |
791 |
- avfilter_add_format(&avfmts, conversion_map[i].pix_fmt); |
|
791 |
+ ff_add_format(&avfmts, conversion_map[i].pix_fmt); |
|
792 | 792 |
lastpixfmt = conversion_map[i].pix_fmt; |
793 | 793 |
} |
794 | 794 |
} |
795 | 795 |
} |
796 | 796 |
|
797 | 797 |
//We assume all allowed input formats are also allowed output formats |
798 |
- avfilter_set_common_pixel_formats(ctx, avfmts); |
|
798 |
+ ff_set_common_formats(ctx, avfmts); |
|
799 | 799 |
return 0; |
800 | 800 |
} |
801 | 801 |
|
... | ... |
@@ -836,7 +839,7 @@ static int request_frame(AVFilterLink *outlink) |
836 | 836 |
av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n"); |
837 | 837 |
|
838 | 838 |
for(m->frame_returned=0; !m->frame_returned;){ |
839 |
- ret=avfilter_request_frame(outlink->src->inputs[0]); |
|
839 |
+ ret=ff_request_frame(outlink->src->inputs[0]); |
|
840 | 840 |
if(ret<0) |
841 | 841 |
break; |
842 | 842 |
} |
... | ... |
@@ -178,7 +178,7 @@ static int request_frame(AVFilterLink *link) |
178 | 178 |
/* loop until a frame thumbnail is available (when a frame is queued, |
179 | 179 |
* thumb->n is reset to zero) */ |
180 | 180 |
do { |
181 |
- int ret = avfilter_request_frame(link->src->inputs[0]); |
|
181 |
+ int ret = ff_request_frame(link->src->inputs[0]); |
|
182 | 182 |
if (ret < 0) |
183 | 183 |
return ret; |
184 | 184 |
} while (thumb->n); |
... | ... |
@@ -203,7 +203,7 @@ static int poll_frame(AVFilterLink *link) |
203 | 203 |
|
204 | 204 |
/* we have some frame(s) available in the input link, but not yet enough to |
205 | 205 |
* output a thumbnail, so we request more */ |
206 |
- ret = avfilter_request_frame(inlink); |
|
206 |
+ ret = ff_request_frame(inlink); |
|
207 | 207 |
return ret < 0 ? ret : 0; |
208 | 208 |
} |
209 | 209 |
|
... | ... |
@@ -28,6 +28,7 @@ |
28 | 28 |
#include "drawutils.h" |
29 | 29 |
#include "formats.h" |
30 | 30 |
#include "video.h" |
31 |
+#include "internal.h" |
|
31 | 32 |
|
32 | 33 |
typedef struct { |
33 | 34 |
unsigned w, h; |
... | ... |
@@ -170,7 +171,7 @@ static int request_frame(AVFilterLink *outlink) |
170 | 170 |
int r; |
171 | 171 |
|
172 | 172 |
while (1) { |
173 |
- r = avfilter_request_frame(inlink); |
|
173 |
+ r = ff_request_frame(inlink); |
|
174 | 174 |
if (r < 0) { |
175 | 175 |
if (r == AVERROR_EOF && tile->current) |
176 | 176 |
end_last_frame(ctx); |
... | ... |
@@ -334,7 +334,7 @@ static int poll_frame(AVFilterLink *outlink) |
334 | 334 |
val = ff_poll_frame(inlink); |
335 | 335 |
|
336 | 336 |
if (val == 1 && !tinterlace->next) { |
337 |
- if ((ret = avfilter_request_frame(inlink)) < 0) |
|
337 |
+ if ((ret = ff_request_frame(inlink)) < 0) |
|
338 | 338 |
return ret; |
339 | 339 |
val = ff_poll_frame(inlink); |
340 | 340 |
} |
... | ... |
@@ -351,7 +351,7 @@ static int request_frame(AVFilterLink *outlink) |
351 | 351 |
do { |
352 | 352 |
int ret; |
353 | 353 |
|
354 |
- if ((ret = avfilter_request_frame(inlink)) < 0) |
|
354 |
+ if ((ret = ff_request_frame(inlink)) < 0) |
|
355 | 355 |
return ret; |
356 | 356 |
} while (!tinterlace->cur); |
357 | 357 |
|
... | ... |
@@ -321,6 +321,11 @@ void ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) |
321 | 321 |
draw_slice(link, y, h, slice_dir); |
322 | 322 |
} |
323 | 323 |
|
324 |
+void avfilter_default_end_frame(AVFilterLink *inlink) |
|
325 |
+{ |
|
326 |
+ default_end_frame(inlink); |
|
327 |
+} |
|
328 |
+ |
|
324 | 329 |
#if FF_API_FILTERS_PUBLIC |
325 | 330 |
AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h) |
326 | 331 |
{ |
... | ... |
@@ -330,10 +335,6 @@ void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picre |
330 | 330 |
{ |
331 | 331 |
default_start_frame(inlink, picref); |
332 | 332 |
} |
333 |
-void avfilter_default_end_frame(AVFilterLink *inlink) |
|
334 |
-{ |
|
335 |
- default_end_frame(inlink); |
|
336 |
-} |
|
337 | 333 |
void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) |
338 | 334 |
{ |
339 | 335 |
default_draw_slice(inlink, y, h, slice_dir); |
... | ... |
@@ -49,7 +49,7 @@ void av_set_cpu_flags_mask(int mask) |
49 | 49 |
|
50 | 50 |
int av_parse_cpu_flags(const char *s) |
51 | 51 |
{ |
52 |
-#define CPUFLAG_MMX2 (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMX2) |
|
52 |
+#define CPUFLAG_MMX2 (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_CMOV) |
|
53 | 53 |
#define CPUFLAG_3DNOW (AV_CPU_FLAG_3DNOW | AV_CPU_FLAG_MMX) |
54 | 54 |
#define CPUFLAG_3DNOWEXT (AV_CPU_FLAG_3DNOWEXT | CPUFLAG_3DNOW) |
55 | 55 |
#define CPUFLAG_SSE (AV_CPU_FLAG_SSE | CPUFLAG_MMX2) |
... | ... |
@@ -84,6 +84,7 @@ int av_parse_cpu_flags(const char *s) |
84 | 84 |
{ "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_FMA4 }, .unit = "flags" }, |
85 | 85 |
{ "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOW }, .unit = "flags" }, |
86 | 86 |
{ "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOWEXT }, .unit = "flags" }, |
87 |
+ { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_CMOV }, .unit = "flags" }, |
|
87 | 88 |
#elif ARCH_ARM |
88 | 89 |
{ "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV5TE }, .unit = "flags" }, |
89 | 90 |
{ "armv6", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV6 }, .unit = "flags" }, |
... | ... |
@@ -188,6 +189,7 @@ static const struct { |
188 | 188 |
{ AV_CPU_FLAG_FMA4, "fma4" }, |
189 | 189 |
{ AV_CPU_FLAG_3DNOW, "3dnow" }, |
190 | 190 |
{ AV_CPU_FLAG_3DNOWEXT, "3dnowext" }, |
191 |
+ { AV_CPU_FLAG_CMOV, "cmov" }, |
|
191 | 192 |
#endif |
192 | 193 |
{ 0 } |
193 | 194 |
}; |
... | ... |
@@ -40,9 +40,14 @@ |
40 | 40 |
#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions |
41 | 41 |
#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions |
42 | 42 |
#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used |
43 |
-#define AV_CPU_FLAG_CMOV 0x1000000 ///< supports cmov instruction |
|
44 | 43 |
#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions |
45 | 44 |
#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions |
45 |
+#if LIBAVUTIL_VERSION_MAJOR <52 |
|
46 |
+#define AV_CPU_FLAG_CMOV 0x1001000 ///< supports cmov instruction |
|
47 |
+#else |
|
48 |
+#define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction |
|
49 |
+#endif |
|
50 |
+ |
|
46 | 51 |
#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard |
47 | 52 |
|
48 | 53 |
#define AV_CPU_FLAG_ARMV5TE (1 << 0) |
... | ... |
@@ -83,7 +83,7 @@ int ff_get_cpu_flags_x86(void) |
83 | 83 |
cpuid(1, eax, ebx, ecx, std_caps); |
84 | 84 |
family = ((eax>>8)&0xf) + ((eax>>20)&0xff); |
85 | 85 |
model = ((eax>>4)&0xf) + ((eax>>12)&0xf0); |
86 |
- if (std_caps & (1<<15)) |
|
86 |
+ if (std_caps & (1 << 15)) |
|
87 | 87 |
rval |= AV_CPU_FLAG_CMOV; |
88 | 88 |
if (std_caps & (1<<23)) |
89 | 89 |
rval |= AV_CPU_FLAG_MMX; |