Change to dynamic timestamps allocate, because the number of timestamps may be 
insufficient when it is a fixed value.
The number of timestamps depends on the number of packets required before 
outputting the frame, and the number to be reserved for frame reordering.
The number of packets which QSV decoder needs cannot be guessed before starting 
to output first frame, because it depends on the video stream.
The number to be reserved for frame reordering from H.264 specification is 32.
(Max B frame) * (Max picture per frame) = 16 * 2 = 32 (1 picture = 1 packet)
After first frame is output, the number of timestamps can be determined.

In the following cases, the value is changed.
1. If the number of timestamps is insufficient, it is increased until first 
frame is output.
2. Add 32 to the number of timestamps in use after first frame is output.
---
 libavcodec/qsv.c | 87 +++++++++++++++++++++++++++++++++-----------------------
 libavcodec/qsv.h | 10 +++++--
 2 files changed, 59 insertions(+), 38 deletions(-)

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index 1ba4474..622b0b3 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -84,29 +84,10 @@ static int codec_id_to_mfx(enum AVCodecID codec_id)
     return AVERROR(ENOSYS);
 }
 
-static int qsv_timestamps_alloc(QSVContext *q, mfxFrameAllocRequest *req)
+static void reset_timestamps(QSVContext *q)
 {
-    int ret    = AVERROR(ENOMEM);
-
-    q->dts = av_mallocz_array(q->nb_timestamps, sizeof(*q->dts));
-    q->pts = av_mallocz_array(q->nb_timestamps, sizeof(*q->pts));
-
-    if (!q->dts || !q->pts)
-        goto fail;
-
     for (int i = 0; i < q->nb_timestamps; i++)
-        q->pts[i] = q->dts[i] = AV_NOPTS_VALUE;
-
-    if ((ret = MFXVideoDECODE_Init(q->session, &q->param)))
-        ret = ff_qsv_error(ret);
-
-fail:
-    if (ret) {
-        av_free(q->dts);
-        av_free(q->pts);
-    }
-
-    return ret;
+        q->timestamps[i].pts = q->timestamps[i].dts = AV_NOPTS_VALUE;
 }
 
 int ff_qsv_init(AVCodecContext *c, QSVContext *q)
@@ -151,9 +132,19 @@ int ff_qsv_init(AVCodecContext *c, QSVContext *q)
         return ff_qsv_error(ret);
 
     q->nb_timestamps = req.NumFrameSuggested + q->param.AsyncDepth;
+    q->put_dts_cnt   = 0;
+    q->decoded_cnt   = 0;
     q->last_ret      = MFX_ERR_MORE_DATA;
 
-    return qsv_timestamps_alloc(q, &req);
+    if (!(q->timestamps = av_mallocz_array(q->nb_timestamps, 
sizeof(*q->timestamps))))
+        return AVERROR(ENOMEM);
+
+    reset_timestamps(q);
+
+    if ((ret = MFXVideoDECODE_Init(q->session, &q->param)))
+        ret = ff_qsv_error(ret);
+
+    return ret;
 }
 
 static int bitstream_realloc(mfxBitstream *bs, int size)
@@ -264,7 +255,22 @@ static mfxFrameSurface1 *get_surface(AVCodecContext 
*avctx, QSVContext *q)
     return &sl->surface;
 }
 
-static int get_dts(QSVContext *q, int64_t pts,  int64_t *dts)
+static int realloc_timestamps(QSVContext *q, int old_nmemb, int new_nmemb)
+{
+    QSVTimeStamp *tmp = av_realloc_array(q->timestamps, new_nmemb, 
sizeof(*q->timestamps));
+    if (!tmp)
+        return AVERROR(ENOMEM);
+
+    q->timestamps = tmp;
+    q->nb_timestamps = new_nmemb;
+
+    for (int i = old_nmemb; i < q->nb_timestamps; i++)
+        q->timestamps[i].pts = q->timestamps[i].dts = AV_NOPTS_VALUE;
+
+    return 0;
+}
+
+static int get_dts(QSVContext *q, int64_t pts, int64_t *dts)
 {
     int i;
 
@@ -274,7 +280,7 @@ static int get_dts(QSVContext *q, int64_t pts,  int64_t 
*dts)
     }
 
     for (i = 0; i < q->nb_timestamps; i++) {
-        if (q->pts[i] == pts)
+        if (q->timestamps[i].pts == pts)
             break;
     }
     if (i == q->nb_timestamps) {
@@ -283,28 +289,32 @@ static int get_dts(QSVContext *q, int64_t pts,  int64_t 
*dts)
                pts);
         return AVERROR_BUG;
     }
-    *dts = q->dts[i];
+    *dts = q->timestamps[i].dts;
 
-    q->pts[i] = AV_NOPTS_VALUE;
+    q->timestamps[i].pts = AV_NOPTS_VALUE;
 
     return 0;
 }
 
 static int put_dts(QSVContext *q, int64_t pts, int64_t dts)
 {
-    int i;
-    for (i = 0; i < q->nb_timestamps; i++) {
-        if (q->pts[i] == AV_NOPTS_VALUE)
-            break;
-    }
+    int ret, i;
 
-    if (i == q->nb_timestamps) {
-        av_log(q, AV_LOG_INFO, "No slot available.\n");
-        return AVERROR_BUG;
+    if (!q->decoded_cnt && q->nb_timestamps == q->put_dts_cnt) {
+        // For decoder delay
+        if ((ret = realloc_timestamps(q, q->nb_timestamps, q->nb_timestamps * 
2)) < 0)
+            return ret;
+    } else if (q->decoded_cnt == 1 && q->nb_timestamps < (q->put_dts_cnt + 
32)) {
+        // For frame reordering
+        // I[31]P[30]B[29]B[28] ... B[1]B[0] (Number in [] is display order)
+        if ((ret = realloc_timestamps(q, q->nb_timestamps, q->put_dts_cnt + 
32)) < 0)
+            return ret;
     }
 
-    q->pts[i] = pts;
-    q->dts[i] = dts;
+    i = q->put_dts_cnt % q->nb_timestamps;
+    q->timestamps[i].pts = pts;
+    q->timestamps[i].dts = dts;
+    q->put_dts_cnt++;
 
     return 0;
 }
@@ -409,6 +419,7 @@ int ff_qsv_decode(AVCodecContext *avctx, QSVContext *q,
         outsurf->Data.UV = workframe->data[1];
 
         *got_frame = 1;
+        q->decoded_cnt++;
 
         frame->pkt_pts = frame->pts = outsurf->Data.TimeStamp;
         frame->pkt_dts = dts;
@@ -440,6 +451,8 @@ int ff_qsv_flush(QSVContext *q)
 
     free_surface_list(q);
 
+    reset_timestamps(q);
+
     ff_packet_list_free(&q->pending, &q->pending_end);
 
     return ret;
@@ -451,6 +464,8 @@ int ff_qsv_close(QSVContext *q)
 
     free_surface_list(q);
 
+    av_freep(&q->timestamps);
+
     ff_packet_list_free(&q->pending, &q->pending_end);
 
     return ff_qsv_error(ret);
diff --git a/libavcodec/qsv.h b/libavcodec/qsv.h
index a9f4583..dd2a53d 100644
--- a/libavcodec/qsv.h
+++ b/libavcodec/qsv.h
@@ -37,6 +37,11 @@
 #define TIMEOUT_DEFAULT 5 * 1000    // 5s
 
 
+typedef struct QSVTimeStamp {
+    int64_t pts;
+    int64_t dts;
+} QSVTimeStamp;
+
 typedef struct QSVSurfaceList {
     mfxFrameSurface1 surface;
     struct QSVSurfaceList *next;
@@ -47,9 +52,10 @@ typedef struct QSVContext {
     mfxSession session;
     mfxVideoParam param;
     QSVSurfaceList *surflist;
-    int64_t *dts;
-    int64_t *pts;
+    QSVTimeStamp *timestamps;
     int nb_timestamps;
+    int put_dts_cnt;
+    int decoded_cnt;
     mfxSyncPoint sync;
     mfxBitstream bs;
     int last_ret;
-- 
1.8.3.msysgit.0

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to