diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c index cb1151a195..363e12427e 100644 --- a/libavcodec/mediacodecdec.c +++ b/libavcodec/mediacodecdec.c @@ -25,7 +25,6 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" -#include "libavutil/fifo.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" #include "libavutil/pixfmt.h" @@ -43,8 +42,6 @@ typedef struct MediaCodecH264DecContext { MediaCodecDecContext *ctx; - AVFifoBuffer *fifo; - AVPacket buffered_pkt; } MediaCodecH264DecContext; @@ -56,8 +53,6 @@ static av_cold int mediacodec_decode_close(AVCodecContext *avctx) ff_mediacodec_dec_close(avctx, s->ctx); s->ctx = NULL; - av_fifo_free(s->fifo); - av_packet_unref(&s->buffered_pkt); return 0; @@ -400,12 +395,6 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_INFO, "MediaCodec started successfully, ret = %d\n", ret); - s->fifo = av_fifo_alloc(sizeof(AVPacket)); - if (!s->fifo) { - ret = AVERROR(ENOMEM); - goto done; - } - done: if (format) { ff_AMediaFormat_delete(format); @@ -418,13 +407,33 @@ done: return ret; } +static int mediacodec_send_receive(AVCodecContext *avctx, + MediaCodecH264DecContext *s, + AVFrame *frame, bool wait) +{ + int ret; + + /* send any pending data from buffered packet */ + while (s->buffered_pkt.size) { + ret = ff_mediacodec_dec_send(avctx, s->ctx, &s->buffered_pkt); + if (ret == AVERROR(EAGAIN)) + break; + else if (ret < 0) + return ret; + s->buffered_pkt.size -= ret; + s->buffered_pkt.data += ret; + if (s->buffered_pkt.size <= 0) + av_packet_unref(&s->buffered_pkt); + } + + /* check for new frame */ + return ff_mediacodec_dec_receive(avctx, s->ctx, frame, wait); +} + static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) { MediaCodecH264DecContext *s = avctx->priv_data; int ret; - int got_frame = 0; - int is_eof = 0; - AVPacket pkt = { 0 }; /* * MediaCodec.flush() discards both input and output buffers, thus we @@ -452,74 +461,34 @@ static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) } } - ret = ff_decode_get_packet(avctx, &pkt); - if (ret == AVERROR_EOF) - is_eof = 1; - else if (ret == AVERROR(EAGAIN)) - ; /* no input packet, but fallthrough to check for pending frames */ - else if (ret < 0) + /* flush buffered packet and check for new frame */ + ret = mediacodec_send_receive(avctx, s, frame, false); + if (ret != AVERROR(EAGAIN)) return ret; - /* buffer the input packet */ - if (pkt.size) { - if (av_fifo_space(s->fifo) < sizeof(pkt)) { - ret = av_fifo_realloc2(s->fifo, - av_fifo_size(s->fifo) + sizeof(pkt)); - if (ret < 0) { - av_packet_unref(&pkt); - return ret; - } - } - av_fifo_generic_write(s->fifo, &pkt, sizeof(pkt), NULL); - } - - /* process buffered data */ - while (!got_frame) { - /* prepare the input data */ - if (s->buffered_pkt.size <= 0) { - av_packet_unref(&s->buffered_pkt); - - /* no more data */ - if (av_fifo_size(s->fifo) < sizeof(AVPacket)) { - AVPacket null_pkt = { 0 }; - if (is_eof) { - ret = ff_mediacodec_dec_decode(avctx, s->ctx, frame, - &got_frame, &null_pkt); - if (ret < 0) - return ret; - else if (got_frame) - return 0; - else - return AVERROR_EOF; - } - return AVERROR(EAGAIN); - } - - av_fifo_generic_read(s->fifo, &s->buffered_pkt, sizeof(s->buffered_pkt), NULL); - } + /* skip fetching new packet if we still have one buffered */ + if (s->buffered_pkt.size > 0) + return AVERROR(EAGAIN); - ret = ff_mediacodec_dec_decode(avctx, s->ctx, frame, &got_frame, &s->buffered_pkt); + /* fetch new packet or eof */ + ret = ff_decode_get_packet(avctx, &s->buffered_pkt); + if (ret == AVERROR_EOF) { + AVPacket null_pkt = { 0 }; + ret = ff_mediacodec_dec_send(avctx, s->ctx, &null_pkt); if (ret < 0) return ret; - - s->buffered_pkt.size -= ret; - s->buffered_pkt.data += ret; } + else if (ret < 0) + return ret; - return 0; + /* crank decoder with new packet */ + return mediacodec_send_receive(avctx, s, frame, true); } static void mediacodec_decode_flush(AVCodecContext *avctx) { MediaCodecH264DecContext *s = avctx->priv_data; - while (av_fifo_size(s->fifo)) { - AVPacket pkt; - av_fifo_generic_read(s->fifo, &pkt, sizeof(pkt), NULL); - av_packet_unref(&pkt); - } - av_fifo_reset(s->fifo); - av_packet_unref(&s->buffered_pkt); ff_mediacodec_dec_flush(avctx, s->ctx); diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index a9147f3a08..b44abaef7f 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -555,23 +555,17 @@ fail: return ret; } -int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, - AVFrame *frame, int *got_frame, - AVPacket *pkt) +int ff_mediacodec_dec_send(AVCodecContext *avctx, MediaCodecDecContext *s, + AVPacket *pkt) { - int ret; int offset = 0; int need_draining = 0; uint8_t *data; ssize_t index; size_t size; FFAMediaCodec *codec = s->codec; - FFAMediaCodecBufferInfo info = { 0 }; - int status; - int64_t input_dequeue_timeout_us = INPUT_DEQUEUE_TIMEOUT_US; - int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US; if (s->flushing) { av_log(avctx, AV_LOG_ERROR, "Decoder is flushing and cannot accept new buffer " @@ -584,13 +578,14 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, } if (s->draining && s->eos) { - return 0; + return AVERROR_EOF; } while (offset < pkt->size || (need_draining && !s->draining)) { index = ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us); if (ff_AMediaCodec_infoTryAgainLater(codec, index)) { + av_log(avctx, AV_LOG_TRACE, "Failed to dequeue input buffer, try again later..\n"); break; } @@ -621,13 +616,15 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, return AVERROR_EXTERNAL; } + av_log(avctx, AV_LOG_TRACE, "Queued input buffer %zd" + " size=%zd ts=%" PRIi64 "\n", index, size, pts); + s->draining = 1; break; } else { int64_t pts = pkt->pts; size = FFMIN(pkt->size - offset, size); - memcpy(data, pkt->data + offset, size); offset += size; @@ -643,11 +640,32 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, } } - if (need_draining || s->draining) { + if (offset == 0) + return AVERROR(EAGAIN); + return offset; +} + +int ff_mediacodec_dec_receive(AVCodecContext *avctx, MediaCodecDecContext *s, + AVFrame *frame, bool wait) +{ + int ret; + uint8_t *data; + ssize_t index; + size_t size; + FFAMediaCodec *codec = s->codec; + FFAMediaCodecBufferInfo info = { 0 }; + int status; + int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US; + + if (s->draining && s->eos) { + return AVERROR_EOF; + } + + if (s->draining) { /* If the codec is flushing or need to be flushed, block for a fair * amount of time to ensure we got a frame */ output_dequeue_timeout_us = OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US; - } else if (s->output_buffer_count == 0) { + } else if (s->output_buffer_count == 0 || !wait) { /* If the codec hasn't produced any frames, do not block so we * can push data to it as fast as possible, and get the first * frame */ @@ -656,9 +674,7 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, index = ff_AMediaCodec_dequeueOutputBuffer(codec, &info, output_dequeue_timeout_us); if (index >= 0) { - int ret; - - av_log(avctx, AV_LOG_DEBUG, "Got output buffer %zd" + av_log(avctx, AV_LOG_TRACE, "Got output buffer %zd" " offset=%" PRIi32 " size=%" PRIi32 " ts=%" PRIi64 " flags=%" PRIu32 "\n", index, info.offset, info.size, info.presentationTimeUs, info.flags); @@ -686,8 +702,8 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, } } - *got_frame = 1; s->output_buffer_count++; + return 0; } else { status = ff_AMediaCodec_releaseOutputBuffer(codec, index, 0); if (status < 0) { @@ -737,7 +753,7 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, return AVERROR_EXTERNAL; } - return offset; + return AVERROR(EAGAIN); } int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s) diff --git a/libavcodec/mediacodecdec_common.h b/libavcodec/mediacodecdec_common.h index 10f38277b5..32d16d3e3a 100644 --- a/libavcodec/mediacodecdec_common.h +++ b/libavcodec/mediacodecdec_common.h @@ -25,6 +25,7 @@ #include #include +#include #include #include "libavutil/frame.h" @@ -69,11 +70,14 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, const char *mime, FFAMediaFormat *format); -int ff_mediacodec_dec_decode(AVCodecContext *avctx, - MediaCodecDecContext *s, - AVFrame *frame, - int *got_frame, - AVPacket *pkt); +int ff_mediacodec_dec_send(AVCodecContext *avctx, + MediaCodecDecContext *s, + AVPacket *pkt); + +int ff_mediacodec_dec_receive(AVCodecContext *avctx, + MediaCodecDecContext *s, + AVFrame *frame, + bool wait); int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s);