Skip to content

VOD Playback Demo (MP4) ​

This is the common “MP4 URL → play, pause, seek” example. It uses automatic core selection, so you do not need to choose MSE, WebCodec or WASM first. Try a known-good MP4 before substituting your own file.

1. Prepare the files ​

Use this layout and serve it over HTTP. Download the self-generated ordinary H.264 + AAC test video as media/video.mp4, or use your own file; the code URL must match the real filename. See Test Media and FFmpeg for the VR360 and HEVC samples.

text
demo/
├── index.html
├── media/video.mp4                  ← replace with your MP4
└── output/
    ├── h265web.js
    ├── h265web_wasm.js
    └── h265web_wasm.wasm

If MP4 startup is slow, check moov placement and HTTP Range. To move the index without re-encoding, write a new file rather than overwriting the input:

bash
ffmpeg -i ./media/video.mp4 -map 0 -c copy -movflags +faststart ./media/video-faststart.mp4

A trailing moov does not always prevent playback; see QA WIKI for the full checks.

2. Copy index.html ​

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>MP4 VOD demo</title>
  <script src="./output/h265web.js"></script>
</head>
<body>
  <div id="player"></div>
  <button id="play" disabled>Play</button>
  <button id="pause">Pause</button>
  <button id="seek" disabled>Seek to 10 s</button>
  <button id="sound">Enable sound</button>
  <p id="status">Loading MP4…</p>

  <script>
    const mediaUrl = './media/video.mp4'; // Or use a reachable full HTTP(S) URL.
    const status = document.getElementById('status');
    const playButton = document.getElementById('play');
    const seekButton = document.getElementById('seek');
    const player = H265webjsPlayer();

    // Bind callbacks before build() and load_media(). Ready does not auto-start playback.
    player.on_ready_show_done_callback = () => {
      playButton.disabled = false;
      seekButton.disabled = false;
      status.textContent = 'First frame ready. Press Play.';
    };
    player.video_probe_callback = (info) => console.log('Codec/duration info', info);
    player.on_seek_done_callback = (seconds) => {
      status.textContent = `Seeked to ${seconds.toFixed(1)} s`;
    };
    player.on_error_callback = (error) => {
      status.textContent = `Playback error: ${error.message || error.code}`;
    };

    const ok = player.build({
      player_id: 'player',
      base_url: './output/',
      wasm_js_uri: 'h265web_wasm.js',
      wasm_wasm_uri: 'h265web_wasm.wasm',
      width: '100%', height: 480,
      auto_play: false, ignore_audio: false,
      // No core field: let the SDK select a path for this file and browser.
    });
    if (ok) {
      player.set_voice(0); // Start muted; enable sound after a user click.
      player.load_media(mediaUrl);
    } else {
      status.textContent = 'Player build failed: check SDK file paths.';
    }

    playButton.onclick = () => player.play();
    document.getElementById('pause').onclick = () => player.pause();
    seekButton.onclick = () => player.seek(10); // Seconds; use a smaller value for short clips.
    document.getElementById('sound').onclick = () => player.set_voice(1);
    window.addEventListener('beforeunload', () => player.release());
  </script>
</body>
</html>

3. Open and troubleshoot ​

Run python3 -m http.server 8080 in demo/ and open http://localhost:8080/. With auto_play: false, press Play. If the first frame is ready but looks black, check whether the source begins with a black frame. If ready never fires, inspect the MP4 response status, type and Range in Network and consult QA WIKI.