| ... | ... |
@@ -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 */ |