Menu

#141 Systematic reencoding in second pass

None
closed-out-of-date
None
5
2024-08-03
2020-08-03
No

Hello, first off thanks for this high quality library, I am currently evaluating it using it through its GStreamer wrapper instead of the FFmpeg implementation. Picture quality shows a large improvement at a similar bitrate, but I am experiencing slower than real time encoding with high resolution (1080p) input streams.

Multithreading only offers a minor performance improvement, as as far as I can tell large parts of the encoding process are still single-threaded (eg QuantiseAndCode()).

I noticed that a significant culprit is that reencoding occurs nearly systematically in the second pass, at least with my set of parameters / input data.

You can find a sample of my input data at https://storage.googleapis.com/www.mathieudu.com/misc/dumped.avi, and I have attached filtered logs showing the problem to this issue, I ran mpeg2enc with:

lav2yuv -v0 dumped.avi | mpeg2enc -v 2 -M12 --video-bitrate 20000 --video-buffer 1000 --cbr -o output.mpeg2 2>&1 | grep "RECODED\|RETAINED\|reencode actual"

As you can see, 90 % of the images end up being recoded. As far as I can tell, there is a feedback loop in the code that aims to avoid this, but it doesn't look to have enough an effect to significantly affect the amount of reencoding that takes place after processing 30 seconds of data. At that point, the performance hit is enough to cause GStreamer to start dropping buffers to keep up, which of course results in degraded user experience.

I apologize if this should have been filed as a support request, but it feels pretty pathological to me.

One thing I'm not clear on is why a second pass occurs at all when CBR mode is explicitly required? I was under the impression that CBR was supposed to be single pass, but I am not that familiar with video encoding so I might be completely wrong :)

One workaround I can imagine at the GStreamer element level is to subclass "OnTheFlyPass2", and make ReencodeRquired() return false, when cbr was requested, but I'm unsure of the theoretical consequences it might have. In practice, with the streams I have tested this against, I do not see any significant difference, the bitrate profile over time is pretty much the same with and without the hack.

Again, thanks for the free software :)

1 Attachments

Discussion

  • Bernhard Praschinger

    • assigned_to: Bernhard Praschinger
    • Group: -->
     
    • Andrew Stevens

      Andrew Stevens - 2020-08-21

      When you want to speed up Enconding mpeg2enc (which it was never
      built for) A small speedup should be able to gained when you change
      the options of mpeg2enc to this:

      -M 8--video-bitrate 20000 --video-buffer 1000 -f 0 -4 4 -2 4 -r 8 -D
      8 -o ...
      The encoding time did go down a little on my machine from 37-39 sec
      down to 35.5-37 seconds. Measured with time, using several tries.
      The problem ist that the original developer of mpeg2enc has been
      offline for a lot of years. If you find things to speed up the code
      please go forward.

      I didn't really go offline I just got Kids ( and some fairly
      interesting day-job programming tasks) and some time-consuming
      Hobbies to keep me enterained ;-) ;-)
      With h264 etc making MPEG2 encoding obsolete I didn't really have a
      coding itch so scratch anymore.

      Anyway mepg2enc was tested/tuned for bitrates <= DVD and the first
      pass uses some (fairly naive) feedback control to allocate bits.
      Itcould be the first pass (or the heuristics for doing a reencode)
      are simply doing a crappy job at 20Mbps resulting (perhaps
      unnecessary) reencoding.

      Just out of interest: encoding MPEG2 at 20Mbps CBR is a pretty
      exotic choice! its not DVD standard so playback would be on a
      computer or similar. For that kind of player you could simply specify
      a fat video buffer and constant quality and get good results without
      wasting bits on encoding-to-death highly compressible passages.

      Cheers,

      Andrew
      

      PS
      At the time it was written dual- CPU (not dual core!!) with SSEwas
      high-end so aggressive multi-threading through striping etc was a low
      priority. Nowadays you'd want to support AVX and implement a few more
      modern motion estimation algorithms too!

       
      • Mathieu Duponchelle

        Hey Andrew, thanks for dropping by :)

        MPEG-2 encoding is still used in broadcasting for backward compatibility reasons, and in this context CBR is very much a requirement, and a bitrate in the 15-20 Mbps range for HDTV is actually pretty typical as far as I know.

        As far as I've observed with my test samples avoiding reencoding in the second pass doesn't make a significant difference in terms of bitrate peaks, perhaps something doesn't scale right at higher bitrates as you suggest indeed, though from a brief look at the code calculations of the error rate seem to be expressed as factors as one would expect, but it'd probably be easier to figure out what's going on for someone with more knowledge of the code base.

        re AVX, I don't know enough assembly to tackle that sort of work but I'll cheer from the sidelines in case anyone wants to do so :)

         
  • Bernhard Praschinger

    Hallo,

    A smaler sample (<100MB) would have been enough.
    The manpage of mpeg2enc says: there is a hardcoded limit of 4 worker threads.
    Are you aware that you create a MPEG1 output:
    INFO: [mpeg2enc] Selecting Generic MPEG1 output profile
    INFO: [mpeg2enc] Progressive input - selecting progressive encoding.
    INFO: [mpeg2enc] Encoding MPEG-1 video to output.mpeg2
    ---ENDE---

    When you want to speed up Enconding mpeg2enc (which it was never built for) A small speedup should be able to gained when you change the options of mpeg2enc to this:
    -M 8--video-bitrate 20000 --video-buffer 1000 -f 0 -4 4 -2 4 -r 8 -D 8 -o ...

    The encoding time did go down a little on my machine from 37-39 sec down to 35.5-37 seconds. Measured with time, using several tries.

    The problem ist that the original developer of mpeg2enc has been offline for a lot of years. If you find things to speed up the code please go forward.

    Regards, Bernhard

     
  • Mathieu Duponchelle

    Heya, thanks for following up, indeed I didn't realize that command line was encoding as MPEG-1, but the behaviour is the same with MPEG-2. I also observed marginal improvements in encoding time with the reduction switches, but nothing significant enough. I ended up exposing a "disable-encode-retries" property in the GStreamer wrapper: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1491/diffs?commit_id=93a54093ec821e9c46fd8cefcb3f06f54777b05e , it's probably a bit hacky but it was the only "easy" way to achieve consistent and relaiable real-time 1080p encoding on my system.

    As far as I could tell from playing around the codebase, managing to make https://sourceforge.net/p/mjpeg/Code/HEAD/tree/trunk/mjpeg_play/mpeg2enc/picture.cc#l540 multithreaded could yield a very significant performance boost, but it's not as easy as I hoped, mostly because the calculated quantizer for each macroblock depends on the currently encoded size (Picture::EncodedSize()). I realised this after making a first try at calculating suggested quantizers in an initial loop, then dispatching quantization jobs to multiple threads. If you have an idea how to solve this problem in a deterministic way I'd be happy to try again, in our days of CPUs with very high core counts it's a shame that mpeg2enc fails to leverage those in a meaningful manner, especially as the picture quality given the same bitrate is heads and shoulders above the FFmpeg encoder!

     
  • Mathieu Duponchelle

    re hardcoded limit, there is one indeed but it's 16 :

    mjpeg_play/mpeg2enc/encoderparams.hh:#define MAX_WORKER_THREADS 16

    Not that it really matters, because most of the encoding work is still done in a single thread anyway :)

     
  • Steven Schultz

    Steven Schultz - 2024-08-03
    • status: open --> closed-out-of-date
     

Log in to post a comment.

MongoDB Logo MongoDB