Log in

View Full Version : Fast H.264 decoding in Javascript


implant
11th August 2014, 20:31
Hello.

Currently, I work on a h.264 video decoder, which should be implemented in plain html 5. It should not rely on plugins to gain real browser- & device-independence.

The Broadway decoder shows that this is at least possible. Although the framerate of 10 fps for 1080p on an average system is not good. The other point is that it requires webGL for yuv -> rgb conversion.

For my use case, I have a NVIDIA GRID graphics card, which does the h.264 encoding. The video stream is then sent to a browser via streaming AJAX. I need to reduce the CPU load on the client below 50% while improving the framerate to at least 20 fps.

I can not use the html 5 <video> tag, because of no guaranteed support for mp4, but more important because the lack of video streaming support.

Solution 1 "tune": I use low compression (= high bandwith) and low framerate settings with the h.264 encoder. Then I hardcode the parameter sets in the decoder and optimize the source code. I use approximations instead of accuracy in the decoding process. I convert yuv -> rgb on macroblock update.

Solution 2 "rgb space": On the server, I encode the video stream normally with the NVIDIA GRID graphics card. Then, I decode the stream on the server again and extract the p-frame transformations. After this, I convert yuv -> rgb color space and encode a second time in software using the existing transformations. This will at least save the time for yuv -> rgb conversion on the client.

Solution 3 "jpeg intra": On the server, I encode the video stream normally with the NVIDIA GRID graphics card. Then, I decode the stream on the server again and extract the p-frame transformations, which are sent to the client in a custom format. The intra frame itself is captured seperately on the server and encoded as jpeg. The client loads and decodes it via <img> tag and applies the p-frame transformations. I suppose the quality is not as good but the performance is improved.

The only option for built-in acceleration I found is the jpeg/decoder of the browser.

I would like to hear what you think.

LoRd_MuldeR
11th August 2014, 21:38
Maybe you want to have a look at Emscripten and asm.js, if you haven't yet.

foxyshadis
12th August 2014, 01:41
I'd think you'd want to push more work to WebGL, not less. Translators like emscripten/asm.js are practically required for doing intense work like this, but they're still limited to a single thread and unable to take advantage of SIMD, without which you'll never get acceptable performance beyond a modest 720p24, if that. Push as much as possible to WebGL, not the other way around.

Since you control both the server and the client, you can re-encode any way you want, and if you dynamically monitor bandwidth then a JPEG stream isn't a bad choice for a very-high-bandwidth connection. Any lower and you'll have to go with another format, though. MPEG-1 or MPEG-2 isn't a terrible choice for medium-high, they're easy to decode but the licensing fees will hurt. h.264 baseline (no B-frames, no CABAC, no 8x8) is another good option, especially if you turn deblocking off; it's much easier to decode than high profile, though harder than older MPEG formats.

implant
30th August 2014, 12:50
I finally chose to use screenshots and a standard JPEG encoder on my server to stream about 10*1080p frames per second to the client browser. The frames are received with streaming Ajax and passed via DataURL to an IMG tag, where they are decoded. I do not touch any pixel to keep the CPU load low. For this reason, I also discarded plans for delta encoding.

With this simple solution I get (in my case) acceptable framerate and quality while the bandwidth stays below 4 mbps.