From patchwork Tue May 14 10:27:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Andreas_H=C3=A5kon?= X-Patchwork-Id: 13105 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 7811A447220 for ; Tue, 14 May 2019 13:27:39 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 545C2680768; Tue, 14 May 2019 13:27:39 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-40136.protonmail.ch (mail-40136.protonmail.ch [185.70.40.136]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1642D680352 for ; Tue, 14 May 2019 13:27:33 +0300 (EEST) Date: Tue, 14 May 2019 10:27:29 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=default; t=1557829652; bh=EOPkRFCxbQrgJ3Y9Z9gflrrqO0glcbDLhF8794uGLGE=; h=Date:To:From:Reply-To:Subject:Feedback-ID:From; b=T/4QMUO7Z+mzTm+SLOYkef7aIfUGNPn3jPLjg2XKBB/iVHkCDeK6y2wm63ketcyGN cxSGgNlVCyhytcTQQ4C7abPwMkVCy5XTvodHDosZojJUhWjLM/u8Iai4frTZXUpjKQ 6sYBB15A5o28mOHiTgkYxBlhbq127hmsvjhTEtv8= To: FFmpeg development discussions and patches From: =?UTF-8?Q?Andreas_H=C3=A5kon?= Message-ID: Feedback-ID: Mx8CaiV20jk_fqXDN0fFpg3vRaGkb9VCTrYRnZNHwEija3aOdqvFspzl6ODkmHrlSKJSx29p-LzkuvS_96L02A==:Ext:ProtonMail MIME-Version: 1.0 X-Spam-Status: No, score=-1.2 required=7.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mail.protonmail.ch X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: [FFmpeg-devel] [PATCH] libavformat/qsvenc: fix mpeg2 missing headers X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Hi, A fix for the missing in-band Sequence Headers from the QSV MPEG-2 HW Encoder. Regards. A.H. --- From a0b8525e0ebfd1a3b91bad7a21cc9de5c5a01e0e Mon Sep 17 00:00:00 2001 From: Andreas Hakon Date: Tue, 14 May 2019 11:07:10 +0100 Subject: [PATCH] libavformat/qsvenc: fix mpeg2 missing headers 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 reading these headers the first time they appear, and reinserting them back into each GOP with the rest of the MPEG-2 headers. Signed-off-by: Andreas Hakon --- libavcodec/qsvenc.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/qsvenc.h | 5 +++ 2 files changed, 93 insertions(+) diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index a03ab69..18d4540 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -39,6 +39,7 @@ #include "qsv.h" #include "qsv_internal.h" #include "qsvenc.h" +#include "mpegvideo.h" static const struct { mfxU16 profile; @@ -998,6 +999,13 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) int opaque_alloc = 0; int ret; + if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + q->section_state = 0; + } + else { + q->section_state = -1; + } + q->param.AsyncDepth = q->async_depth; q->async_fifo = av_fifo_alloc(q->async_depth * qsv_fifo_item_size()); @@ -1296,6 +1304,10 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, QSVFrame *qsv_frame = NULL; mfxEncodeCtrl* enc_ctrl = NULL; int ret; + int p_sec, p_bytes_left; + const uint8_t *p_buf; + const uint8_t *p_buf_end; + uint32_t start_code; if (frame) { ret = submit_frame(q, frame, &qsv_frame); @@ -1388,6 +1400,82 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, 0 : ff_qsv_print_error(avctx, ret, "Error during encoding"); } + // Patch MPEG-2 missing Sequence Sections + if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && + (bs->FrameType & MFX_FRAMETYPE_I || bs->FrameType & MFX_FRAMETYPE_xI)) { + if (q->section_state == 0) { + av_log(avctx, AV_LOG_VERBOSE, "Searching for MPEG-2 initial Sequence Sections\n"); + // LOAD Sequence sections + p_sec = 0; + p_buf = bs->Data; + p_buf_end = bs->Data + bs->DataLength; + while (p_buf < p_buf_end) { + start_code= -1; + p_buf = avpriv_find_start_code(p_buf, p_buf_end, &start_code); + p_bytes_left = p_buf_end - p_buf; + switch(start_code) { + case SEQ_START_CODE: + if (p_bytes_left >= 7) { + memcpy(q->seq_header, p_buf - 4, 13); + p_sec += 1; + av_log(avctx, AV_LOG_VERBOSE, "Found MPEG-2 SEQ_START_CODE Section\n"); + if ((p_buf[7] & 0x1) == 1) { + memcpy(q->matrix, p_buf + 8, 64); + p_sec += 4; + av_log(avctx, AV_LOG_VERBOSE, "Found MPEG-2 Matrix\n"); + } + } + continue; + case EXT_START_CODE: + if (p_bytes_left >= 5 && (p_buf[0] >> 4) == 0x01) { + memcpy(q->seq_ext, p_buf - 4, 10); + p_sec += 2; + av_log(avctx, AV_LOG_VERBOSE, "Found MPEG-2 EXT_START_CODE Section\n"); + } + continue; + case -1: + break; + default: + if (start_code >= SLICE_MIN_START_CODE && + start_code <= SLICE_MAX_START_CODE) + break; + continue; + } + break; + } + switch (p_sec) { + case 3: + q->section_state = 1; // SEQ_START_CODE & EXT_START_CODE + break; + case 7: + q->section_state = 2; // SEQ_START_CODE+Matrix & EXT_START_CODE + break; + default: + q->section_state = 0; // Insufficient data + } + } else { + // ADD stored sections + switch (q->section_state) { + case 1: + memmove(bs->Data + 23, bs->Data, bs->DataLength - 23); + bs->DataLength += 23; + memcpy( bs->Data + 0 , q->seq_header, 13); + memcpy( bs->Data + 13, q->seq_ext, 10); + break; + case 2: + memmove(bs->Data + 87, bs->Data, bs->DataLength - 87); + bs->DataLength += 87; + memcpy( bs->Data + 0 , q->seq_header, 13); + memcpy( bs->Data + 13, q->matrix, 64); + memcpy( bs->Data + 77, q->seq_ext, 10); + break; + default: + return ff_qsv_print_error(avctx, MFX_ERR_UNDEFINED_BEHAVIOR, + "Impossible to Patch MPEG-2 missing Sequence Sections"); + } + } + } + if (ret == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM && frame->interlaced_frame) print_interlace_msg(avctx, q); diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h index f2f4d38..f2c9fba 100644 --- a/libavcodec/qsvenc.h +++ b/libavcodec/qsvenc.h @@ -177,6 +177,11 @@ typedef struct QSVEncContext { int low_power; int gpb; + int section_state; // -1: not used; 0: uninitialized; 1: loaded without matrix; 2: loaded with matrix + uint8_t seq_header[13]; + uint8_t matrix[64]; + uint8_t seq_ext[10]; + int a53_cc; #if QSV_HAVE_MF