Stable volume, experimental super resolution and integration skills
This SDK release includes these optional APIs. Check capabilities when integrating an older cached bundle. Both playback enhancements are off by default. They keep the existing media route, clock and user volume controls.
| Feature | Purpose | Default and availability |
|---|---|---|
| Stable volume | Reduce differences between quiet and loud sections using RMS automatic gain control and peak protection | None; StableVolume requires a usable browser audio graph and accessible audio track |
| Experimental super resolution | Fixed tiny AN CNN in the renderer's WebGL2 context | Disabled; confirmed compatible SDR input and device performance are required |
| Integration and troubleshooting skills | Generate demos or diagnose integration problems with evidence | Two standalone skills; templates for vanilla JS, React, Vue, Svelte, Angular, Next and Nuxt |
Operate the demos
The website home demo and full player share the playback-enhancements panel. The SDK distribution’s index.html / index-cn.html, the development repository’s dynamic index.html and fixed index-multi.html use the same interaction. Each player has its own two switches.
| Action | When it is available | What the panel shows |
|---|---|---|
| Enable stable volume | Preset before creation or switch during playback; no rebuild needed | Waiting for audio, processing, or an unavailable reason |
| Enable SR | Preset before creation or request it after creation; ready is not a prerequisite for the request | First use selects “One step up”; actual output size, frame/model progress or a reason for preserving the original |
| Change SR output | Choose “One step up”, “Automatic” or an offered size during playback | “One step up” uses the smallest currently available enhanced option; “Automatic” uses the SDK’s standard selection policy |
| Disable an effect | Switch it off during playback | Audio processing bypasses or the original picture returns; user volume and mute stay unchanged |
| Change the SDR declaration or apply a renderer requiring recreation | Explicitly reload when prompted | VOD starts from the beginning; live playback reconnects. Toggling an effect does not silently reload media |
The switch is a request; the status shows the actual result. SR can be requested before the first frame, but usable video frames are needed to choose an output, load the model and evaluate performance. A first enable while paused may wait for playback to resume. warming can already include enhanced output; active also means the current output has passed the performance evaluation.
Arbitrary sources start with unknown color. SDR confirmation belongs to the current media URL. After changing sources, confirm the new source and apply the declaration again when prompted. Choose “Confirmed SDR” only for verified compatible media, then apply and reload when prompted. This is a build-time declaration; set_super_resolution() cannot change it at runtime. The bundled SDR home clip can be declared in advance; verify color again for your own replacement media. Unknown color, HDR, ERP, a display that needs no enlargement or an unsupported device keeps the original picture with a reason.
Stable volume reduces loudness differences rather than applying a multiband EQ. It works before user volume, so enabling it does not unmute playback. Adjust volume yourself to listen. An older SDK without the APIs disables the corresponding controls and points to the current build.
The demo’s stable-volume switch only changes the leveling request; it does not call play or notify a user gesture. If audio remains pending for activation, Play & activate audio is a separate, explicit action that starts or resumes playback through the entry’s play handler. It preserves the user’s volume/mute setting and keeps the playback button state in sync.
Playback environment and hosting
The website home and player demos load the website’s current SDK and WASM from the same origin by default. Use ?sdk=cdn only to diagnose the pinned CDN release; remove it to return to the website build. The home demo uses a same-origin SDR sample and an isolated page. Both effects still start off.
The full player and SDK demos accept arbitrary URLs and start in Compatibility mode. Choose Enable software decoding when a path needs WASM/shared memory. This reloads the page with ?isolation=1; Return to compatibility mode removes it. The tab restores URLs, core choices, volume/mute, enhancement switches and requested SR output. The temporary sessionStorage record expires after 10 minutes and is removed after the restore attempt. Playback reconnects; this does not preserve a running decoder or VOD position.
?isolation=1 is a demo hosting contract, not an SDK API or a way to create response headers. The host must send Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp on the isolated document in a secure context; a direct pthread Worker script also needs COEP. The panel checks the real browser environment and reports missing support without repeatedly reloading. Keep SDK/glue/WASM files from the same build, serve WASM as application/wasm, and allow required cross-origin resources through CORS/CORP. In isolated mode, ordinary cross-origin no-CORS video needs CORP; an Access-Control-Allow-Origin header alone does not change its request mode. Compatibility mode retains native playback’s existing request behavior.
SR on a compatible native video does not require the software-decoding switch. Its frame access, SDR declaration, model, output-size and GPU requirements still apply. These page controls do not change the SDK’s core-selection or enhancement algorithms. When embedding only the enhancement controls, do not add an environment reload requirement to native SR. The distribution also includes demo-environment.js and demo-environment.css; reuse the full demo’s capture/restore wiring if you expose the page environment switch. Static hosting must supply the response headers—copying the helper or using plain python3 -m http.server is not enough.
Start with normal playback
Copy the three runtime files from the same build. To use super resolution, also copy the complete models/sr/ directory, including its manifest, weights and license notices, alongside the WASM JS. Ordinary playback does not download a model when SR stays off.
sdk/
├── h265web.js
├── h265web_wasm.js
├── h265web_wasm.wasm
└── models/sr/ # Required only for SRBind callbacks before build() and keep them limited to what the application needs. Low-level frame callbacks can affect core selection. Model state is separate from media errors.
const player = H265webjsPlayer();
const hasLeveling = typeof player.set_audio_leveling === 'function' &&
typeof player.get_audio_leveling_state === 'function';
const hasSR = typeof player.set_super_resolution === 'function' &&
typeof player.get_super_resolution_state === 'function';
player.on_ready_show_done_callback = () => console.log('Ready');
player.on_error_callback = error => console.error(error);
if (hasSR) player.on_super_resolution_state = state => console.log('SR', state);
const config = {
player_id: 'player', width: 960, height: 540,
base_url: './sdk/', wasm_js_uri: 'h265web_wasm.js',
wasm_wasm_uri: 'h265web_wasm.wasm', ignore_audio: false, auto_play: false
};
if (hasLeveling) config.audio_leveling = 'None';
// Declare SDR only when the source has been verified as compatible SDR.
if (hasSR) config.super_resolution = { enabled: false, input_color: 'unknown' };
if (!player.build(config)) throw new Error('Player build failed');
player.set_voice(0);
player.load_media('./media/demo.mp4');Replace ./media/demo.mp4 with your own playable media URL. Place <div id="player"></div> in the page before running this code. In an actual user click handler, call player.notify_user_gesture() and player.play() to satisfy browser activation requirements. Keep mute and user volume under application control.
Stable volume and user volume are independent
if (hasLeveling) {
player.set_audio_leveling('StableVolume');
console.log(player.get_audio_leveling_state());
player.set_audio_leveling('None');
}
player.set_voice(0.3); // User's final 0–1 output volumeThe processing order is source audio → automatic gain / peak protection → user volume → output. Enabling the feature does not move the volume slider or unmute playback. set_voice(0) remains silent; ignore_audio: true skips audio initialization and cannot be reversed by adjusting volume.
An accepted request is not proof of processing. Inspect status (disabled, pending, active, unavailable) and reason. Browser user activation, AudioWorklet support, source security and the presence of an audio track determine actual availability. An unavailable feature preserves playback and does not force another video core. This is not an EQ, LUFS normalizer or true-peak certification.
Experimental super resolution
For verified compatible SDR media, set input_color: 'sdr' in the initial build configuration. The default unknown safely bypasses enhancement. Keep HDR and wide-gamut sources out of this opt-in declaration.
if (hasSR) {
// One step up: use the smallest currently available enhanced option.
player.set_super_resolution({ enabled: true, level: 'light', targetKey: null });
// When the user selects Automatic:
// player.set_super_resolution({ enabled: true, level: 'standard', targetKey: null });
// Populate or refresh controls from subsequent state notifications.
// In a later, separate user action: player.set_super_resolution(false);
}Inspect status, reason, source, output and options; a true return accepts intent only. States are off, loading, warming, active, bypass and released. Read the initial state after build; a player that never enables SR does not emit unused SR notifications. warming may already display enhanced frames; active also requires passing GPU timing windows.
At most two aspect-preserving candidates use 1.25×, 1.5× or 2×. Input short side must be ≤720; output long side ≤1920, short side ≤1080 and total pixels ≤2,073,600, subject to viewport and device budget. A 720p source may offer 900p/1080p experimental candidates; bitrate does not unlock 1440p/4K. These limits apply to enhancement, not ordinary high-resolution playback.
| Source / condition | Behavior |
|---|---|
| Compatible native video, WebCodec VideoFrame or verified I420 | Can use the shared WebGL2 effect when the source and budget qualify |
| Existing C++ renderer | renderer-recreate-required; an explicit rebuild creates a renderer that can support SR; no automatic reload |
| Old WASM without a trustworthy I420 descriptor | Normal playback continues; SR bypasses |
| Unknown color, HDR / wide gamut, ERP, native PiP/video-only fullscreen or unsupported captions | Original picture with a reason |
| Model failure, unsupported GPU or sustained budget failure | Original picture with a reason; no SR media error or core switch |
The SDK ships one fixed experimental AN model. WASM/ORT and WebGPU comparison experiments are research results, not selectable SDK SR backends. GPU correctness tests prove the implementation follows its mathematical recipe; they do not prove every source looks better. Mobile devices, long-term temperature/power and production picture-quality approval remain outside the current acceptance scope.
Reuse the shared switch panel
The SDK distribution includes standalone demo-enhancements.js and demo-enhancements.css page controls that call public player APIs. Serve them from your SDK directory. Keep matching runtime JS/WASM files and models/sr/ inside static/. Connect the following fragment to your existing creation/release flow; the minimal playback example can stay intact.
<link rel="stylesheet" href="./sdk/demo-enhancements.css">
<script src="./sdk/static/h265web.js"></script>
<script src="./sdk/demo-enhancements.js"></script>
<div id="player"></div>
<fieldset id="playback-enhancements" data-locale="en"></fieldset>
<button id="load-media" type="button">Create and load</button>
<button id="play-media" type="button">Play</button>let player = null;
let recreating = false;
const mediaUrl = './media/demo.mp4';
const config = {
player_id: 'player', width: 960, height: 540,
base_url: './sdk/static/', wasm_js_uri: 'h265web_wasm.js',
wasm_wasm_uri: 'h265web_wasm.wasm', auto_play: false, ignore_audio: false
};
const controls = createPlaybackEnhancementControls(
document.getElementById('playback-enhancements'), () => player,
{recreate: recreatePlayer}
);
function createPlayer() {
const current = H265webjsPlayer();
player = current;
current.on_error_callback = error => console.error(error);
// Bind application callbacks, then controls, before build.
controls.bind(current);
if (!current.build({...config, ...controls.buildConfig(current)})) {
player = null;
controls.unbind();
current.release();
return;
}
current.set_voice(0); // Initial mute; retain user-selected volume in your application.
controls.refresh();
current.load_media(mediaUrl);
}
function recreatePlayer() {
if (recreating) return;
recreating = true;
const previous = player;
player = null;
controls.unbind();
const start = () => { recreating = false; createPlayer(); };
if (previous) previous.release(start);
else start();
}
document.getElementById('load-media').onclick = recreatePlayer;
document.getElementById('play-media').onclick = () => {
if (!player) return;
player.notify_user_gesture();
player.play();
};Replace mediaUrl with a playable URL and resolve asset paths from your page. Reloading is an explicit user action; production components must also invalidate late work on unmount and wait for release completion. For volume, seeking and full interaction, use the distribution’s English demo or the website player, rather than maintaining another control implementation in every example.
Use the integration and troubleshooting skills
The SDK repository contains skills/h265web-bootstrap/ and skills/h265web-troubleshoot/. Copy each complete directory to the skill location supported by your coding assistant; retain its scripts, references and assets. Use the SDK from the same checkout when generating a local demo.
- Ask
$h265web-bootstrapto create a demo or integrate an existing framework. Request stable-volume and SR controls explicitly; keep them optional and capability-checked. - Ask
$h265web-troubleshootto inspect media, HTTP delivery, actual core selection, lifecycle and feature states. A requested core or enabled switch is not evidence of actual playback or enhancement.
For release/unmount, use the completion callback of player.release(callback) before reusing a container. Rapid source changes and delayed SDK/model loads must not resurrect an old component.
See API Docs, Get Started and QA WIKI for the complete contract.