diff mbox

[FFmpeg-devel] avcodec/mediacodecdec: work around for decoding h264 with coded fields

Message ID 20180322181450.1152-1-ffmpeg@tmm1.net
State Superseded
Headers show

Commit Message

Aman Gupta March 22, 2018, 6:14 p.m. UTC
From: Aman Gupta <aman@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 mbox

Patch

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,