From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id F0F7A40C8E for ; Thu, 23 Jan 2025 14:12:45 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id C4E5868B92A; Thu, 23 Jan 2025 16:12:32 +0200 (EET) Received: from out203-205-221-239.mail.qq.com (out203-205-221-239.mail.qq.com [203.205.221.239]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1E9FB68B8CD for ; Thu, 23 Jan 2025 16:12:25 +0200 (EET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foxmail.com; s=s201512; t=1737641538; bh=LZc7uhsZS4YfNdt4WyoOh67exMG59RGNPlLbntOJASQ=; h=From:To:Cc:Subject:Date; b=Ms0DD/jD7yA52hXf1CyAVt5D2O0aupjOPD3UteDb2TJgXLCfh6fOoUGEI13Z/D32u clBhbhI99gC/nnPnT46Vojeg6pQJOaeadw5CkfDqtVs5GdqzwqZqyGd0K3gdZVl40O PD1+Mp3b4n7C7XrltCrZZzrpFIlWDvkP8FtX49+Q= Received: from localhost.localdomain ([119.147.10.242]) by newxmesmtplogicsvrszb20-0.qq.com (NewEsmtp) with SMTP id 310996AE; Thu, 23 Jan 2025 22:12:16 +0800 X-QQ-mid: xmsmtpt1737641536typ3v6ejz Message-ID: X-QQ-XMAILINFO: MSFnopehvepyFipRWLWm3wgZ/kDiQe2ZklF8yfWf2On7W8//DYEJje+38fdPRp Wsb64HLeBJX65Jl9Smy7GtOglDZ2P+3maoa6E+JpXdLus8B3FBDN3E2f4PPeDMLEuZFtZzpiFmRx v44pxn8uoOOMhEgwYYtXMmFIrR8nPymaIWEALUIDQBZzbYExypI4lhbG9u0iHH8pqFwGaOPg2liX GzQTODMxgyh7G1tRuA45k6Bv7shoR6qRP5LX6mCwhOG6wwXhxWD+cTkA8WREOu3Mf/DqQj7eLoBP yhheKYmosLe+tJvJskG4c7fPkvKKEqbgUohWO//EeQROPva62vvQcgIOJwcph1ZcyFedZDXqhiT1 ZDYXGJJPT9lGvB3xEMMX5C0AhRsYj0+txAQlO+0p0qlL3IM9nw9WYWW7RmaZic1Y4FktlksjzslK ErnOygCCX3U9mSZm1p45NFdp7ftkxlT6DUOTI7H9li0cAzacTp9wdlmD9L45IulY99aALsRZ4VoQ 3l2TBtyjZrDP0I3fYO+tWfu/Pbv7rIiZowBwiyY6+zdTYxEs/YHJJAKxnavJfO+WZgGlh48p3KWN 6MYUt9sX0ry/wMDrSA8qDVLHwhFxt8RxP0hZof2Vk4jmJhVd2H23IKQKM+/uIHIFmKld4Qq2KRhw WOJ4o4IDdKTkHMUQ71d374y48ztIpmNnzTlJgoniLmjZJklw7qcCcXCHbKjzRYWVl0iA+TftXNO8 m8C/TXCafYe5dd5zkrtZDNixXEuglXjoObqnITfuBgpuHungK2KoRhCBW+xCAGIUH1Z+hZnr58y9 jDGfW45ruBrLCgauMOdaCS0h+mTxAJAQHwE0JBWvZVwzwazY8QZhdT3zobUyKBl+xsLIvirRrL99 Wpgyq+7G6W9bFYY3SyU3OJTJG+PkNtVffZ//xwq+1HkFtjM73aGkAqR+NTIdC9wlJLLwb8Z22jg7 nQB8zFIXCBUAsiHmghGBdmJH/jECIZnz5IJ2UOmX30B4dgTddJAQ== X-QQ-XMRINFO: NI4Ajvh11aEj8Xl/2s1/T8w= From: Zhao Zhili To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 Jan 2025 22:12:14 +0800 X-OQ-MSGID: <20250123141214.56038-1-quinkblack@foxmail.com> X-Mailer: git-send-email 2.46.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 3/3] avcodec/hevc: Add support for output_corrupt/showall flags X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Zhao Zhili Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: From: Zhao Zhili Also handle gradual decoding refresh stream. --- I can't find a perfect hevc intra refresh stream. 1. x265 doesn't output useful recovery point SEI. It only output a single recovery point SEI with recovery_poc_cnt equal to 0 together with IDR. 2. With patch 1/3, nvenc output SEI with recovery_poc_cnt only about half the size of required value. It looks like the encoder set recovery_poc_cnt = height / 64, but encoded with intra block CTU size 32. I would be very grateful if anyone could provide a test file that meets the standards. libavcodec/hevc/hevcdec.c | 22 +++++++++++++++++++++- libavcodec/hevc/hevcdec.h | 6 ++++++ libavcodec/hevc/refs.c | 24 +++++++++++++++++++++++- libavcodec/hevc/sei.c | 1 + libavcodec/hevc/sei.h | 1 + tests/fate/hevc.mak | 4 ++-- 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c index 79dd63092c..098ec4a9b4 100644 --- a/libavcodec/hevc/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c @@ -3228,9 +3228,19 @@ static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, s->first_nal_type = s->nal_unit_type; s->poc = s->sh.poc; - if (IS_IRAP(s)) + if (IS_IRAP(s)) { s->no_rasl_output_flag = IS_IDR(s) || IS_BLA(s) || (s->nal_unit_type == HEVC_NAL_CRA_NUT && s->last_eos); + s->recovery_poc = HEVC_RECOVERY_END; + } + + if (s->recovery_poc != HEVC_RECOVERY_END && + s->sei.recovery_point.has_recovery_poc) { + if (s->recovery_poc == HEVC_RECOVERY_UNSPECIFIED) + s->recovery_poc = s->poc + s->sei.recovery_point.recovery_poc_cnt; + else if (s->poc >= s->recovery_poc) + s->recovery_poc = HEVC_RECOVERY_END; + } /* 8.3.1 */ if (s->temporal_id == 0 && @@ -3606,6 +3616,12 @@ fail: return ret; } +static void decode_reset_recovery_point(HEVCContext *s) +{ + s->recovery_poc = HEVC_RECOVERY_UNSPECIFIED; + s->sei.recovery_point.has_recovery_poc = 0; +} + static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) { int i, ret = 0; @@ -3616,6 +3632,8 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) s->last_eos = s->eos; s->eos = 0; s->slice_initialized = 0; + if (s->last_eos) + decode_reset_recovery_point(s); for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { HEVCLayerContext *l = &s->layers[i]; @@ -3637,6 +3655,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) s->pkt.nals[i].type == HEVC_NAL_EOS_NUT) { if (eos_at_start) { s->last_eos = 1; + decode_reset_recovery_point(s); } else { s->eos = 1; } @@ -4010,6 +4029,7 @@ static int hevc_update_thread_context(AVCodecContext *dst, s->sei.common.alternative_transfer = s0->sei.common.alternative_transfer; s->sei.tdrdi = s0->sei.tdrdi; s->sei.recovery_point = s0->sei.recovery_point; + s->recovery_poc = s0->recovery_poc; return 0; } diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h index 4e95035688..d8c8c0d011 100644 --- a/libavcodec/hevc/hevcdec.h +++ b/libavcodec/hevc/hevcdec.h @@ -78,6 +78,10 @@ (s)->nal_unit_type == HEVC_NAL_BLA_N_LP) #define IS_IRAP(s) ((s)->nal_unit_type >= HEVC_NAL_BLA_W_LP && (s)->nal_unit_type <= HEVC_NAL_RSV_IRAP_VCL23) +#define HEVC_RECOVERY_UNSPECIFIED INT_MAX +#define HEVC_RECOVERY_END INT_MIN +#define HEVC_IS_RECOVERING(s) ((s)->recovery_poc != HEVC_RECOVERY_UNSPECIFIED && (s)->recovery_poc != HEVC_RECOVERY_END) + enum RPSType { ST_CURR_BEF = 0, ST_CURR_AFT, @@ -353,6 +357,7 @@ typedef struct DBParams { #define HEVC_FRAME_FLAG_SHORT_REF (1 << 1) #define HEVC_FRAME_FLAG_LONG_REF (1 << 2) #define HEVC_FRAME_FLAG_UNAVAILABLE (1 << 3) +#define HEVC_FRAME_FLAG_CORRUPT (1 << 4) typedef struct HEVCFrame { union { @@ -523,6 +528,7 @@ typedef struct HEVCContext { int slice_idx; ///< number of the slice being currently decoded int eos; ///< current packet contains an EOS/EOB NAL int last_eos; ///< last packet contains an EOS/EOB NAL + int recovery_poc; // NoRaslOutputFlag associated with the last IRAP frame int no_rasl_output_flag; diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c index dd7f7f95a8..c5d0ad4be7 100644 --- a/libavcodec/hevc/refs.c +++ b/libavcodec/hevc/refs.c @@ -34,6 +34,8 @@ void ff_hevc_unref_frame(HEVCFrame *frame, int flags) { frame->flags &= ~flags; + if (!(frame->flags & ~HEVC_FRAME_FLAG_CORRUPT)) + frame->flags = 0; if (!frame->flags) { ff_progress_frame_unref(&frame->tf); av_frame_unref(frame->frame_grain); @@ -176,6 +178,7 @@ int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc) { HEVCFrame *ref; int i; + int no_output; /* check that this POC doesn't already exist */ for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { @@ -199,7 +202,10 @@ int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc) ref->base_layer_frame = (l != &s->layers[0] && s->layers[0].cur_frame) ? s->layers[0].cur_frame - s->layers[0].DPB : -1; - if (s->sh.pic_output_flag) + no_output = !IS_IRAP(s) && (s->poc < s->recovery_poc) && + !(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL); + if (s->sh.pic_output_flag && !no_output) ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF; else ref->flags = HEVC_FRAME_FLAG_SHORT_REF; @@ -266,6 +272,8 @@ int ff_hevc_output_frames(HEVCContext *s, int output = !discard && (layers_active_output & (1 << min_layer)); if (output) { + if (frame->flags & HEVC_FRAME_FLAG_CORRUPT) + f->flags |= AV_FRAME_FLAG_CORRUPT; f->pkt_dts = s->pkt_dts; ret = av_container_fifo_write(s->output_fifo, f, AV_CONTAINER_FIFO_FLAG_REF); } @@ -462,6 +470,20 @@ static int add_candidate_ref(HEVCContext *s, HEVCLayerContext *l, if (ref == s->cur_frame || list->nb_refs >= HEVC_MAX_REFS) return AVERROR_INVALIDDATA; + if (!IS_IRAP(s)) { + int ref_corrupt = !ref || ref->flags & (HEVC_FRAME_FLAG_CORRUPT | + HEVC_FRAME_FLAG_UNAVAILABLE); + int recovering = HEVC_IS_RECOVERING(s); + + if (ref_corrupt && !recovering) { + if (!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && + !(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) + return AVERROR_INVALIDDATA; + + s->cur_frame->flags |= HEVC_FRAME_FLAG_CORRUPT; + } + } + if (!ref) { ref = generate_missing_ref(s, l, poc); if (!ref) diff --git a/libavcodec/hevc/sei.c b/libavcodec/hevc/sei.c index 9c3594ac2f..b8e98cde89 100644 --- a/libavcodec/hevc/sei.c +++ b/libavcodec/hevc/sei.c @@ -89,6 +89,7 @@ static int decode_nal_sei_recovery_point(HEVCSEI *s, GetBitContext *gb) rec->recovery_poc_cnt = recovery_poc_cnt; rec->exact_match_flag = get_bits1(gb); rec->broken_link_flag = get_bits1(gb); + rec->has_recovery_poc = 1; return 0; } diff --git a/libavcodec/hevc/sei.h b/libavcodec/hevc/sei.h index 7e1a2b0756..c4714bb7c5 100644 --- a/libavcodec/hevc/sei.h +++ b/libavcodec/hevc/sei.h @@ -99,6 +99,7 @@ typedef struct HEVCSEIRecoveryPoint { int16_t recovery_poc_cnt; uint8_t exact_match_flag; uint8_t broken_link_flag; + uint8_t has_recovery_poc; } HEVCSEIRecoveryPoint; typedef struct HEVCSEI { diff --git a/tests/fate/hevc.mak b/tests/fate/hevc.mak index 9e6fd72618..99f8aa83b5 100644 --- a/tests/fate/hevc.mak +++ b/tests/fate/hevc.mak @@ -207,7 +207,7 @@ $(HEVC_TESTS_444_8BIT): SCALE_OPTS := -pix_fmt yuv444p $(HEVC_TESTS_10BIT): SCALE_OPTS := -pix_fmt yuv420p10le -vf scale $(HEVC_TESTS_422_10BIT) $(HEVC_TESTS_422_10BIN): SCALE_OPTS := -pix_fmt yuv422p10le -vf scale $(HEVC_TESTS_444_12BIT): SCALE_OPTS := -pix_fmt yuv444p12le -vf scale -fate-hevc-conformance-%: CMD = framecrc -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bit $(SCALE_OPTS) +fate-hevc-conformance-%: CMD = framecrc -flags output_corrupt -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bit $(SCALE_OPTS) $(HEVC_TESTS_422_10BIN): CMD = framecrc -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bin $(SCALE_OPTS) $(HEVC_TESTS_MULTIVIEW): CMD = framecrc -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bit \ -pix_fmt yuv420p -map "0:view:0" -map "0:view:1" -vf setpts=N @@ -248,7 +248,7 @@ FATE_HEVC_FFPROBE-$(call DEMDEC, HEVC, HEVC) += fate-hevc-paired-fields fate-hevc-monochrome-crop: CMD = probeframes -show_entries frame=width,height:stream=width,height $(TARGET_SAMPLES)/hevc/hevc-monochrome.hevc FATE_HEVC_FFPROBE-$(call PARSERDEMDEC, HEVC, HEVC, HEVC) += fate-hevc-monochrome-crop -fate-hevc-afd-tc-sei: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -bitexact -show_entries frame_side_data_list -select_streams v $(TARGET_SAMPLES)/mpegts/loewe.ts +fate-hevc-afd-tc-sei: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -bitexact -flags output_corrupt -show_entries frame_side_data_list -select_streams v $(TARGET_SAMPLES)/mpegts/loewe.ts FATE_HEVC_FFPROBE-$(call PARSERDEMDEC, HEVC, HEVC, HEVC) += fate-hevc-afd-tc-sei fate-hevc-hdr10-plus-metadata: CMD = probeframes -show_entries frame=side_data_list $(TARGET_SAMPLES)/hevc/hdr10_plus_h265_sample.hevc -- 2.46.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".