Hi,

This patch supersedes #13105 (https://patchwork.ffmpeg.org/patch/13105/)

A new (simpler and more robust) implementationof of the reinsertion of the
missing headers in the MPEG-2 bitstream from the HW QSV encoder.

The problem is quite simple: The bitstream generated by the MPEG-2 QSV
encoder only incorporates the SEQ_START_CODE and EXT_START_CODE
headers in the first GOP. This generates a result that is not suitable for
streaming or broadcasting.
With this patch the "mpeg2_qsv" encoder is at the same level as the
"mpeg2video", as the software implementation repeats these headers by default
in each GOP.

Regards.
A.H.

---
From 8a139ea03b0445e3057122577126f3a48744fe29 Mon Sep 17 00:00:00 2001
From: Andreas Hakon <andreas.ha...@protonmail.com>
Date: Tue, 28 May 2019 11:27:05 +0100
Subject: [PATCH] libavformat/qsvenc: repeat mpeg2 missing headers [v2]

The current implementation of the QSV MPEG-2 HW encoder writes the value
of MPEG-2 sequence headers in-band one time only. That is, in the first GOP
of the stream. This behavior generates a bitstream that is not suitable for
streaming or broadcasting.
This patch resolves this problem by storing the headers in the configuration 
phase, and reinserting them back if necessary into each GOP.

Signed-off-by: Andreas Hakon <andreas.ha...@protonmail.com>
---
 libavcodec/qsvenc.c |   27 +++++++++++++++++++++++++++
 libavcodec/qsvenc.h |    3 +++
 2 files changed, 30 insertions(+)

diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 8dbad71..63ee198 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -859,6 +859,15 @@ static int qsv_retrieve_enc_params(AVCodecContext *avctx, 
QSVEncContext *q)
 
     q->packet_size = q->param.mfx.BufferSizeInKB * 
q->param.mfx.BRCParamMultiplier * 1000;
 
+    if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
+        av_log(avctx, AV_LOG_DEBUG, "Reading MPEG-2 initial Sequence Sections 
(SPSBuffer:%d)\n", extradata.SPSBufSize);
+        q->add_headers = av_malloc(extradata.SPSBufSize);
+        if (!q->add_headers)
+            return AVERROR(ENOMEM);
+        q->add_headers_size = extradata.SPSBufSize;
+        memcpy(q->add_headers, extradata.SPSBuffer, q->add_headers_size);
+    }
+
     if (!extradata.SPSBufSize || (need_pps && !extradata.PPSBufSize)
 #if QSV_HAVE_CO_VPS
         || (q->hevc_vps && !extradata_vps.VPSBufSize)
@@ -999,6 +1008,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext 
*q)
     int ret;
 
     q->param.AsyncDepth = q->async_depth;
+    q->add_headers_size = 0;
 
     q->async_fifo = av_fifo_alloc(q->async_depth * qsv_fifo_item_size());
     if (!q->async_fifo)
@@ -1437,6 +1447,20 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext 
*q,
             ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000);
         } while (ret == MFX_WRN_IN_EXECUTION);
 
+        if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && q->add_headers_size > 
0 &&
+            (bs->FrameType & MFX_FRAMETYPE_I || bs->FrameType & 
MFX_FRAMETYPE_IDR || bs->FrameType & MFX_FRAMETYPE_xI || bs->FrameType & 
MFX_FRAMETYPE_xIDR)) {
+                if (bs->Data[0] == 0x00 && bs->Data[1] == 0x00 && bs->Data[2] 
== 0x01 && bs->Data[3] != 0xb3 ) {
+                    av_log(avctx, AV_LOG_DEBUG, "Missing MPEG-2 Sequence 
Sections, reinsertion required\n");
+                    if (q->add_headers_size + bs->DataLength <= 
q->packet_size) {
+                        memmove(new_pkt.data + q->add_headers_size, 
new_pkt.data, bs->DataLength);
+                        memcpy(new_pkt.data, q->add_headers, 
q->add_headers_size);
+                        bs->DataLength += q->add_headers_size;
+                    } else {
+                        av_log(avctx, AV_LOG_WARNING, "Insufficient spacing to 
reinsert MPEG-2 Sequence Sections");
+                    }
+                }
+            }
+
         new_pkt.dts  = av_rescale_q(bs->DecodeTimeStamp, (AVRational){1, 
90000}, avctx->time_base);
         new_pkt.pts  = av_rescale_q(bs->TimeStamp,       (AVRational){1, 
90000}, avctx->time_base);
         new_pkt.size = bs->DataLength;
@@ -1545,5 +1569,8 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext 
*q)
 
     av_freep(&q->extparam);
 
+    if (q->add_headers_size > 0)
+        av_freep(&q->add_headers);
+
     return 0;
 }
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index f2f4d38..ee81c51 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -177,6 +177,9 @@ typedef struct QSVEncContext {
     int low_power;
     int gpb;
 
+    int add_headers_size;
+    uint8_t *add_headers;
+
     int a53_cc;
 
 #if QSV_HAVE_MF
-- 
1.7.10.4

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to