| @@ -55,6 +55,13 @@ typedef struct { · 54 unmodified lines |
| 55 | /* video-only fields */ | 55 | /* video-only fields */ |
| 56 | int w, h; | 56 | int w, h; |
| 57 | AVFilterBufferRef *picref; | 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 | } MovieContext; | 65 | } MovieContext; |
| 59 | | 66 | |
| 60 | #define OFFSET(x) offsetof(MovieContext, x) | 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 | avfilter_unref_buffer(movie->picref); | 193 | avfilter_unref_buffer(movie->picref); |
| 187 | av_freep(&movie->frame); | 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 | static av_cold int movie_init(AVFilterContext *ctx, const char *args, void *opaque) | 202 | static av_cold int movie_init(AVFilterContext *ctx, const char *args, void *opaque) |
| 191 | { | 203 | { |
| 192 | MovieContext *movie = ctx->priv; | 204 | MovieContext *movie = ctx->priv; |
| @@ -317,3 +329,148 @@ AVFilter avfilter_vsrc_movie = { · 124 unmodified lines |
| 317 | .config_props = movie_config_output_props, }, | 329 | .config_props = movie_config_output_props, }, |
| 318 | { .name = NULL}}, | 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 */ |