... | ... |
@@ -1505,6 +1505,7 @@ udp_protocol_deps="network" |
1505 | 1505 |
# filters |
1506 | 1506 |
abuffer_filter_deps="strtok_r" |
1507 | 1507 |
aformat_filter_deps="strtok_r" |
1508 |
+amovie_filter_deps="avcodec avformat" |
|
1508 | 1509 |
blackframe_filter_deps="gpl" |
1509 | 1510 |
boxblur_filter_deps="gpl" |
1510 | 1511 |
cropdetect_filter_deps="gpl" |
... | ... |
@@ -239,6 +239,38 @@ equivalent to: |
239 | 239 |
abuffer=44100:1:3:1 |
240 | 240 |
@end example |
241 | 241 |
|
242 |
+@section amovie |
|
243 |
+ |
|
244 |
+Read an audio stream from a movie container. |
|
245 |
+ |
|
246 |
+It accepts the syntax: @var{movie_name}[:@var{options}] where |
|
247 |
+@var{movie_name} is the name of the resource to read (not necessarily |
|
248 |
+a file but also a device or a stream accessed through some protocol), |
|
249 |
+and @var{options} is an optional sequence of @var{key}=@var{value} |
|
250 |
+pairs, separated by ":". |
|
251 |
+ |
|
252 |
+The description of the accepted options follows. |
|
253 |
+ |
|
254 |
+@table @option |
|
255 |
+ |
|
256 |
+@item format_name, f |
|
257 |
+Specify the format assumed for the movie to read, and can be either |
|
258 |
+the name of a container or an input device. If not specified the |
|
259 |
+format is guessed from @var{movie_name} or by probing. |
|
260 |
+ |
|
261 |
+@item seek_point, sp |
|
262 |
+Specify the seek point in seconds, the frames will be output |
|
263 |
+starting from this seek point, the parameter is evaluated with |
|
264 |
+@code{av_strtod} so the numerical value may be suffixed by an IS |
|
265 |
+postfix. Default value is "0". |
|
266 |
+ |
|
267 |
+@item stream_index, si |
|
268 |
+Specify the index of the audio stream to read. If the value is -1, |
|
269 |
+the best suited audio stream will be automatically selected. Default |
|
270 |
+value is "-1". |
|
271 |
+ |
|
272 |
+@end table |
|
273 |
+ |
|
242 | 274 |
@section anullsrc |
243 | 275 |
|
244 | 276 |
Null audio source, never return audio frames. It is mainly useful as a |
... | ... |
@@ -2,6 +2,7 @@ include $(SUBDIR)../config.mak |
2 | 2 |
|
3 | 3 |
NAME = avfilter |
4 | 4 |
FFLIBS = avutil |
5 |
+FFLIBS-$(CONFIG_AMOVIE_FILTER) += avformat avcodec |
|
5 | 6 |
FFLIBS-$(CONFIG_ARESAMPLE_FILTER) += avcodec |
6 | 7 |
FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec |
7 | 8 |
FFLIBS-$(CONFIG_SCALE_FILTER) += swscale |
... | ... |
@@ -25,6 +26,7 @@ OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o |
25 | 25 |
OBJS-$(CONFIG_ASHOWINFO_FILTER) += af_ashowinfo.o |
26 | 26 |
|
27 | 27 |
OBJS-$(CONFIG_ABUFFER_FILTER) += asrc_abuffer.o |
28 |
+OBJS-$(CONFIG_AMOVIE_FILTER) += src_movie.o |
|
28 | 29 |
OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o |
29 | 30 |
|
30 | 31 |
OBJS-$(CONFIG_ABUFFERSINK_FILTER) += asink_abuffer.o |
... | ... |
@@ -40,6 +40,7 @@ void avfilter_register_all(void) |
40 | 40 |
REGISTER_FILTER (ASHOWINFO, ashowinfo, af); |
41 | 41 |
|
42 | 42 |
REGISTER_FILTER (ABUFFER, abuffer, asrc); |
43 |
+ REGISTER_FILTER (AMOVIE, amovie, asrc); |
|
43 | 44 |
REGISTER_FILTER (ANULLSRC, anullsrc, asrc); |
44 | 45 |
|
45 | 46 |
REGISTER_FILTER (ABUFFERSINK, abuffersink, asink); |
... | ... |
@@ -29,8 +29,8 @@ |
29 | 29 |
#include "libavutil/rational.h" |
30 | 30 |
|
31 | 31 |
#define LIBAVFILTER_VERSION_MAJOR 2 |
32 |
-#define LIBAVFILTER_VERSION_MINOR 34 |
|
33 |
-#define LIBAVFILTER_VERSION_MICRO 2 |
|
32 |
+#define LIBAVFILTER_VERSION_MINOR 35 |
|
33 |
+#define LIBAVFILTER_VERSION_MICRO 0 |
|
34 | 34 |
|
35 | 35 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
36 | 36 |
LIBAVFILTER_VERSION_MINOR, \ |
... | ... |
@@ -55,6 +55,13 @@ typedef struct { |
55 | 55 |
/* video-only fields */ |
56 | 56 |
int w, h; |
57 | 57 |
AVFilterBufferRef *picref; |
58 |
+ |
|
59 |
+ /* audio-only fields */ |
|
60 |
+ void *samples_buf; |
|
61 |
+ int samples_buf_size; |
|
62 |
+ int bps; ///< bytes per sample |
|
63 |
+ AVPacket pkt, pkt0; |
|
64 |
+ AVFilterBufferRef *samplesref; |
|
58 | 65 |
} MovieContext; |
59 | 66 |
|
60 | 67 |
#define OFFSET(x) offsetof(MovieContext, x) |
... | ... |
@@ -185,8 +192,13 @@ static av_cold void movie_common_uninit(AVFilterContext *ctx) |
185 | 185 |
|
186 | 186 |
avfilter_unref_buffer(movie->picref); |
187 | 187 |
av_freep(&movie->frame); |
188 |
+ |
|
189 |
+ avfilter_unref_buffer(movie->samplesref); |
|
190 |
+ av_freep(&movie->samples_buf); |
|
188 | 191 |
} |
189 | 192 |
|
193 |
+#if CONFIG_MOVIE_FILTER |
|
194 |
+ |
|
190 | 195 |
static av_cold int movie_init(AVFilterContext *ctx, const char *args, void *opaque) |
191 | 196 |
{ |
192 | 197 |
MovieContext *movie = ctx->priv; |
... | ... |
@@ -317,3 +329,148 @@ AVFilter avfilter_vsrc_movie = { |
317 | 317 |
.config_props = movie_config_output_props, }, |
318 | 318 |
{ .name = NULL}}, |
319 | 319 |
}; |
320 |
+ |
|
321 |
+#endif /* CONFIG_MOVIE_FILTER */ |
|
322 |
+ |
|
323 |
+#if CONFIG_AMOVIE_FILTER |
|
324 |
+ |
|
325 |
+static av_cold int amovie_init(AVFilterContext *ctx, const char *args, void *opaque) |
|
326 |
+{ |
|
327 |
+ MovieContext *movie = ctx->priv; |
|
328 |
+ int ret; |
|
329 |
+ |
|
330 |
+ if ((ret = movie_common_init(ctx, args, opaque, AVMEDIA_TYPE_AUDIO)) < 0) |
|
331 |
+ return ret; |
|
332 |
+ |
|
333 |
+ movie->bps = av_get_bytes_per_sample(movie->codec_ctx->sample_fmt); |
|
334 |
+ return 0; |
|
335 |
+} |
|
336 |
+ |
|
337 |
+static int amovie_query_formats(AVFilterContext *ctx) |
|
338 |
+{ |
|
339 |
+ MovieContext *movie = ctx->priv; |
|
340 |
+ AVCodecContext *c = movie->codec_ctx; |
|
341 |
+ |
|
342 |
+ enum AVSampleFormat sample_fmts[] = { c->sample_fmt, -1 }; |
|
343 |
+ int packing_fmts[] = { AVFILTER_PACKED, -1 }; |
|
344 |
+ int64_t chlayouts[] = { c->channel_layout, -1 }; |
|
345 |
+ |
|
346 |
+ avfilter_set_common_sample_formats (ctx, avfilter_make_format_list(sample_fmts)); |
|
347 |
+ avfilter_set_common_packing_formats(ctx, avfilter_make_format_list(packing_fmts)); |
|
348 |
+ avfilter_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts)); |
|
349 |
+ |
|
350 |
+ return 0; |
|
351 |
+} |
|
352 |
+ |
|
353 |
+static int amovie_config_output_props(AVFilterLink *outlink) |
|
354 |
+{ |
|
355 |
+ MovieContext *movie = outlink->src->priv; |
|
356 |
+ AVCodecContext *c = movie->codec_ctx; |
|
357 |
+ |
|
358 |
+ outlink->sample_rate = c->sample_rate; |
|
359 |
+ outlink->time_base = movie->format_ctx->streams[movie->stream_index]->time_base; |
|
360 |
+ |
|
361 |
+ return 0; |
|
362 |
+} |
|
363 |
+ |
|
364 |
+static int amovie_get_samples(AVFilterLink *outlink) |
|
365 |
+{ |
|
366 |
+ MovieContext *movie = outlink->src->priv; |
|
367 |
+ AVPacket pkt; |
|
368 |
+ int ret, samples_size, decoded_data_size; |
|
369 |
+ |
|
370 |
+ if (!movie->pkt.size && movie->is_done == 1) |
|
371 |
+ return AVERROR_EOF; |
|
372 |
+ |
|
373 |
+ /* check for another frame, in case the previous one was completely consumed */ |
|
374 |
+ if (!movie->pkt.size) { |
|
375 |
+ while ((ret = av_read_frame(movie->format_ctx, &pkt)) >= 0) { |
|
376 |
+ // Is this a packet from the selected stream? |
|
377 |
+ if (pkt.stream_index != movie->stream_index) { |
|
378 |
+ av_free_packet(&pkt); |
|
379 |
+ continue; |
|
380 |
+ } else { |
|
381 |
+ movie->pkt0 = movie->pkt = pkt; |
|
382 |
+ break; |
|
383 |
+ } |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ if (ret == AVERROR_EOF) { |
|
387 |
+ movie->is_done = 1; |
|
388 |
+ return ret; |
|
389 |
+ } |
|
390 |
+ } |
|
391 |
+ |
|
392 |
+ /* reallocate the buffer for the decoded samples, if necessary */ |
|
393 |
+ samples_size = |
|
394 |
+ FFMAX(movie->pkt.size*sizeof(movie->bps), AVCODEC_MAX_AUDIO_FRAME_SIZE); |
|
395 |
+ if (samples_size > movie->samples_buf_size) { |
|
396 |
+ movie->samples_buf = av_fast_realloc(movie->samples_buf, |
|
397 |
+ &movie->samples_buf_size, samples_size); |
|
398 |
+ if (!movie->samples_buf) |
|
399 |
+ return AVERROR(ENOMEM); |
|
400 |
+ } |
|
401 |
+ decoded_data_size = movie->samples_buf_size; |
|
402 |
+ |
|
403 |
+ /* decode and update the movie pkt */ |
|
404 |
+ ret = avcodec_decode_audio3(movie->codec_ctx, movie->samples_buf, |
|
405 |
+ &decoded_data_size, &movie->pkt); |
|
406 |
+ if (ret < 0) |
|
407 |
+ return ret; |
|
408 |
+ movie->pkt.data += ret; |
|
409 |
+ movie->pkt.size -= ret; |
|
410 |
+ |
|
411 |
+ /* wrap the decoded data in a samplesref */ |
|
412 |
+ if (decoded_data_size > 0) { |
|
413 |
+ int nb_samples = decoded_data_size / movie->bps / movie->codec_ctx->channels; |
|
414 |
+ movie->samplesref = |
|
415 |
+ avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, |
|
416 |
+ movie->codec_ctx->sample_fmt, nb_samples, |
|
417 |
+ movie->codec_ctx->channel_layout, 0); |
|
418 |
+ memcpy(movie->samplesref->data[0], movie->samples_buf, decoded_data_size); |
|
419 |
+ movie->samplesref->pts = movie->pkt.pts; |
|
420 |
+ movie->samplesref->pos = movie->pkt.pos; |
|
421 |
+ movie->samplesref->audio->sample_rate = movie->codec_ctx->sample_rate; |
|
422 |
+ } |
|
423 |
+ |
|
424 |
+ // We got it. Free the packet since we are returning |
|
425 |
+ if (movie->pkt.size <= 0) |
|
426 |
+ av_free_packet(&movie->pkt0); |
|
427 |
+ |
|
428 |
+ return 0; |
|
429 |
+} |
|
430 |
+ |
|
431 |
+static int amovie_request_frame(AVFilterLink *outlink) |
|
432 |
+{ |
|
433 |
+ MovieContext *movie = outlink->src->priv; |
|
434 |
+ int ret; |
|
435 |
+ |
|
436 |
+ if (movie->is_done) |
|
437 |
+ return AVERROR_EOF; |
|
438 |
+ if ((ret = amovie_get_samples(outlink)) < 0) |
|
439 |
+ return ret; |
|
440 |
+ |
|
441 |
+ avfilter_filter_samples(outlink, avfilter_ref_buffer(movie->samplesref, ~0)); |
|
442 |
+ avfilter_unref_buffer(movie->samplesref); |
|
443 |
+ movie->samplesref = NULL; |
|
444 |
+ |
|
445 |
+ return 0; |
|
446 |
+} |
|
447 |
+ |
|
448 |
+AVFilter avfilter_asrc_amovie = { |
|
449 |
+ .name = "amovie", |
|
450 |
+ .description = NULL_IF_CONFIG_SMALL("Read audio from a movie source."), |
|
451 |
+ .priv_size = sizeof(MovieContext), |
|
452 |
+ .init = amovie_init, |
|
453 |
+ .uninit = movie_common_uninit, |
|
454 |
+ .query_formats = amovie_query_formats, |
|
455 |
+ |
|
456 |
+ .inputs = (AVFilterPad[]) {{ .name = NULL }}, |
|
457 |
+ .outputs = (AVFilterPad[]) {{ .name = "default", |
|
458 |
+ .type = AVMEDIA_TYPE_AUDIO, |
|
459 |
+ .request_frame = amovie_request_frame, |
|
460 |
+ .config_props = amovie_config_output_props, }, |
|
461 |
+ { .name = NULL}}, |
|
462 |
+}; |
|
463 |
+ |
|
464 |
+#endif /* CONFIG_AMOVIE_FILTER */ |