[FFmpeg-trac] #8916(avcodec:open): Incorrect field order indication when encoding interlace top field first using h264_nvenc
FFmpeg
trac at avcodec.org
Thu Feb 11 18:01:44 EET 2021
#8916: Incorrect field order indication when encoding interlace top field first
using h264_nvenc
-------------------------------------+-------------------------------------
Reporter: Ptaah | Owner:
Type: defect | Status: open
Priority: important | Component: avcodec
Version: git-master | Resolution:
Keywords: nvenc | Blocked By:
regression |
Blocking: | Reproduced by developer: 0
Analyzed by developer: 0 |
-------------------------------------+-------------------------------------
Comment (by Ptaah):
I've made some progress today. First I identified the range of versions in
between which it got broken:
It works with avcodec 57.102.100 from 1.7.2017
It doesn't work with avcodec 57.105.100 from 1.9.2017
However I didn't find any significant changes in nvenc source files
between these dates.
Then I went all in and began to parse the bitstream myself. What I noticed
is, the good version generates bitstream with no SEI messages (simply SPS,
PPS, IDR, P, ...), BUT the bad version generates two SEI messages after
SPS and PPS. Second SEI has within itself pic_timing payload and it has
pic_struct with value of 1 (H264_SEI_PIC_STRUCT_TOP_FIELD). After keyframe
(which itself is top field) there is another SEI message with pic struct
with value of 2 (H264_SEI_PIC_STRUCT_BOTTOM_FIELD).
Now let's look at the avcodec h264 decoder, specifically how it's
determining field order in h264 bitstream.
h264_slice.c, line:1198
1198 if (cur->field_poc[0] != cur->field_poc[1]) {
1199 /* Derive top_field_first from field pocs. */
1200 out->top_field_first = cur->field_poc[0] < cur->field_poc[1];
1201 } else {
1202 if (sps->pic_struct_present_flag &&
h->sei.picture_timing.present) {
1203 /* Use picture timing SEI information. Even if it is a
1204 * information of a past frame, better than nothing. */
1205 if (h->sei.picture_timing.pic_struct ==
H264_SEI_PIC_STRUCT_TOP_BOTTOM ||
1206 h->sei.picture_timing.pic_struct ==
H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP)
1207 out->top_field_first = 1;
1208 else
1209 out->top_field_first = 0;
1210 } else if (out->interlaced_frame) {
1211 /* Default to top field first when pic_struct_present_flag
1212 * is not set but interlaced frame detected */
1213 out->top_field_first = 1;
1214 } else {
1215 /* Most likely progressive */
1216 out->top_field_first = 0;
1217 }
1218 }
When parsing bitstream generated by older version (without SEI) it either
goes to line 1200, or 1213 (I'm not sure). However, when parsing bitstream
generated by newer version (with SEI), it DEFINITELY goes to line 1209.
Now it becomes clear. It's not a bug in nvenc implementation, it's seems
to be a bug in avcodec h264 decoder, because it is not properly handling
h264 interlaced with separated fields and SEI messages present. The reason
might be simply because MBAFF is wildly more used than separated fields.
This hypothesis is supported by the fact, that MediaInfo correctly detects
top field first with those specific files.
So the quick, even if not optimal, solution, is to strip output bitstream
of all SEI. It will still work and the field order will be correctly
detected by libavcodec.
One question however remains. Why nvenc started to output SEI nalu in h264
bitstream? I have no answer.
--
Ticket URL: <https://trac.ffmpeg.org/ticket/8916#comment:17>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker
More information about the FFmpeg-trac
mailing list