[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 ==
 1206                h->sei.picture_timing.pic_struct ==
 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