... | ... |
@@ -151,6 +151,33 @@ anullsrc=48000:4 |
151 | 151 |
anullsrc=48000:mono |
152 | 152 |
@end example |
153 | 153 |
|
154 |
+@section abuffer |
|
155 |
+Buffer audio frames, and make them available to the filter chain. |
|
156 |
+ |
|
157 |
+This source is not intended to be part of user-supplied graph descriptions but |
|
158 |
+for insertion by calling programs through the interface defined in |
|
159 |
+@file{libavfilter/buffersrc.h}. |
|
160 |
+ |
|
161 |
+It accepts the following named parameters: |
|
162 |
+@table @option |
|
163 |
+ |
|
164 |
+@item time_base |
|
165 |
+Timebase which will be used for timestamps of submitted frames. It must be |
|
166 |
+either a floating-point number or in @var{numerator}/@var{denominator} form. |
|
167 |
+ |
|
168 |
+@item sample_rate |
|
169 |
+Audio sample rate. |
|
170 |
+ |
|
171 |
+@item sample_fmt |
|
172 |
+Name of the sample format, as returned by @code{av_get_sample_fmt_name()}. |
|
173 |
+ |
|
174 |
+@item channel_layout |
|
175 |
+Channel layout of the audio data, in the form that can be accepted by |
|
176 |
+@code{av_get_channel_layout()}. |
|
177 |
+@end table |
|
178 |
+ |
|
179 |
+All the parameters need to be explicitly defined. |
|
180 |
+ |
|
154 | 181 |
@c man end AUDIO SOURCES |
155 | 182 |
|
156 | 183 |
@chapter Audio Sinks |
... | ... |
@@ -96,6 +96,10 @@ void avfilter_register_all(void) |
96 | 96 |
avfilter_register(&avfilter_vsrc_buffer); |
97 | 97 |
} |
98 | 98 |
{ |
99 |
+ extern AVFilter avfilter_asrc_abuffer; |
|
100 |
+ avfilter_register(&avfilter_asrc_abuffer); |
|
101 |
+ } |
|
102 |
+ { |
|
99 | 103 |
extern AVFilter avfilter_vsink_buffer; |
100 | 104 |
avfilter_register(&avfilter_vsink_buffer); |
101 | 105 |
} |
... | ... |
@@ -23,27 +23,51 @@ |
23 | 23 |
* memory buffer source filter |
24 | 24 |
*/ |
25 | 25 |
|
26 |
+#include "audio.h" |
|
26 | 27 |
#include "avfilter.h" |
27 | 28 |
#include "buffersrc.h" |
29 |
+#include "formats.h" |
|
28 | 30 |
#include "vsrc_buffer.h" |
31 |
+ |
|
32 |
+#include "libavutil/audioconvert.h" |
|
29 | 33 |
#include "libavutil/fifo.h" |
30 | 34 |
#include "libavutil/imgutils.h" |
35 |
+#include "libavutil/opt.h" |
|
36 |
+#include "libavutil/samplefmt.h" |
|
31 | 37 |
|
32 | 38 |
typedef struct { |
39 |
+ const AVClass *class; |
|
33 | 40 |
AVFifoBuffer *fifo; |
41 |
+ AVRational time_base; ///< time_base to set in the output link |
|
42 |
+ |
|
43 |
+ /* video only */ |
|
34 | 44 |
int h, w; |
35 | 45 |
enum PixelFormat pix_fmt; |
36 |
- AVRational time_base; ///< time_base to set in the output link |
|
37 | 46 |
AVRational pixel_aspect; |
47 |
+ |
|
48 |
+ /* audio only */ |
|
49 |
+ int sample_rate; |
|
50 |
+ enum AVSampleFormat sample_fmt; |
|
51 |
+ char *sample_fmt_str; |
|
52 |
+ uint64_t channel_layout; |
|
53 |
+ char *channel_layout_str; |
|
54 |
+ |
|
38 | 55 |
int eof; |
39 | 56 |
} BufferSourceContext; |
40 | 57 |
|
41 |
-#define CHECK_PARAM_CHANGE(s, c, width, height, format)\ |
|
58 |
+#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\ |
|
42 | 59 |
if (c->w != width || c->h != height || c->pix_fmt != format) {\ |
43 | 60 |
av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ |
44 | 61 |
return AVERROR(EINVAL);\ |
45 | 62 |
} |
46 | 63 |
|
64 |
+#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, format)\ |
|
65 |
+ if (c->sample_fmt != format || c->sample_rate != srate ||\ |
|
66 |
+ c->channel_layout != ch_layout) {\ |
|
67 |
+ av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ |
|
68 |
+ return AVERROR(EINVAL);\ |
|
69 |
+ } |
|
70 |
+ |
|
47 | 71 |
#if FF_API_VSRC_BUFFER_ADD_FRAME |
48 | 72 |
int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, |
49 | 73 |
int64_t pts, AVRational pixel_aspect) |
... | ... |
@@ -80,12 +104,28 @@ int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame) |
80 | 80 |
sizeof(buf))) < 0) |
81 | 81 |
return ret; |
82 | 82 |
|
83 |
- CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format); |
|
84 |
- |
|
85 |
- buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, |
|
86 |
- c->w, c->h); |
|
87 |
- av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize, |
|
88 |
- c->pix_fmt, c->w, c->h); |
|
83 |
+ switch (buffer_filter->outputs[0]->type) { |
|
84 |
+ case AVMEDIA_TYPE_VIDEO: |
|
85 |
+ CHECK_VIDEO_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, |
|
86 |
+ frame->format); |
|
87 |
+ buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, |
|
88 |
+ c->w, c->h); |
|
89 |
+ av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize, |
|
90 |
+ c->pix_fmt, c->w, c->h); |
|
91 |
+ break; |
|
92 |
+ case AVMEDIA_TYPE_AUDIO: |
|
93 |
+ CHECK_AUDIO_PARAM_CHANGE(buffer_filter, c, frame->sample_rate, frame->channel_layout, |
|
94 |
+ frame->format); |
|
95 |
+ buf = ff_get_audio_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, |
|
96 |
+ frame->nb_samples); |
|
97 |
+ av_samples_copy(buf->extended_data, frame->extended_data, |
|
98 |
+ 0, 0, frame->nb_samples, |
|
99 |
+ av_get_channel_layout_nb_channels(frame->channel_layout), |
|
100 |
+ frame->format); |
|
101 |
+ break; |
|
102 |
+ default: |
|
103 |
+ return AVERROR(EINVAL); |
|
104 |
+ } |
|
89 | 105 |
|
90 | 106 |
avfilter_copy_frame_props(buf, frame); |
91 | 107 |
|
... | ... |
@@ -113,7 +153,17 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf) |
113 | 113 |
sizeof(buf))) < 0) |
114 | 114 |
return ret; |
115 | 115 |
|
116 |
- CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format); |
|
116 |
+ switch (s->outputs[0]->type) { |
|
117 |
+ case AVMEDIA_TYPE_VIDEO: |
|
118 |
+ CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format); |
|
119 |
+ break; |
|
120 |
+ case AVMEDIA_TYPE_AUDIO: |
|
121 |
+ CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout, |
|
122 |
+ buf->format); |
|
123 |
+ break; |
|
124 |
+ default: |
|
125 |
+ return AVERROR(EINVAL); |
|
126 |
+ } |
|
117 | 127 |
|
118 | 128 |
if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) |
119 | 129 |
return ret; |
... | ... |
@@ -121,7 +171,7 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf) |
121 | 121 |
return 0; |
122 | 122 |
} |
123 | 123 |
|
124 |
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
|
124 |
+static av_cold int init_video(AVFilterContext *ctx, const char *args, void *opaque) |
|
125 | 125 |
{ |
126 | 126 |
BufferSourceContext *c = ctx->priv; |
127 | 127 |
char pix_fmt_str[128]; |
... | ... |
@@ -150,6 +200,69 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
150 | 150 |
return 0; |
151 | 151 |
} |
152 | 152 |
|
153 |
+#define OFFSET(x) offsetof(BufferSourceContext, x) |
|
154 |
+#define A AV_OPT_FLAG_AUDIO_PARAM |
|
155 |
+static const AVOption audio_options[] = { |
|
156 |
+ { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, A }, |
|
157 |
+ { "sample_rate", NULL, OFFSET(sample_rate), AV_OPT_TYPE_INT, { 0 }, 0, INT_MAX, A }, |
|
158 |
+ { "sample_fmt", NULL, OFFSET(sample_fmt_str), AV_OPT_TYPE_STRING, .flags = A }, |
|
159 |
+ { "channel_layout", NULL, OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A }, |
|
160 |
+ { NULL }, |
|
161 |
+}; |
|
162 |
+ |
|
163 |
+static const AVClass abuffer_class = { |
|
164 |
+ .class_name = "abuffer source", |
|
165 |
+ .item_name = av_default_item_name, |
|
166 |
+ .option = audio_options, |
|
167 |
+ .version = LIBAVUTIL_VERSION_INT, |
|
168 |
+}; |
|
169 |
+ |
|
170 |
+static av_cold int init_audio(AVFilterContext *ctx, const char *args, void *opaque) |
|
171 |
+{ |
|
172 |
+ BufferSourceContext *s = ctx->priv; |
|
173 |
+ int ret = 0; |
|
174 |
+ |
|
175 |
+ s->class = &abuffer_class; |
|
176 |
+ av_opt_set_defaults(s); |
|
177 |
+ |
|
178 |
+ if ((ret = av_set_options_string(s, args, "=", ":")) < 0) { |
|
179 |
+ av_log(ctx, AV_LOG_ERROR, "Error parsing options string: %s.\n", args); |
|
180 |
+ goto fail; |
|
181 |
+ } |
|
182 |
+ |
|
183 |
+ s->sample_fmt = av_get_sample_fmt(s->sample_fmt_str); |
|
184 |
+ if (s->sample_fmt == AV_SAMPLE_FMT_NONE) { |
|
185 |
+ av_log(ctx, AV_LOG_ERROR, "Invalid sample format %s.\n", |
|
186 |
+ s->sample_fmt_str); |
|
187 |
+ ret = AVERROR(EINVAL); |
|
188 |
+ goto fail; |
|
189 |
+ } |
|
190 |
+ |
|
191 |
+ s->channel_layout = av_get_channel_layout(s->channel_layout_str); |
|
192 |
+ if (!s->channel_layout) { |
|
193 |
+ av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n", |
|
194 |
+ s->channel_layout_str); |
|
195 |
+ ret = AVERROR(EINVAL); |
|
196 |
+ goto fail; |
|
197 |
+ } |
|
198 |
+ |
|
199 |
+ if (!(s->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) { |
|
200 |
+ ret = AVERROR(ENOMEM); |
|
201 |
+ goto fail; |
|
202 |
+ } |
|
203 |
+ |
|
204 |
+ if (!s->time_base.num) |
|
205 |
+ s->time_base = (AVRational){1, s->sample_rate}; |
|
206 |
+ |
|
207 |
+ av_log(ctx, AV_LOG_VERBOSE, "tb:%d/%d samplefmt:%s samplerate: %d " |
|
208 |
+ "ch layout:%s\n", s->time_base.num, s->time_base.den, s->sample_fmt_str, |
|
209 |
+ s->sample_rate, s->channel_layout_str); |
|
210 |
+ |
|
211 |
+fail: |
|
212 |
+ av_opt_free(s); |
|
213 |
+ return ret; |
|
214 |
+} |
|
215 |
+ |
|
153 | 216 |
static av_cold void uninit(AVFilterContext *ctx) |
154 | 217 |
{ |
155 | 218 |
BufferSourceContext *s = ctx->priv; |
... | ... |
@@ -165,9 +278,29 @@ static av_cold void uninit(AVFilterContext *ctx) |
165 | 165 |
static int query_formats(AVFilterContext *ctx) |
166 | 166 |
{ |
167 | 167 |
BufferSourceContext *c = ctx->priv; |
168 |
- enum PixelFormat pix_fmts[] = { c->pix_fmt, PIX_FMT_NONE }; |
|
168 |
+ AVFilterChannelLayouts *channel_layouts = NULL; |
|
169 |
+ AVFilterFormats *formats = NULL; |
|
170 |
+ AVFilterFormats *samplerates = NULL; |
|
171 |
+ |
|
172 |
+ switch (ctx->outputs[0]->type) { |
|
173 |
+ case AVMEDIA_TYPE_VIDEO: |
|
174 |
+ avfilter_add_format(&formats, c->pix_fmt); |
|
175 |
+ avfilter_set_common_formats(ctx, formats); |
|
176 |
+ break; |
|
177 |
+ case AVMEDIA_TYPE_AUDIO: |
|
178 |
+ avfilter_add_format(&formats, c->sample_fmt); |
|
179 |
+ avfilter_set_common_formats(ctx, formats); |
|
180 |
+ |
|
181 |
+ avfilter_add_format(&samplerates, c->sample_rate); |
|
182 |
+ ff_set_common_samplerates(ctx, samplerates); |
|
183 |
+ |
|
184 |
+ ff_add_channel_layout(&channel_layouts, c->channel_layout); |
|
185 |
+ ff_set_common_channel_layouts(ctx, channel_layouts); |
|
186 |
+ break; |
|
187 |
+ default: |
|
188 |
+ return AVERROR(EINVAL); |
|
189 |
+ } |
|
169 | 190 |
|
170 |
- avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); |
|
171 | 191 |
return 0; |
172 | 192 |
} |
173 | 193 |
|
... | ... |
@@ -175,11 +308,21 @@ static int config_props(AVFilterLink *link) |
175 | 175 |
{ |
176 | 176 |
BufferSourceContext *c = link->src->priv; |
177 | 177 |
|
178 |
- link->w = c->w; |
|
179 |
- link->h = c->h; |
|
180 |
- link->sample_aspect_ratio = c->pixel_aspect; |
|
181 |
- link->time_base = c->time_base; |
|
178 |
+ switch (link->type) { |
|
179 |
+ case AVMEDIA_TYPE_VIDEO: |
|
180 |
+ link->w = c->w; |
|
181 |
+ link->h = c->h; |
|
182 |
+ link->sample_aspect_ratio = c->pixel_aspect; |
|
183 |
+ break; |
|
184 |
+ case AVMEDIA_TYPE_AUDIO: |
|
185 |
+ link->channel_layout = c->channel_layout; |
|
186 |
+ link->sample_rate = c->sample_rate; |
|
187 |
+ break; |
|
188 |
+ default: |
|
189 |
+ return AVERROR(EINVAL); |
|
190 |
+ } |
|
182 | 191 |
|
192 |
+ link->time_base = c->time_base; |
|
183 | 193 |
return 0; |
184 | 194 |
} |
185 | 195 |
|
... | ... |
@@ -195,9 +338,19 @@ static int request_frame(AVFilterLink *link) |
195 | 195 |
} |
196 | 196 |
av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); |
197 | 197 |
|
198 |
- avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0)); |
|
199 |
- avfilter_draw_slice(link, 0, link->h, 1); |
|
200 |
- avfilter_end_frame(link); |
|
198 |
+ switch (link->type) { |
|
199 |
+ case AVMEDIA_TYPE_VIDEO: |
|
200 |
+ avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0)); |
|
201 |
+ avfilter_draw_slice(link, 0, link->h, 1); |
|
202 |
+ avfilter_end_frame(link); |
|
203 |
+ break; |
|
204 |
+ case AVMEDIA_TYPE_AUDIO: |
|
205 |
+ ff_filter_samples(link, avfilter_ref_buffer(buf, ~0)); |
|
206 |
+ break; |
|
207 |
+ default: |
|
208 |
+ return AVERROR(EINVAL); |
|
209 |
+ } |
|
210 |
+ |
|
201 | 211 |
avfilter_unref_buffer(buf); |
202 | 212 |
|
203 | 213 |
return 0; |
... | ... |
@@ -218,7 +371,7 @@ AVFilter avfilter_vsrc_buffer = { |
218 | 218 |
.priv_size = sizeof(BufferSourceContext), |
219 | 219 |
.query_formats = query_formats, |
220 | 220 |
|
221 |
- .init = init, |
|
221 |
+ .init = init_video, |
|
222 | 222 |
.uninit = uninit, |
223 | 223 |
|
224 | 224 |
.inputs = (AVFilterPad[]) {{ .name = NULL }}, |
... | ... |
@@ -229,3 +382,21 @@ AVFilter avfilter_vsrc_buffer = { |
229 | 229 |
.config_props = config_props, }, |
230 | 230 |
{ .name = NULL}}, |
231 | 231 |
}; |
232 |
+ |
|
233 |
+AVFilter avfilter_asrc_abuffer = { |
|
234 |
+ .name = "abuffer", |
|
235 |
+ .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."), |
|
236 |
+ .priv_size = sizeof(BufferSourceContext), |
|
237 |
+ .query_formats = query_formats, |
|
238 |
+ |
|
239 |
+ .init = init_audio, |
|
240 |
+ .uninit = uninit, |
|
241 |
+ |
|
242 |
+ .inputs = (AVFilterPad[]) {{ .name = NULL }}, |
|
243 |
+ .outputs = (AVFilterPad[]) {{ .name = "default", |
|
244 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
245 |
+ .request_frame = request_frame, |
|
246 |
+ .poll_frame = poll_frame, |
|
247 |
+ .config_props = config_props, }, |
|
248 |
+ { .name = NULL}}, |
|
249 |
+}; |