### Install Dependencies Source: https://github.com/privaloops/hevc.js/blob/main/site/docs/dashjs-plugin.html Install the necessary packages for the HEVC plugin and dash.js. ```bash $ npm install @hevcjs/dashjs-plugin dashjs ``` -------------------------------- ### Install and Build Demo Source: https://github.com/privaloops/hevc.js/blob/main/README.md Installs project dependencies, builds WASM and JS bundles for the demo, and serves the demo locally. ```bash pnpm install pnpm build:demo npx serve demo ``` -------------------------------- ### Install @hevcjs/dashjs-plugin and dashjs Source: https://github.com/privaloops/hevc.js/blob/main/packages/dashjs-plugin/README.md Install the necessary packages using npm. This command installs both the HEVC plugin and the dash.js library. ```bash npm install @hevcjs/dashjs-plugin dashjs ``` -------------------------------- ### Clone and Install Project Dependencies Source: https://github.com/privaloops/hevc.js/blob/main/CONTRIBUTING.md Clone the hevc.js repository and install its dependencies using pnpm. This is the initial step for setting up the development environment. ```bash git clone https://github.com/privaloops/hevc.js.git cd hevc.js pnpm install ``` -------------------------------- ### Install HEVC.js Plugins Source: https://github.com/privaloops/hevc.js/blob/main/README.md Install the appropriate HEVC.js plugin for your player using npm. ```bash npm install @hevcjs/dashjs-plugin # dash.js npm install @hevcjs/shaka-plugin # Shaka Player ``` -------------------------------- ### Initial Page Load Setup Source: https://github.com/privaloops/hevc.js/blob/main/demo/index.html Initializes WebGL and the Web Worker when the page loads. Displays an error if WebGL is not available. ```javascript if (initGL()) { fetch('hevc-decode.wasm').then(r => { window._wasmSize = +r.headers.get('content-length') || 0; }); initWorker(); } else { setStatus('WebGL not available'); } ``` -------------------------------- ### Install Shaka Player and HEVC Plugin Source: https://github.com/privaloops/hevc.js/blob/main/packages/shaka-plugin/README.md Install the necessary packages for Shaka Player and the HEVC plugin using npm. ```bash npm install @hevcjs/shaka-plugin shaka-player ``` -------------------------------- ### Install @hevcjs/core via npm Source: https://github.com/privaloops/hevc.js/blob/main/packages/core/README.md Install the core package using npm. This is the standard way to include the library in your project. ```bash npm install @hevcjs/core ``` -------------------------------- ### Setup dash.js with HEVC.js Plugin Source: https://github.com/privaloops/hevc.js/blob/main/README.md Integrate the HEVC.js plugin with dash.js by attaching the support and initializing the player with the worker URL. ```javascript import dashjs from 'dashjs'; import { attachHevcSupport } from '@hevcjs/dashjs-plugin'; const player = dashjs.MediaPlayer().create(); attachHevcSupport(player, { workerUrl: './transcode-worker.js' }); player.initialize(videoElement, 'https://example.com/manifest.mpd', true); ``` -------------------------------- ### Initialize Shaka Player and Load Stream Source: https://github.com/privaloops/hevc.js/blob/main/demo/shaka.html Initialize a Shaka Player instance and attach it to a video element. Then, load a Media Presentation Description (MPD) stream. This is a basic setup after registering the HEVC transmuxer. ```javascript const player = new shaka.Player(); await player.attach(videoElement); await player.load(mpdUrl); ``` -------------------------------- ### Setup Shaka Player with HEVC.js Plugin Source: https://github.com/privaloops/hevc.js/blob/main/README.md Register the HEVC.js transmuxer with Shaka Player and attach compute-aware ABR. Ensure the worker URL is correctly provided. ```javascript import shaka from 'shaka-player'; import { registerHevcTransmuxer } from '@hevcjs/shaka-plugin'; const handle = registerHevcTransmuxer(shaka, { workerUrl: './transcode-worker.js' }); const player = new shaka.Player(); await player.attach(videoElement); handle.attachComputeAware(player); // wire compute-aware ABR (on by default) await player.load('https://example.com/manifest.mpd'); ``` -------------------------------- ### Console Logging Setup Source: https://github.com/privaloops/hevc.js/blob/main/demo/dash.html Redirects console.log, console.warn, and console.error to a dedicated log element and prefixes messages. This is useful for debugging and monitoring player behavior. ```javascript const logEl = document.getElementById('log'); function log(...args) { const line = args.map(a => { if (a instanceof Error) return `${a.name}: ${a.message}`; if (typeof a === 'object') return JSON.stringify(a); return String(a); }).join(' '); logEl.value += line + '\n'; logEl.scrollTop = logEl.scrollHeight; } const _log = console.log, _warn = console.warn, _err = console.error; console.log = (...a) => { _log(...a); log('[log]', ...a); }; console.warn = (...a) => { _warn(...a); log('[warn]', ...a); }; console.error = (...a) => { _err(...a); log('[ERROR]', ...a); }; ``` -------------------------------- ### Load @hevcjs/core from CDN Source: https://github.com/privaloops/hevc.js/blob/main/packages/core/README.md Load the library directly from a CDN for a zero-build setup. This method is useful for quick integration or when a build step is not desired. Ensure the `wasmBinaryUrl` is specified if assets are on a different origin. ```html ``` -------------------------------- ### Dash.js Player Event Handlers Source: https://github.com/privaloops/hevc.js/blob/main/demo/dash.html Sets up event listeners for dash.js player events like quality change, stream initialization, and playback start. It also includes error handling and checks for WebCodecs support. ```javascript // Active variant (refreshed when dash.js switches quality). function refreshActive() { const idx = player.getQualityFor?.('video'); const list = player.getBitrateInfoListFor?.('video') || []; const active = list[idx]; if (active) { document.getElementById('cmp-quality').textContent = 'quality: ' + (active.height ? active.height + 'p' : '?') + ' · ' + Math.round((active.bitrate || 0) / 1000) + ' kbps'; } } player.on(dashjs.MediaPlayer.events.QUALITY_CHANGE_RENDERED, refreshActive); player.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, refreshActive); player.on(dashjs.MediaPlayer.events.PLAYBACK_STARTED, () => { document.getElementById('status').textContent = 'Playing via dash.js + hevc.js'; }); // Warn if HEVC transcoding is unavailable (Firefox — VideoEncoder H.264 broken) player.on(dashjs.MediaPlayer.events.MANIFEST_LOADED, () => { if (typeof VideoEncoder === 'undefined') { document.getElementById('status').textContent = 'This browser does not support WebCodecs. HEVC transcoding is not available. Try Chrome or Edge 94+.'; return; } VideoEncoder.isConfigSupported({ codec: 'avc1.42001f', width: 320, height: 240 }).then(r => { if (!r.supported) { document.getElementById('status').textContent = 'This browser cannot encode H.264 via WebCodecs. HEVC transcoding is not available. Try Chrome or Edge 94+.'; } }).catch(() => {}); }); player.on(dashjs.MediaPlayer.events.ERROR, (e) => { document.getElementById('status').textContent = 'Error: ' + (e.error?.message || JSON.stringify(e.error)); }); player.initialize(video, url, true); document.getElementById('status').textContent = 'Loading ' + url + '...'; } ``` -------------------------------- ### Logging Setup for Diagnostics Source: https://github.com/privaloops/hevc.js/blob/main/demo/shaka.html Redirects console logs (log, warn, error) to a textarea element for debugging and diagnostics. This helps in monitoring Shaka Player's behavior and the HEVC transmuxer's activity. ```javascript const logEl = document.getElementById('log'); function log(...args) { const line = args.map(a => { if (a instanceof Error) return `${a.name}: ${a.message}`; if (typeof a === 'object') return JSON.stringify(a); return String(a); }).join(' '); logEl.value += line + '\n'; logEl.scrollTop = logEl.scrollHeight; } const _log = console.log, _warn = console.warn, _err = console.error; console.log = (...a) => { _log(...a); log('[log]', ...a); }; console.warn = (...a) => { _warn(...a); log('[warn]', ...a); }; console.error = (...a) => { _err(...a); log('[ERROR]', ...a); }; ``` -------------------------------- ### Attach HEVC Support to dash.js Player Source: https://github.com/privaloops/hevc.js/blob/main/site/index.html Integrates HEVC playback capabilities into a dash.js player instance. Ensure the plugin is installed via npm. ```javascript import { attachHevcSupport } from '@hevcjs/dashjs-plugin'; await attachHevcSupport(player); ``` -------------------------------- ### Initialize dash.js Player with HEVC Support (Bundled) Source: https://github.com/privaloops/hevc.js/blob/main/packages/dashjs-plugin/README.md Import and attach the HEVC support to the dash.js player. Ensure the worker and WASM URLs are correctly set to the copied static assets. This code initializes the player with a given video element and manifest URL. ```javascript import dashjs from 'dashjs'; import { attachHevcSupport } from '@hevcjs/dashjs-plugin'; const video = document.querySelector('video'); const player = dashjs.MediaPlayer().create(); await attachHevcSupport(player, { workerUrl: '/transcode-worker.js', wasmUrl: '/hevc-decode.js', }); player.initialize(video, 'https://example.com/stream/manifest.mpd', true); ``` -------------------------------- ### Run End-to-End Browser Tests Source: https://github.com/privaloops/hevc.js/blob/main/CONTRIBUTING.md Builds the demo bundles and then runs the end-to-end browser tests. This requires both the WASM build and demo assets to be ready. ```bash # E2E browser tests (requires built WASM + demo bundles) pnpm build:demo pnpm test:e2e ``` -------------------------------- ### Play/Pause Video Playback Source: https://github.com/privaloops/hevc.js/blob/main/demo/index.html Toggles video playback. Starts or stops an interval timer to cycle through frames. ```javascript document.getElementById('btn-play').addEventListener('click', () => { if (playing) { playing = false; clearInterval(playTimer); document.getElementById('btn-play').textContent = 'Play'; } else { playing = true; document.getElementById('btn-play').textContent = 'Pause'; playTimer = setInterval(() => { if (currentFrame >= frames.length - 1) currentFrame = -1; showFrame(currentFrame + 1); }, 40); } }); ``` -------------------------------- ### Load and Decode Sample File Source: https://github.com/privaloops/hevc.js/blob/main/demo/index.html Fetches a sample HEVC file ('bbb1080_singleslice.265') and sends it to the worker for decoding. ```javascript document.getElementById('use-sample').addEventListener('click', async (e) => { e.stopPropagation(); setStatus('Downloading sample...'); const resp = await fetch('bbb1080_singleslice.265'); const data = await resp.arrayBuffer(); decodeStartTime = performance.now(); worker.postMessage({ type: 'decode', data }, [data]); setStatus('Decoding sample...'); }); ``` -------------------------------- ### Configure Unit Tests with Google Test Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt This snippet sets up Google Test for unit testing. It declares, fetches, and makes Google Test available, then adds an executable for the tests and links it against the main library and the GTest main library. ```cmake if(BUILD_TESTS AND NOT BUILD_WASM) include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.14.0 ) FetchContent_MakeAvailable(googletest) enable_testing() add_executable(hevc_tests tests/unit/test_bitstream_reader.cpp tests/unit/test_nal_parser.cpp tests/unit/test_picture.cpp tests/unit/test_parameter_sets.cpp tests/unit/test_cabac.cpp tests/unit/test_incremental.cpp ) target_link_libraries(hevc_tests PRIVATE hevc-decode-lib GTest::gtest_main ) target_compile_definitions(hevc_tests PRIVATE FIXTURES_DIR="${CMAKE_SOURCE_DIR}/tests/conformance/fixtures" ) include(GoogleTest) gtest_discover_tests(hevc_tests) endif() ``` -------------------------------- ### Initialize dash.js Player with HEVC Support (CDN) Source: https://github.com/privaloops/hevc.js/blob/main/packages/dashjs-plugin/README.md Load the HEVC plugin from a CDN and attach it to the dash.js player. This method is suitable for environments without a build pipeline. Specify URLs for worker, WASM loader, and WASM binary, especially for cross-origin loading. ```html ``` -------------------------------- ### WebGL Initialization and Texture Upload Source: https://github.com/privaloops/hevc.js/blob/main/demo/index.html Initializes the WebGL context, compiles shaders, sets up buffers, and creates textures for Y, Cb, and Cr color planes. Includes functions to upload texture data. ```javascript let gl, program, texY, texCb, texCr, uScale; let worker; let frames = []; let streamInfo = null; let currentFrame = 0; let playing = false; let playTimer = null; let decodeStartTime = 0; let decodeTimeMs = 0; function initGL() { const canvas = document.getElementById('display'); gl = canvas.getContext('webgl'); if (!gl) { setStatus('WebGL not supported'); return false; } const vs = compileShader(gl.VERTEX_SHADER, VERTEX_SRC); const fs = compileShader(gl.FRAGMENT_SHADER, FRAGMENT_SRC); program = gl.createProgram(); gl.attachShader(program, vs); gl.attachShader(program, fs); gl.linkProgram(program); gl.useProgram(program); const buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -1,-1, 0,1, 1,-1, 1,1, -1,1, 0,0, 1,1, 1,0 ]), gl.STATIC_DRAW); const aPos = gl.getAttribLocation(program, 'a_pos'); const aTex = gl.getAttribLocation(program, 'a_tex'); gl.enableVertexAttribArray(aPos); gl.enableVertexAttribArray(aTex); gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0); gl.vertexAttribPointer(aTex, 2, gl.FLOAT, false, 16, 8); texY = createTexture(0); texCb = createTexture(1); texCr = createTexture(2); gl.uniform1i(gl.getUniformLocation(program, 'u_texY'), 0); gl.uniform1i(gl.getUniformLocation(program, 'u_texCb'), 1); gl.uniform1i(gl.getUniformLocation(program, 'u_texCr'), 2); uScale = gl.getUniformLocation(program, 'u_scale'); return true; } function compileShader(type, src) { const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s); return s; } function createTexture(unit) { gl.activeTexture(gl.TEXTURE0 + unit); const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); return tex; } function uploadPlane(tex, unit, data, width, height, bitDepth) { gl.activeTexture(gl.TEXTURE0 + unit); gl.bindTexture(gl.TEXTURE_2D, tex); const scale = bitDepth <= 8 ? 1 : (255 / ((1 << bitDepth) - 1)); const u8 = new Uint8Array(width * height); for (let i = 0; i < width * height; i++) { u8[i] = Math.min(255, Math.round(data[i] * scale)); } gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, u8); } function renderFrame(frame) { const canvas = document.getElementById('display'); canvas.width = frame.width; canvas.height = frame.height; gl.viewport(0, 0, frame.width, frame.height); gl.uniform1f(uScale, 1.0); uploadPlane(texY, 0, frame.dataY, frame.width, frame.height, frame.bitDepth); uploadPlane(texCb, 1, frame.dataCb, frame.width >> 1, frame.height >> 1, frame.bitDepth); uploadPlane(texCr, 2, frame.dataCr, frame.width >> 1, frame.height >> 1, frame.bitDepth); gl.drawArrays(gl.TRIANGLES, 0, 6); } ``` -------------------------------- ### Add Oracle Test for Toy Bitstream (QP45) Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Adds a specific oracle test for a toy bitstream with QP45. This test is labeled 'oracle', 'phase4', and 'toy'. It will skip if the decoder is not yet implemented for this feature. ```cmake add_test(NAME oracle_toy_qp45 COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/toy_qp45.265 64 64 52ca5108bd4354383a9d29d96cf64b47 $) set_tests_properties(oracle_toy_qp45 PROPERTIES LABELS "oracle;phase4;toy" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Enable MSE Intercept for HEVC Playback Source: https://github.com/privaloops/hevc.js/blob/main/packages/core/README.md Use the `installMSEIntercept` function to enable transparent HEVC playback using Media Source Extensions. Ensure the worker and WASM URLs are correctly configured for your server setup. ```javascript import { installMSEIntercept } from '@hevcjs/core'; installMSEIntercept({ workerUrl: '/transcode-worker.js', wasmUrl: '/hevc-decode.js', }); ``` -------------------------------- ### Register HEVC Transmuxer with Shaka Player Source: https://github.com/privaloops/hevc.js/blob/main/demo/shaka.html Import and register the HEVC transmuxer plugin for Shaka Player. This allows Shaka Player to handle HEVC streams by transcoding them to H.264 using WASM. This snippet assumes a zero-build setup loading from a CDN. ```javascript import { registerHevcTransmuxer } from 'https://esm.sh/@hevcjs/shaka-plugin@0'; registerHevcTransmuxer(shaka); ``` -------------------------------- ### HEVC Plugin API and Configuration Options Source: https://github.com/privaloops/hevc.js/blob/main/packages/dashjs-plugin/README.md Demonstrates the usage of the `attachHevcSupport` function with various configuration options. The function returns a cleanup callback to remove patches when no longer needed. ```typescript const cleanup = await attachHevcSupport(player, { workerUrl: '/transcode-worker.js', // URL to the Web Worker script wasmUrl: '/hevc-decode.js', // URL to the Emscripten loader wasmBinaryUrl: '/hevc-decode.wasm', // URL to the .wasm binary — required for cross-origin loading fps: 25, // Target framerate (optional, default: 25) bitrate: 4_000_000, // H.264 encode bitrate (optional) forceTranscode: false, // Bypass native HEVC detection (optional) adaptiveCompute: true, // Compute-aware ABR (default true; pass false to opt out) }); // Remove patches when done (also detaches the compute-aware listener) cleanup(); ``` -------------------------------- ### Initialize dash.js with hevc.js Support Source: https://github.com/privaloops/hevc.js/blob/main/demo/dash.html This snippet shows how to import and attach hevc.js support to a dash.js MediaPlayer instance. It requires specifying URLs for the WASM decoder, WASM binary, and the transcode worker. Use this when you need to play HEVC content via dash.js and want to leverage WASM for transcoding. ```javascript import { attachHevcSupport } from 'https://esm.sh/@hevcjs/dashjs-plugin@1'; const player = dashjs.MediaPlayer().create(); await attachHevcSupport(player, { wasmUrl: 'https://unpkg.com/@hevcjs/core@1/dist/wasm/hevc-decode.js', wasmBinaryUrl: 'https://unpkg.com/@hevcjs/core@1/dist/wasm/hevc-decode.wasm', workerUrl: 'https://unpkg.com/@hevcjs/core@1/dist/transcode-worker.js', }); player.initialize(videoElement, mpdUrl, true); ``` -------------------------------- ### Native Build and Test Source: https://github.com/privaloops/hevc.js/blob/main/CONTRIBUTING.md Builds the project for native execution with debug symbols and runs C++ unit and oracle tests. This is useful for local development and debugging. ```bash # Native build (debug + tests) cmake -B build -DCMAKE_BUILD_TYPE=Debug cmake --build build cd build && ctest --output-on-failure ``` -------------------------------- ### Run Native Tests Source: https://github.com/privaloops/hevc.js/blob/main/CONTRIBUTING.md Executes the C++ unit and oracle tests for the project. This command should be run after a successful native build. ```bash # C++ unit + oracle tests (128 tests) pnpm test:native ``` -------------------------------- ### Add Oracle Test for Phase 5 (P-frames, QCIF, 10 frames) Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Adds an oracle test for Phase 5, focusing on P-frames for a QCIF resolution over 10 frames. This test is labeled 'oracle' and 'phase5'. It will skip if the decoder is not yet implemented for this feature. ```cmake add_test(NAME oracle_p_qcif_10f COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/p_qcif_10f.265 176 144 921650ab84b8e366a1aa4e16f2527e46 $) set_tests_properties(oracle_p_qcif_10f PROPERTIES LABELS "oracle;phase5" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Initialize dash.js Player with HEVC Support Source: https://github.com/privaloops/hevc.js/blob/main/site/docs/dashjs-plugin.html Import the attachHevcSupport function and call it on your dash.js player instance to enable HEVC playback. ```javascript import dashjs from 'dashjs'; import { attachHevcSupport } from '@hevcjs/dashjs-plugin'; const video = document.querySelector('video'); const player = dashjs.MediaPlayer().create(); // One line — that's it attachHevcSupport(player); player.initialize(video, 'https://example.com/stream/manifest.mpd', true); ``` -------------------------------- ### Handle File Drop Events Source: https://github.com/privaloops/hevc.js/blob/main/demo/index.html Sets up event listeners for drag-and-drop file handling. Includes dragover, dragleave, and drop events. ```javascript const dropZone = document.getElementById('drop-zone'); dropZone.addEventListener('click', () => document.getElementById('file-input').click()); dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('dragover'); }); dropZone.addEventListener('dragleave', () => dropZone.classList.remove('dragover')); dropZone.addEventListener('drop', (e) => { e.preventDefault(); dropZone.classList.remove('dragover'); const file = e.dataTransfer.files[0]; if (file) decodeFile(file); }); ``` -------------------------------- ### Initialize WebGL Context Source: https://github.com/privaloops/hevc.js/blob/main/demo/index.html Initializes the WebGL rendering context. Returns true if successful, false otherwise. ```javascript function initGL() { canvas = document.getElementById('canvas'); try { gl = canvas.getContext('webgl2', { antialias: false, depth: false, alpha: false, // Use 'webgl' for older browsers // gl = canvas.getContext('webgl', { antialias: false, depth: false, alpha: false }); }); } catch (e) { console.error(e); return false; } if (!gl) { alert('WebGL 2 not supported'); return false; } const ext = gl.getExtension('EXT_color_buffer_float'); if (!ext) { alert('EXT_color_buffer_float not supported'); return false; } return true; } ``` -------------------------------- ### Add Oracle Test for Toy Bitstream (QP30) Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Adds a specific oracle test for a toy bitstream with QP30. This test is labeled 'oracle', 'phase4', and 'toy'. It will skip if the decoder is not yet implemented for this feature. ```cmake add_test(NAME oracle_toy_qp30 COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/toy_qp30.265 64 64 9f59878470d904dc2e162d3d191611af $) set_tests_properties(oracle_toy_qp30 PROPERTIES LABELS "oracle;phase4;toy" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Add Oracle Test for Phase 5 (B-frames, QCIF, 10 frames) Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Adds an oracle test for Phase 5, focusing on B-frames for a QCIF resolution over 10 frames. This test is labeled 'oracle' and 'phase5'. It will skip if the decoder is not yet implemented for this feature. ```cmake add_test(NAME oracle_b_qcif_10f COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/b_qcif_10f.265 176 144 dffe2712c0561c75ee40256d59299826 $) set_tests_properties(oracle_b_qcif_10f PROPERTIES LABELS "oracle;phase5" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Add Oracle Test for Toy Bitstream (QP10) Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Adds a specific oracle test for a toy bitstream with QP10. This test is labeled 'oracle', 'phase4', and 'toy'. It will skip if the decoder is not yet implemented for this feature. ```cmake add_test(NAME oracle_toy_qp10 COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/toy_qp10.265 64 64 ff469ce7e872152490b9b39b0d05dd7b $) set_tests_properties(oracle_toy_qp10 PROPERTIES LABELS "oracle;phase4;toy" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Add Oracle Test for Phase 4 (I-frame, 64x64, QP22) Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Adds an oracle test for Phase 4, specifically an I-frame of size 64x64 with QP22. This test is labeled 'oracle' and 'phase4'. It will skip if the decoder is not yet implemented for this feature. ```cmake add_test(NAME oracle_i_64x64_qp22 COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/i_64x64_qp22.265 64 64 48c64cd2de381113913149e92065d66c $) set_tests_properties(oracle_i_64x64_qp22 PROPERTIES LABELS "oracle;phase4" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Native Debug Build with Tests Source: https://github.com/privaloops/hevc.js/blob/main/README.md Instructions for building the decoder in debug mode with tests enabled using CMake. This is useful for development and verification. ```bash cmake -B build -DCMAKE_BUILD_TYPE=Debug cmake --build build cd build && ctest --output-on-failure # 128 tests ``` -------------------------------- ### Attach, Load, and Play Media Source: https://github.com/privaloops/hevc.js/blob/main/demo/shaka.html Attaches the player to the video element, loads the specified media URL, and attempts to play the media. Includes error handling for loading and a catch for potential autoplay blocking. ```javascript try { console.log('[demo] player.attach()'); await player.attach(video); console.log('[demo] player.load()', url); await player.load(url); video.play().catch((e) => console.warn('[demo] video.play() blocked', e?.message)); document.getElementById('status').textContent = 'Loaded — playback should start'; } catch (e) { console.error('[demo] load error', e); document.getElementById('status').textContent = 'Load error: ' + (e.message || JSON.stringify(e)); } ``` -------------------------------- ### Configure Oracle Conformance Tests Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt This section configures 'oracle' conformance tests that compare the decoder's YUV output MD5 against a reference. These tests are designed to be run separately using `ctest -L oracle` and will skip gracefully if the decoder cannot produce output for a specific feature. ```cmake set(FIXTURES_DIR "${CMAKE_SOURCE_DIR}/tests/conformance/fixtures") set(ORACLE_SCRIPT "${CMAKE_SOURCE_DIR}/tools/oracle_test.sh") # All oracle tests skip gracefully when decoder can't produce output yet # Exit code 2 = SKIP (decoder not implemented for this feature) ``` -------------------------------- ### Load HEVC Stream with dash.js and HEVC.js Source: https://github.com/privaloops/hevc.js/blob/main/site/index.html Initializes a dash.js player to load and play an HEVC stream, attaching HEVC.js for decoding. This function also sets up event listeners for playback status and errors. ```javascript let player = null; async function loadStream() { const url = '../demo/streams/dash_abr/manifest.mpd'; const video = document.getElementById('player'); player = dashjs.MediaPlayer().create(); await HevcDash.attachHevcSupport(player, { workerUrl: '../demo/transcode-worker.js', }); player.on(dashjs.MediaPlayer.events.PLAYBACK_STARTED, () => { document.getElementById('status').textContent = 'Playing via dash.js + hevc.js'; }); player.on(dashjs.MediaPlayer.events.ERROR, (e) => { document.getElementById('status').textContent = 'Error: ' + (e.error && e.error.message ? e.error.message : JSON.stringify(e.error)); }); player.initialize(video, url, true); document.getElementById('status').textContent = 'Loading HEVC stream…'; } ``` -------------------------------- ### Add CLI Executable Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Defines the native command-line interface executable for the project. Links against the main library. ```cmake add_executable(hevc-decode src/main.cpp ) target_link_libraries(hevc-decode PRIVATE hevc-decode-lib) ``` -------------------------------- ### Configure Compute-aware ABR Settings Source: https://github.com/privaloops/hevc.js/blob/main/packages/shaka-plugin/README.md Customize the behavior of the compute-aware Adaptive Bitrate (ABR) by adjusting parameters like target speed and thresholds. This allows for finer control over variant selection based on transcoding performance. ```javascript // Tune the decider (defaults: measureWindow 2, lowerAfter 1, raiseAfter 6, targetSpeedX 1.3) registerHevcTransmuxer(shaka, { adaptiveCompute: { targetSpeedX: 1.5, lowerAfter: 2 }, }); // Telemetry hook — fires per segment, not just on cap changes handle.attachComputeAware(player, { onObservation: (stat, avgSpeedX, capIndex, reason) => { console.log(`speedX=${stat.speedX.toFixed(2)} cap=${capIndex} (${reason})`); }, }); // Opt out registerHevcTransmuxer(shaka, { adaptiveCompute: false }); ``` -------------------------------- ### Add Test for 10-bit Full QCIF 10fps Bitstream Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Defines a test case for a 10-bit Main 10 profile Full QCIF 10fps bitstream using the ORACLE_SCRIPT. This test is part of the phase 7 milestone suite. ```cmake add_test(NAME oracle_full_qcif_10f_10bit COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/full_qcif_10f_10bit.265 176 144 19efbf36509c6ecb86e42a7f709998b5 $ yuv420p10le) set_tests_properties(oracle_full_qcif_10f_10bit PROPERTIES LABELS "oracle;phase7;main10;milestone" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Copy Static Assets Source: https://github.com/privaloops/hevc.js/blob/main/packages/core/README.md Copy the necessary static files (worker, Emscripten glue code, and WASM binary) from node_modules to your public/static directory. Adjust the destination path as needed for your project structure. ```bash cp node_modules/@hevcjs/core/dist/transcode-worker.js public/ cp node_modules/@hevcjs/core/dist/wasm/hevc-decode.js public/ cp node_modules/@hevcjs/core/dist/wasm/hevc-decode.wasm public/ ``` -------------------------------- ### C API Usage for HEVC Decoding Source: https://github.com/privaloops/hevc.js/blob/main/README.md Demonstrates the basic lifecycle and decoding process using the C API. Ensure the 'wasm/hevc_api.h' header is included. ```c #include "wasm/hevc_api.h" HEVCDecoder* dec = hevc_decoder_create(); hevc_decoder_decode(dec, data, size); int count = hevc_decoder_get_frame_count(dec); for (int i = 0; i < count; i++) { HEVCFrame frame; hevc_decoder_get_frame(dec, i, &frame); // frame.y / frame.cb / frame.cr — YUV planes (uint16_t*) // frame.width / frame.height — luma dimensions // frame.bit_depth — 8 or 10 } hevc_decoder_destroy(dec); ``` -------------------------------- ### Register HEVC Transmuxer and Load Stream Source: https://github.com/privaloops/hevc.js/blob/main/packages/shaka-plugin/README.md Import and register the HEVC transmuxer, then attach it to a Shaka Player instance and load a media stream. The compute-aware ABR is enabled by default. ```javascript import shaka from 'shaka-player'; import { registerHevcTransmuxer } from '@hevcjs/shaka-plugin'; const handle = registerHevcTransmuxer(shaka, { workerUrl: '/transcode-worker.js', wasmUrl: '/hevc-decode.js', }); const player = new shaka.Player(); await player.attach(document.querySelector('video')); handle.attachComputeAware(player); // compute-aware ABR (on by default) await player.load('https://example.com/stream/manifest.mpd'); // later: handle(); // unregisters transmuxer AND detaches compute-aware ``` -------------------------------- ### Add Test for Big Buck Bunny 1080p 50fps Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Defines a test case for the Big Buck Bunny 1080p 50fps bitstream using the ORACLE_SCRIPT. This test is part of the real-world bitstream suite. ```cmake add_test(NAME oracle_bbb1080_50f COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/bbb1080_50f.265 1920 1080 a7c12e24701e3636ce58246033bff6ed $) set_tests_properties(oracle_bbb1080_50f PROPERTIES LABELS "oracle;phase6;realworld" SKIP_RETURN_CODE 2) ``` -------------------------------- ### Initialize Web Worker for Decoding Source: https://github.com/privaloops/hevc.js/blob/main/demo/index.html Initializes the Web Worker for HEVC decoding. Sets up message handling for communication with the worker. ```javascript function initWorker() { worker = new Worker('worker.js'); worker.onmessage = (e) => { const msg = e.data; switch (msg.type) { case 'ready': setStatus('Ready — open a .265 file or use the sample clip'); break; case 'info': streamInfo = msg.info; break; case 'frame': frames.push(msg.frame); break; case 'done': decodeTimeMs = performance.now() - decodeStartTime; setStatus(`Decoded ${msg.frameCount} frames in ${(decodeTimeMs / 1000).toFixed(2)}s`); updateInfo(); if (frames.length > 0) { currentFrame = 0; showFrame(0); document.getElementById('btn-prev').disabled = false; document.getElementById('btn-next').disabled = false; document.getElementById('btn-play').disabled = false; } break; case 'error': setStatus('Error: ' + msg.message); break; } }; worker.postMessage({ type: 'init', wasmUrl: 'hevc-decode.js' }); } ``` -------------------------------- ### Enable Adaptive Compute Source: https://github.com/privaloops/hevc.js/blob/main/site/docs/dashjs-plugin.html Enables compute-aware adaptive bitrate control by default. This caps dash.js variants when the device cannot sustain transcoding in real-time. It also provides options to tune specific knobs or opt out entirely. ```javascript // Default — adaptiveCompute is ON, defaults are sensible const cleanup = await attachHevcSupport(player, { workerUrl: '/transcode-worker.js', }); // To tune knobs: // attachHevcSupport(player, { adaptiveCompute: { targetSpeedX: 1.5 } }) // To opt out: // attachHevcSupport(player, { adaptiveCompute: false }) player.initialize(videoElement, mpdUrl, true); // Cleanup detaches the compute-aware listener AND uninstalls MSE intercept cleanup(); ``` -------------------------------- ### WebAssembly Build with Emscripten Source: https://github.com/privaloops/hevc.js/blob/main/README.md Steps to compile the HEVC decoder to WebAssembly using Emscripten and CMake. This produces a small JS/WASM bundle suitable for web deployment. ```bash source ~/emsdk/emsdk_env.sh emcmake cmake -B build-wasm -DBUILD_WASM=ON -DCMAKE_BUILD_TYPE=Release cmake --build build-wasm # Output: build-wasm/hevc-decode.js + hevc-decode.wasm (236KB) ``` -------------------------------- ### adaptiveCompute Source: https://github.com/privaloops/hevc.js/blob/main/site/docs/shaka-plugin.html Enables compute-aware adaptive bitrate (ABR) that caps Shaka variants when the device cannot sustain transcoding at real-time. This feature is enabled by default. ```APIDOC ### adaptiveCompute — compute-aware ABR on by default Feedback loop that caps Shaka variants when the device can't sustain transcoding at real-time. Shaka's bandwidth-based ABR keeps choosing freely — we only narrow the ceiling it's allowed to pick from. Useful on devices where WASM HEVC decode + WebCodecs H.264 encode runs slower than playback (typical on low-end Windows boxes at 1080p+). **On by default** — pass `adaptiveCompute: false` to opt out. #### Example Usage ```javascript // Default — adaptiveCompute is ON, defaults are sensible const handle = registerHevcTransmuxer(shaka, { workerUrl: '/transcode-worker.js', }); // To tune knobs: // registerHevcTransmuxer(shaka, { adaptiveCompute: { targetSpeedX: 1.5 } }) // To opt out: // registerHevcTransmuxer(shaka, { adaptiveCompute: false }) const player = new shaka.Player(); const detach = handle.attachComputeAware(player); // after player exists await player.load(manifestUrl); // Cleanup detach(); // stop observing handle(); // unregister transmuxer + detach ``` #### Tuning knobs - `targetSpeedX` (number, default 1.3): Required headroom over real-time before the cap is allowed to rise. `1.3` means the rolling average must show transcode at 1.3× real-time before we let the host ABR pick a higher variant. - `measureWindow` (number, default 2): Rolling-window size for smoothing. Default is intentionally small — the cost of staying too long at an unreachable quality (buffer underrun, frozen playback) is much worse than the cost of a brief unnecessary dip. - `lowerAfter` (number, default 1): Consecutive windows averaging below 1.0× before lowering the cap one notch. Default `1` — react on the first confirmed low window. - `raiseAfter` (number, default 6): Consecutive windows averaging above `targetSpeedX` before raising the cap one notch. Wider than `lowerAfter` by design — hysteresis prevents yo-yo between two adjacent variants. - `onObservation` ((stat, avg, cap) => void): Optional telemetry sink called for every segment (not just cap changes). Handy for plotting `speedX` over time in a demo or admin panel. Caps are applied via Shaka's public `player.configure({ abr: { restrictions: { maxHeight, maxBandwidth } } })` — no fork of the ABR controller, no reach into private APIs. ``` -------------------------------- ### Configure Compute-aware ABR for HEVC Plugin Source: https://github.com/privaloops/hevc.js/blob/main/packages/dashjs-plugin/README.md Customize the adaptive compute settings for the HEVC plugin. This includes adjusting parameters like `targetSpeedX` and `lowerAfter`, or providing a telemetry hook for observation. ```javascript // Tune (defaults: measureWindow 2, lowerAfter 1, raiseAfter 6, targetSpeedX 1.3) await attachHevcSupport(player, { adaptiveCompute: { targetSpeedX: 1.5, lowerAfter: 2 }, }); // Telemetry hook — fires per segment, not just on cap changes await attachHevcSupport(player, { adaptiveCompute: { onObservation: (stat, avgSpeedX, capIndex, reason) => { console.log(`speedX=${stat.speedX.toFixed(2)} cap=${capIndex} (${reason})`); }, }, }); // Opt out await attachHevcSupport(player, { adaptiveCompute: false }); ``` -------------------------------- ### Initialize and Transcode Media Segments with SegmentTranscoder Source: https://github.com/privaloops/hevc.js/blob/main/site/docs/shaka-plugin.html This snippet demonstrates how to use the SegmentTranscoder from '@hevcjs/core' for advanced, direct transcoding. It requires initializing the transcoder, preparing an init segment, and then processing media segments. ```javascript import { SegmentTranscoder } from '@hevcjs/core'; const transcoder = new SegmentTranscoder({ fps: 25 }); await transcoder.init(); // Synthesize a matching H.264 init segment up-front const init = await transcoder.prepareInit(hevcInitBytes); // Then transcode media segments const h264Segment = await transcoder.processMediaSegment(mediaSegmentBytes); ``` -------------------------------- ### Add Oracle Test for Phase 6 (Full Pipeline, Milestone) Source: https://github.com/privaloops/hevc.js/blob/main/CMakeLists.txt Adds an oracle test for Phase 6, representing the full pipeline with B-frames, deblocking, and SAO, considered a Main profile milestone. This test is labeled 'oracle', 'phase6', and 'milestone'. It will skip if the decoder is not yet implemented for this feature. ```cmake add_test(NAME oracle_full_qcif_10f COMMAND ${ORACLE_SCRIPT} ${FIXTURES_DIR}/full_qcif_10f.265 176 144 a4984ee61d18ac9619808c5338132eaa $) set_tests_properties(oracle_full_qcif_10f PROPERTIES LABELS "oracle;phase6;milestone" SKIP_RETURN_CODE 2) ``` -------------------------------- ### WASM Build Source: https://github.com/privaloops/hevc.js/blob/main/CONTRIBUTING.md Builds the project for WebAssembly (WASM) targets using Emscripten. This is necessary for browser-based execution. ```bash # WASM build source ~/emsdk/emsdk_env.sh emcmake cmake -B build-wasm -DBUILD_WASM=ON -DCMAKE_BUILD_TYPE=Release cmake --build build-wasm ```