| @@ -55,6 +55,13 @@ typedef struct { · 54 unmodified lines |
| 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) · 124 unmodified lines |
| 185 | 192 | |
| 186 | 193 | avfilter_unref_buffer(movie->picref); |
| 187 | 194 | av_freep(&movie->frame); |
| 195 | + |
| 196 | + avfilter_unref_buffer(movie->samplesref); |
| 197 | + av_freep(&movie->samples_buf); |
| 188 | 198 | } |
| 189 | 199 | |
| 200 | +#if CONFIG_MOVIE_FILTER |
| 201 | + |
| 190 | 202 | static av_cold int movie_init(AVFilterContext *ctx, const char *args, void *opaque) |
| 191 | 203 | { |
| 192 | 204 | MovieContext *movie = ctx->priv; |
| @@ -317,3 +329,148 @@ AVFilter avfilter_vsrc_movie = { · 124 unmodified lines |
| 317 | 329 | .config_props = movie_config_output_props, }, |
| 318 | 330 | { .name = NULL}}, |
| 319 | 331 | }; |
| 332 | + |
| 333 | +#endif /* CONFIG_MOVIE_FILTER */ |
| 334 | + |
| 335 | +#if CONFIG_AMOVIE_FILTER |
| 336 | + |
| 337 | +static av_cold int amovie_init(AVFilterContext *ctx, const char *args, void *opaque) |
| 338 | +{ |
| 339 | + MovieContext *movie = ctx->priv; |
| 340 | + int ret; |
| 341 | + |
| 342 | + if ((ret = movie_common_init(ctx, args, opaque, AVMEDIA_TYPE_AUDIO)) < 0) |
| 343 | + return ret; |
| 344 | + |
| 345 | + movie->bps = av_get_bytes_per_sample(movie->codec_ctx->sample_fmt); |
| 346 | + return 0; |
| 347 | +} |
| 348 | + |
| 349 | +static int amovie_query_formats(AVFilterContext *ctx) |
| 350 | +{ |
| 351 | + MovieContext *movie = ctx->priv; |
| 352 | + AVCodecContext *c = movie->codec_ctx; |
| 353 | + |
| 354 | + enum AVSampleFormat sample_fmts[] = { c->sample_fmt, -1 }; |
| 355 | + int packing_fmts[] = { AVFILTER_PACKED, -1 }; |
| 356 | + int64_t chlayouts[] = { c->channel_layout, -1 }; |
| 357 | + |
| 358 | + avfilter_set_common_sample_formats (ctx, avfilter_make_format_list(sample_fmts)); |
| 359 | + avfilter_set_common_packing_formats(ctx, avfilter_make_format_list(packing_fmts)); |
| 360 | + avfilter_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts)); |
| 361 | + |
| 362 | + return 0; |
| 363 | +} |
| 364 | + |
| 365 | +static int amovie_config_output_props(AVFilterLink *outlink) |
| 366 | +{ |
| 367 | + MovieContext *movie = outlink->src->priv; |
| 368 | + AVCodecContext *c = movie->codec_ctx; |
| 369 | + |
| 370 | + outlink->sample_rate = c->sample_rate; |
| 371 | + outlink->time_base = movie->format_ctx->streams[movie->stream_index]->time_base; |
| 372 | + |
| 373 | + return 0; |
| 374 | +} |
| 375 | + |
| 376 | +static int amovie_get_samples(AVFilterLink *outlink) |
| 377 | +{ |
| 378 | + MovieContext *movie = outlink->src->priv; |
| 379 | + AVPacket pkt; |
| 380 | + int ret, samples_size, decoded_data_size; |
| 381 | + |
| 382 | + if (!movie->pkt.size && movie->is_done == 1) |
| 383 | + return AVERROR_EOF; |
| 384 | + |
| 385 | + /* check for another frame, in case the previous one was completely consumed */ |
| 386 | + if (!movie->pkt.size) { |
| 387 | + while ((ret = av_read_frame(movie->format_ctx, &pkt)) >= 0) { |
| 388 | + // Is this a packet from the selected stream? |
| 389 | + if (pkt.stream_index != movie->stream_index) { |
| 390 | + av_free_packet(&pkt); |
| 391 | + continue; |
| 392 | + } else { |
| 393 | + movie->pkt0 = movie->pkt = pkt; |
| 394 | + break; |
| 395 | + } |
| 396 | + } |
| 397 | + |
| 398 | + if (ret == AVERROR_EOF) { |
| 399 | + movie->is_done = 1; |
| 400 | + return ret; |
| 401 | + } |
| 402 | + } |
| 403 | + |
| 404 | + /* reallocate the buffer for the decoded samples, if necessary */ |
| 405 | + samples_size = |
| 406 | + FFMAX(movie->pkt.size*sizeof(movie->bps), AVCODEC_MAX_AUDIO_FRAME_SIZE); |
| 407 | + if (samples_size > movie->samples_buf_size) { |
| 408 | + movie->samples_buf = av_fast_realloc(movie->samples_buf, |
| 409 | + &movie->samples_buf_size, samples_size); |
| 410 | + if (!movie->samples_buf) |
| 411 | + return AVERROR(ENOMEM); |
| 412 | + } |
| 413 | + decoded_data_size = movie->samples_buf_size; |
| 414 | + |
| 415 | + /* decode and update the movie pkt */ |
| 416 | + ret = avcodec_decode_audio3(movie->codec_ctx, movie->samples_buf, |
| 417 | + &decoded_data_size, &movie->pkt); |
| 418 | + if (ret < 0) |
| 419 | + return ret; |
| 420 | + movie->pkt.data += ret; |
| 421 | + movie->pkt.size -= ret; |
| 422 | + |
| 423 | + /* wrap the decoded data in a samplesref */ |
| 424 | + if (decoded_data_size > 0) { |
| 425 | + int nb_samples = decoded_data_size / movie->bps / movie->codec_ctx->channels; |
| 426 | + movie->samplesref = |
| 427 | + avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, |
| 428 | + movie->codec_ctx->sample_fmt, nb_samples, |
| 429 | + movie->codec_ctx->channel_layout, 0); |
| 430 | + memcpy(movie->samplesref->data[0], movie->samples_buf, decoded_data_size); |
| 431 | + movie->samplesref->pts = movie->pkt.pts; |
| 432 | + movie->samplesref->pos = movie->pkt.pos; |
| 433 | + movie->samplesref->audio->sample_rate = movie->codec_ctx->sample_rate; |
| 434 | + } |
| 435 | + |
| 436 | + // We got it. Free the packet since we are returning |
| 437 | + if (movie->pkt.size <= 0) |
| 438 | + av_free_packet(&movie->pkt0); |
| 439 | + |
| 440 | + return 0; |
| 441 | +} |
| 442 | + |
| 443 | +static int amovie_request_frame(AVFilterLink *outlink) |
| 444 | +{ |
| 445 | + MovieContext *movie = outlink->src->priv; |
| 446 | + int ret; |
| 447 | + |
| 448 | + if (movie->is_done) |
| 449 | + return AVERROR_EOF; |
| 450 | + if ((ret = amovie_get_samples(outlink)) < 0) |
| 451 | + return ret; |
| 452 | + |
| 453 | + avfilter_filter_samples(outlink, avfilter_ref_buffer(movie->samplesref, ~0)); |
| 454 | + avfilter_unref_buffer(movie->samplesref); |
| 455 | + movie->samplesref = NULL; |
| 456 | + |
| 457 | + return 0; |
| 458 | +} |
| 459 | + |
| 460 | +AVFilter avfilter_asrc_amovie = { |
| 461 | + .name = "amovie", |
| 462 | + .description = NULL_IF_CONFIG_SMALL("Read audio from a movie source."), |
| 463 | + .priv_size = sizeof(MovieContext), |
| 464 | + .init = amovie_init, |
| 465 | + .uninit = movie_common_uninit, |
| 466 | + .query_formats = amovie_query_formats, |
| 467 | + |
| 468 | + .inputs = (AVFilterPad[]) {{ .name = NULL }}, |
| 469 | + .outputs = (AVFilterPad[]) {{ .name = "default", |
| 470 | + .type = AVMEDIA_TYPE_AUDIO, |
| 471 | + .request_frame = amovie_request_frame, |
| 472 | + .config_props = amovie_config_output_props, }, |
| 473 | + { .name = NULL}}, |
| 474 | +}; |
| 475 | + |
| 476 | +#endif /* CONFIG_AMOVIE_FILTER */ |