PR #21467 opened by colekas URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21467 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21467.patch
Some HEVC codecs can generate field paired HEVC content that libavcodec identifies as just TOP or BOT fields when the data for the frame is stored in the resulting AVFrame structure. In the decoder identify when the content is encoded as field pairs so upstream applications can maybe weave the two fields into a full frame. See https://github.com/Intel-Media-SDK/MediaSDK/blob/master/doc/mediasdk_hevc_interlace_whitepaper.md for details. >From 797727c8ccd08c75b431ec409a650e2301f6ca88 Mon Sep 17 00:00:00 2001 From: Christopher Olekas <[email protected]> Date: Wed, 14 Jan 2026 09:50:56 -0500 Subject: [PATCH] libavcodec/hevc: Identify field paired HEVC content Some HEVC codecs can generate field paired HEVC content that libavcodec identifies as just TOP or BOT fields when the data for the frame is stored in the resulting AVFrame structure. In the decoder identify when the content is encoded as field pairs so upstream applications can maybe weave the two fields into a full frame. See https://github.com/Intel-Media-SDK/MediaSDK/blob/master/doc/mediasdk_hevc_interlace_whitepaper.md for details. --- libavcodec/avcodec.c | 5 +++++ libavcodec/defs.h | 2 ++ libavcodec/hevc/parser.c | 12 ++++++++++++ libavcodec/hevc/sei.c | 13 ++++++++----- libavcodec/hevc/sei.h | 3 +++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c index de4e083db1..7fdaf9d42f 100644 --- a/libavcodec/avcodec.c +++ b/libavcodec/avcodec.c @@ -587,6 +587,11 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) field_order = "top coded first (swapped)"; else if (enc->field_order == AV_FIELD_BT) field_order = "bottom coded first (swapped)"; + else if (enc->field_order == AV_FIELD_PAIRED_TB) + field_order = "field paired top first"; + else if (enc->field_order == AV_FIELD_PAIRED_BT) + field_order = "field paired bottom first"; + av_bprintf(&bprint, "%s, ", field_order); } diff --git a/libavcodec/defs.h b/libavcodec/defs.h index b13e983b13..c31ff9cd80 100644 --- a/libavcodec/defs.h +++ b/libavcodec/defs.h @@ -215,6 +215,8 @@ enum AVFieldOrder { AV_FIELD_BB, ///< Bottom coded first, bottom displayed first AV_FIELD_TB, ///< Top coded first, bottom displayed first AV_FIELD_BT, ///< Bottom coded first, top displayed first + AV_FIELD_PAIRED_TB, ///< Top fields are paired with next bottom fields + AV_FIELD_PAIRED_BT, ///< Bottom fields are paired with next top fields }; /** diff --git a/libavcodec/hevc/parser.c b/libavcodec/hevc/parser.c index 62bcd91172..2d41aac4e7 100644 --- a/libavcodec/hevc/parser.c +++ b/libavcodec/hevc/parser.c @@ -70,6 +70,18 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, first_slice_in_pic_flag = get_bits1(gb); s->picture_structure = sei->picture_timing.picture_struct; s->field_order = sei->picture_timing.picture_struct; + /* HEVC field coding has the following table + Top Field paired with previous Bottom Field: 9 (AV_FIELD_PAIRED_BT) + Top Field paired with next Bottom Field: 10 (AV_FIELD_PAIRED_TB) + Bottom Field paired with previous Top Field: 11 (AV_FIELD_PAIRED_TB) + Bottom Field paired with next Top Field: 12 (AV_FIELD_PAIRED_BT) + */ + if (sei->picture_timing.hevc_picture_struct == 9 || sei->picture_timing.hevc_picture_struct == 12) { + s->field_order = AV_FIELD_PAIRED_BT; + } + else if (sei->picture_timing.hevc_picture_struct == 10 || sei->picture_timing.hevc_picture_struct == 11) { + s->field_order = AV_FIELD_PAIRED_TB; + } if (IS_IRAP_NAL(nal)) { s->key_frame = 1; diff --git a/libavcodec/hevc/sei.c b/libavcodec/hevc/sei.c index 5fd4e763b3..b95959a095 100644 --- a/libavcodec/hevc/sei.c +++ b/libavcodec/hevc/sei.c @@ -59,21 +59,24 @@ static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb, return AVERROR_INVALIDDATA; if (sps->vui.frame_field_info_present_flag) { - int pic_struct = get_bits(gb, 4); + h->hevc_picture_struct = get_bits(gb, 4); h->picture_struct = AV_PICTURE_STRUCTURE_UNKNOWN; - if (pic_struct == 2 || pic_struct == 10 || pic_struct == 12) { + if (h->hevc_picture_struct == 2 || h->hevc_picture_struct == 10 || h->hevc_picture_struct == 12) { av_log(logctx, AV_LOG_DEBUG, "BOTTOM Field\n"); h->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD; - } else if (pic_struct == 1 || pic_struct == 9 || pic_struct == 11) { + } else if (h->hevc_picture_struct == 1 || h->hevc_picture_struct == 9 || h->hevc_picture_struct == 11) { av_log(logctx, AV_LOG_DEBUG, "TOP Field\n"); h->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD; - } else if (pic_struct == 7) { + } else if (h->hevc_picture_struct == 7) { av_log(logctx, AV_LOG_DEBUG, "Frame/Field Doubling\n"); h->picture_struct = HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING; - } else if (pic_struct == 8) { + } else if (h->hevc_picture_struct == 8) { av_log(logctx, AV_LOG_DEBUG, "Frame/Field Tripling\n"); h->picture_struct = HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING; } + + h->source_scan_type = get_bits(gb, 2); + h->duplicate_flag = get_bits1(gb); } return 0; diff --git a/libavcodec/hevc/sei.h b/libavcodec/hevc/sei.h index 2fcd0e8d57..2d6e8a909c 100644 --- a/libavcodec/hevc/sei.h +++ b/libavcodec/hevc/sei.h @@ -51,7 +51,10 @@ typedef struct HEVCSEIFramePacking { } HEVCSEIFramePacking; typedef struct HEVCSEIPictureTiming { + int hevc_picture_struct; int picture_struct; + int source_scan_type; + int duplicate_flag; } HEVCSEIPictureTiming; typedef struct HEVCSEIAlternativeTransfer { -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
