The default behavior of the mediacodec decoder before this commit was to delay flushes until all pending hardware frames were returned to the decoder. This was useful for certain types of applications, but was unexpected behavior for others. The new default behavior with this commit is now to execute flushes immediately to invalidate all pending frames. The old behavior can be enabled by setting delay_flush=1. With the new behavior, video players implementing seek can simply call flush on the decoder without having to worry about whether they have one or more mediacodec frames still buffered in their rendering pipeline. Previously, all these frames had to be explictly freed (or rendered) before the seek/flush would execute. The new behavior matches the behavior of all other lavc decoders, reducing the amount of special casing required when using the mediacodec decoder.
Unified · Split
| @@ -15,6 +15,11 @@ libavutil: 2017-10-21 · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | API changes, most recent first: |
| 17 | 17 | |
| 18 | +2018-03-xx - xxxxxxx - lavc 58.14.100 - mediacodec.h | |
| 19 | + Change the default behavior of avcodec_flush() on mediacodec | |
| 20 | + video decoders. To restore the previous behavior, use the new | |
| 21 | + delay_flush=1 option. | |
| 22 | + | |
| 18 | 23 | 2018-03-xx - xxxxxxx - lavu 56.8.100 - frame.h |
| 19 | 24 | Add av_frame_new_side_data_from_buf(). |
| 20 | 25 | |
| @@ -91,7 +91,7 @@ int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render) · 90 unmodified lines | ||
| 91 | 91 | MediaCodecDecContext *ctx = buffer->ctx; |
| 92 | 92 | int released = atomic_fetch_add(&buffer->released, 1); |
| 93 | 93 | |
| 94 | − if (!released) { | |
| 94 | + if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) { | |
| 95 | 95 | return ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, render); |
| 96 | 96 | } |
| 97 | 97 | |
| @@ -41,10 +41,14 @@ · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | typedef struct MediaCodecH264DecContext { |
| 43 | 43 | |
| 44 | + AVClass *avclass; | |
| 45 | + | |
| 44 | 46 | MediaCodecDecContext *ctx; |
| 45 | 47 | |
| 46 | 48 | AVPacket buffered_pkt; |
| 47 | 49 | |
| 50 | + int delay_flush; | |
| 51 | + | |
| 48 | 52 | } MediaCodecH264DecContext; |
| 49 | 53 | |
| 50 | 54 | static av_cold int mediacodec_decode_close(AVCodecContext *avctx) |
| @@ -366,6 +370,8 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) · 315 unmodified lines | ||
| 366 | 370 | goto done; |
| 367 | 371 | } |
| 368 | 372 | |
| 373 | + s->ctx->delay_flush = s->delay_flush; | |
| 374 | + | |
| 369 | 375 | if ((ret = ff_mediacodec_dec_init(avctx, s->ctx, codec_mime, format)) < 0) { |
| 370 | 376 | s->ctx = NULL; |
| 371 | 377 | goto done; |
| @@ -485,12 +491,30 @@ static const AVCodecHWConfigInternal *mediacodec_hw_configs[] = { · 113 unmodified lines | ||
| 485 | 491 | NULL |
| 486 | 492 | }; |
| 487 | 493 | |
| 494 | +#define OFFSET(x) offsetof(MediaCodecH264DecContext, x) | |
| 495 | +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM | |
| 496 | +static const AVOption ff_mediacodec_vdec_options[] = { | |
| 497 | + { "delay_flush", "Delay flush until hw output buffers are returned to the decoder", | |
| 498 | + OFFSET(delay_flush), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD }, | |
| 499 | + { NULL } | |
| 500 | +}; | |
| 501 | + | |
| 502 | +#define DECLARE_MEDIACODEC_VCLASS(short_name) \ | |
| 503 | +static const AVClass ff_##short_name##_mediacodec_dec_class = { \ | |
| 504 | + .class_name = #short_name "_mediacodec", \ | |
| 505 | + .item_name = av_default_item_name, \ | |
| 506 | + .option = ff_mediacodec_vdec_options, \ | |
| 507 | + .version = LIBAVUTIL_VERSION_INT, \ | |
| 508 | +}; | |
| 509 | + | |
| 488 | 510 | #define DECLARE_MEDIACODEC_VDEC(short_name, full_name, codec_id, bsf) \ |
| 511 | +DECLARE_MEDIACODEC_VCLASS(short_name) \ | |
| 489 | 512 | AVCodec ff_##short_name##_mediacodec_decoder = { \ |
| 490 | 513 | .name = #short_name "_mediacodec", \ |
| 491 | 514 | .long_name = NULL_IF_CONFIG_SMALL(full_name " Android MediaCodec decoder"), \ |
| 492 | 515 | .type = AVMEDIA_TYPE_VIDEO, \ |
| 493 | 516 | .id = codec_id, \ |
| 517 | + .priv_class = &ff_##short_name##_mediacodec_dec_class, \ | |
| 494 | 518 | .priv_data_size = sizeof(MediaCodecH264DecContext), \ |
| 495 | 519 | .init = mediacodec_decode_init, \ |
| 496 | 520 | .receive_frame = mediacodec_receive_frame, \ |
| @@ -178,11 +178,12 @@ static void mediacodec_buffer_release(void *opaque, uint8_t *data) · 177 unmodified lines | ||
| 178 | 178 | MediaCodecDecContext *ctx = buffer->ctx; |
| 179 | 179 | int released = atomic_load(&buffer->released); |
| 180 | 180 | |
| 181 | − if (!released) { | |
| 181 | + if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) { | |
| 182 | 182 | ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, 0); |
| 183 | 183 | } |
| 184 | 184 | |
| 185 | − ff_mediacodec_dec_unref(ctx); | |
| 185 | + if (ctx->delay_flush) | |
| 186 | + ff_mediacodec_dec_unref(ctx); | |
| 186 | 187 | av_freep(&buffer); |
| 187 | 188 | } |
| 188 | 189 | |
| @@ -236,7 +237,9 @@ FF_ENABLE_DEPRECATION_WARNINGS · 47 unmodified lines | ||
| 236 | 237 | } |
| 237 | 238 | |
| 238 | 239 | buffer->ctx = s; |
| 239 | − ff_mediacodec_dec_ref(s); | |
| 240 | + buffer->serial = atomic_load(&s->serial); | |
| 241 | + if (s->delay_flush) | |
| 242 | + ff_mediacodec_dec_ref(s); | |
| 240 | 243 | |
| 241 | 244 | buffer->index = index; |
| 242 | 245 | buffer->pts = info->presentationTimeUs; |
| @@ -425,6 +428,7 @@ static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContex · 182 unmodified lines | ||
| 425 | 428 | s->draining = 0; |
| 426 | 429 | s->flushing = 0; |
| 427 | 430 | s->eos = 0; |
| 431 | + atomic_fetch_add(&s->serial, 1); | |
| 428 | 432 | |
| 429 | 433 | status = ff_AMediaCodec_flush(codec); |
| 430 | 434 | if (status < 0) { |
| @@ -449,6 +453,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, · 18 unmodified lines | ||
| 449 | 453 | }; |
| 450 | 454 | |
| 451 | 455 | atomic_init(&s->refcount, 1); |
| 456 | + atomic_init(&s->serial, 1); | |
| 452 | 457 | |
| 453 | 458 | pix_fmt = ff_get_format(avctx, pix_fmts); |
| 454 | 459 | if (pix_fmt == AV_PIX_FMT_MEDIACODEC) { |
| @@ -62,6 +62,9 @@ typedef struct MediaCodecDecContext { · 61 unmodified lines | ||
| 62 | 62 | |
| 63 | 63 | uint64_t output_buffer_count; |
| 64 | 64 | |
| 65 | + bool delay_flush; | |
| 66 | + atomic_int serial; | |
| 67 | + | |
| 65 | 68 | } MediaCodecDecContext; |
| 66 | 69 | |
| 67 | 70 | int ff_mediacodec_dec_init(AVCodecContext *avctx, |
| @@ -93,6 +96,7 @@ typedef struct MediaCodecBuffer { · 25 unmodified lines | ||
| 93 | 96 | ssize_t index; |
| 94 | 97 | int64_t pts; |
| 95 | 98 | atomic_int released; |
| 99 | + int serial; | |
| 96 | 100 | |
| 97 | 101 | } MediaCodecBuffer; |
| 98 | 102 | |
| @@ -28,8 +28,8 @@ · 27 unmodified lines | ||
| 28 | 28 | #include "libavutil/version.h" |
| 29 | 29 | |
| 30 | 30 | #define LIBAVCODEC_VERSION_MAJOR 58 |
| 31 | −#define LIBAVCODEC_VERSION_MINOR 13 | |
| 32 | −#define LIBAVCODEC_VERSION_MICRO 102 | |
| 31 | +#define LIBAVCODEC_VERSION_MINOR 14 | |
| 32 | +#define LIBAVCODEC_VERSION_MICRO 100 | |
| 33 | 33 | |
| 34 | 34 | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ |
| 35 | 35 | LIBAVCODEC_VERSION_MINOR, \ |