GNOME Bugzilla – Bug 732631
Missing frames when encoding 16x16 video to MPEG4/MPEG2/H264
Last modified: 2018-11-03 12:56:38 UTC
+++ This bug was initially created as a clone of Bug #732351 +++ When encoding 16x16 video to MPEG, a sanity check triggers in ffmpeg, which causes frames to be not encoded. To reproduce: 1) Create a 16x16 h264 file: gst-launch-1.0 videotestsrc pattern=6 num-buffers=1000 ! \ "video/x-raw, format=(string)I420, width=(int)16, height=(int)16, \ framerate=(fraction)1/1" ! x264enc ! qtmux ! filesink location=/tmp/test.mov 2) Play this file: gst-launch-1.0 playbin uri="file:///tmp/test.mov" video-sink=xvimagesink 3) See grey output, instead of the solid blue (pattern 6) we expected. Tracing shows the encoding earlies out in libav from a sanity check on size (which is apparently too strict): gst-libs/ext/libav/libavcodec/mpegvideo_enc.c, function encode_thread: if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < MAX_MB_BYTES){ av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); return -1; } Commenting out the return -1 above fixes the issue (albeit at the likely cost of possible buffer overflow).
in 1) did you mean avenc_mpeg2video instead of x264enc ? Also, do you have the same issue with mpeg2enc ?
No, and no. And it also happens with avenc_mpeg4.
Actually, this is not quite the same for h264 and mpeg4. I was tracing using mpeg4 after checking what combinations had the issue, and h264 does not trigger that check (but might trigger a similar one elsewhere). Just to be precise.
ok, make more sense, comment 1 is a little confusing. I can also reproduce here, notice that the missing frame is also visible when playing back the mov using mplayer.
At least for MPEG4, it seems that there is exactly as much space in the s->pb bitbuffer as the maximum size of a MB (which is presumably 16x16). The first loop shows there is something already in that buffer, so there is no space left for the theoretical max size of the only MB to write. When encoding a frame with more than 1 MB, I think the actual encoded size of the first MB is less than max-mb-size minus whatever was there in the s->pb buffer before starting encoding MBs, so the check never triggers. However, it would likely trigger if all the MBs before the last one were somehow encoded at the max size. So, to fix this, I think we need to figure out the max amount of data that can be written in s->pb before starting encoding MBs (probably some kind of frame header), and ensure s->pb is initialized with that much space extra.
According to http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html, it seems the picture header can be not only variable size, but of any size (at least if crafted): > additionally if the next bit is "1" (extra_bit_picture) it is followed by 8 > bits of "extra" data (discarded by decoders). This continues until a "0" bit > is encountered. So for at least one case, we can't seem to have a high bound on the amount of data that's present in the buffer prior to encoding a MB. A middle ground would be to allocate some reasonably sized extra space that should be enough in most cases (hopefully all reasonable ones). In the case of such very large picture headers, encoding would still fail as it does now, but cases like that 16x16 frame would pass. Opinions ?
-- GitLab Migration Automatic Message -- This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/gstreamer/gst-libav/issues/15.