From: colekas via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: colekas <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PR] libavcodec/hevc: Identify field paired HEVC content (PR #21467)
Date: Wed, 14 Jan 2026 14:55:16 -0000
Message-ID: <176840251704.25.6593341864695668571@4457048688e7> (raw)
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
reply other threads:[~2026-01-14 14:55 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=176840251704.25.6593341864695668571@4457048688e7 \
--to=ffmpeg-devel@ffmpeg.org \
--cc=code@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
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