Frontend Development 16 min read

Developing a WebAssembly‑Based H.265 Live Streaming Player for Huajiao Live

This article details the research, design, and implementation of a high‑efficiency H.265 live‑streaming player on the web using WebAssembly‑compiled FFmpeg, custom I/O, Web Workers, and WebGL rendering to achieve low‑latency, high‑quality playback in modern browsers.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Developing a WebAssembly‑Based H.265 Live Streaming Player for Huajiao Live

With the rapid evolution of live‑streaming technology, high picture quality, low bandwidth, and low cost have become key goals; H.264 is mainstream, while the next‑generation HEVC (H.265) is increasingly adopted. Huajiao Live has been researching and optimizing H.265 for its platform.

HEVC (H.265) offers up to 50% bitrate reduction at the same visual quality compared with H.264, thanks to flexible Coding Tree Units (CTU), richer intra‑ and inter‑prediction modes, and advanced Sample Adaptive Offset (SAO) filtering, though it also increases decoding complexity.

Web browsers do not natively support H.265 playback, so software decoding is required. JavaScript‑based decoders (e.g., libde265.js) suffer from low frame rates and audio‑video sync issues, prompting the exploration of a more efficient solution.

Chrome’s native audio/video pipeline uses the video tag, a WebMediaPlayer , FFmpeg for demuxing and decoding, and finally renders the decoded frames. Although FFmpeg can decode H.265, it does not support HEVC encapsulated in FLV/RTMP, which is the format used by Huajiao Live.

To overcome this, a custom FFmpeg build with HTTP‑FLV support is created and compiled to WebAssembly using Emscripten. The resulting Wasm module runs in the browser and receives live‑stream data via Web Workers.

Two Web Workers are instantiated: Downloader fetches the HTTP‑FLV stream using the Streams API and forwards binary chunks to the Decoder worker via postMessage with Transferable objects; the Decoder worker passes the data to the Wasm FFmpeg instance, allocating memory with Module._malloc and copying data via Module.HEAPU8.set . Decoded video (YUV420P) and audio (PCM) are sent back to the main thread through callbacks and queued for rendering.

Video rendering is performed with WebGL: YUV data is uploaded to GPU textures and converted to RGBA on‑the‑fly, avoiding costly CPU‑side conversion. Audio playback uses the Web Audio API.

A circular buffer (ring buffer) is employed to store incoming stream data, with head and tail pointers managing read/write positions, ensuring bounded memory usage during continuous live streaming.

FFmpeg’s custom I/O is configured via avio_alloc_context , providing callbacks for reading packets from the in‑memory buffer, enabling seamless decoding of the live stream.

By disabling unnecessary codecs and formats during compilation (using emconfigure ./configure with tailored flags), the final Wasm binary is reduced to ~1.2 MB, improving load time.

Testing on a MacBook Pro (2.2 GHz i7, 16 GB RAM) shows stable memory usage of 270–320 MB and CPU utilization of 40–50% while watching a live stream in Chrome.

Key technologies used: WebAssembly, FFmpeg, Web Workers, WebGL, Web Audio API, HTTP‑FLV, and custom FFmpeg I/O.

live streamingWebAssemblyFFmpegWebGLH.265Video Decoding
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.