Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PR] libavcodec/hevc: Identify field paired HEVC content (PR #21467)
@ 2026-01-14 14:55 colekas via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: colekas via ffmpeg-devel @ 2026-01-14 14:55 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: colekas

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 <chris.olekas@ssimwave.com>
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 -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-01-14 14:55 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-14 14:55 [FFmpeg-devel] [PR] libavcodec/hevc: Identify field paired HEVC content (PR #21467) colekas via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git