From: Aman Gupta <a...@tmm1.net> This is a hacky work-around for #7092, where the lavc h264 parser splits coded fields into separate video packets, only one of which has a PTS set.
The MediaCodec#queueInputBuffer API expects a PTS along with incoming video packets, and breaks badly when the PTS is missing or incorrect (previously it would be passed in as AV_NOPTS_VALUE, but the same breakage happens if you pass in 0 instead). Since it seems there's no easy fix for #7092, this patch stores the previous PTS in the decoder context and re-uses it for the second packet. This emulates the behavior of other Android video players that don't split the coded fields, and pass them as a single buffer with the same timestamp. --- libavcodec/mediacodecdec_common.c | 26 +++++++++++++++----------- libavcodec/mediacodecdec_common.h | 2 ++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index e31adb487c..16112b186d 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -450,6 +450,7 @@ static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContex s->eos = 0; atomic_fetch_add(&s->serial, 1); atomic_init(&s->hw_buffer_count, 0); + s->last_pts = AV_NOPTS_VALUE; status = ff_AMediaCodec_flush(codec); if (status < 0) { @@ -477,6 +478,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, atomic_init(&s->refcount, 1); atomic_init(&s->hw_buffer_count, 0); atomic_init(&s->serial, 1); + s->last_pts = AV_NOPTS_VALUE; pix_fmt = ff_get_format(avctx, pix_fmts); if (pix_fmt == AV_PIX_FMT_MEDIACODEC) { @@ -571,6 +573,7 @@ int ff_mediacodec_dec_send(AVCodecContext *avctx, MediaCodecDecContext *s, FFAMediaCodec *codec = s->codec; int status; int64_t input_dequeue_timeout_us = INPUT_DEQUEUE_TIMEOUT_US; + int64_t pts; if (s->flushing) { av_log(avctx, AV_LOG_ERROR, "Decoder is flushing and cannot accept new buffer " @@ -605,14 +608,21 @@ int ff_mediacodec_dec_send(AVCodecContext *avctx, MediaCodecDecContext *s, return AVERROR_EXTERNAL; } + pts = pkt->pts; + if (pts == AV_NOPTS_VALUE && s->last_pts != AV_NOPTS_VALUE) { + pts = s->last_pts; + } else if (pts == AV_NOPTS_VALUE) { + av_log(avctx, AV_LOG_WARNING, "Packet is missing PTS!\n"); + pts = 0; + } + s->last_pts = pkt->pts; + if (pts && avctx->pkt_timebase.num && avctx->pkt_timebase.den) { + pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1, 1000000)); + } + if (need_draining) { - int64_t pts = pkt->pts; uint32_t flags = ff_AMediaCodec_getBufferFlagEndOfStream(codec); - if (s->surface) { - pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1, 1000000)); - } - av_log(avctx, AV_LOG_DEBUG, "Sending End Of Stream signal\n"); status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, 0, pts, flags); @@ -627,16 +637,10 @@ int ff_mediacodec_dec_send(AVCodecContext *avctx, MediaCodecDecContext *s, s->draining = 1; break; } else { - int64_t pts = pkt->pts; - size = FFMIN(pkt->size - offset, size); memcpy(data, pkt->data + offset, size); offset += size; - if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) { - pts = av_rescale_q(pts, avctx->pkt_timebase, av_make_q(1, 1000000)); - } - status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pts, 0); if (status < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status = %d)\n", status); diff --git a/libavcodec/mediacodecdec_common.h b/libavcodec/mediacodecdec_common.h index 023d4c5fa7..045b7aaac4 100644 --- a/libavcodec/mediacodecdec_common.h +++ b/libavcodec/mediacodecdec_common.h @@ -69,6 +69,8 @@ typedef struct MediaCodecDecContext { bool delay_flush; atomic_int serial; + int64_t last_pts; + } MediaCodecDecContext; int ff_mediacodec_dec_init(AVCodecContext *avctx, -- 2.14.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel