|
| 1 | +// Assuming you have: |
| 2 | +// - an H.264 IDR (keyframe) NAL unit(s) as a Uint8Array: keyframeBytes |
| 3 | +// - optional following delta frame(s): deltaBytes |
| 4 | +// - SPS and PPS NAL units extracted as Uint8Array: spsBytes, ppsBytes |
| 5 | + |
| 6 | +// Build an AVCDecoderConfigRecord (description) by concatenating SPS/PPS in Annex B or AVCC form. |
| 7 | +// For AVCC, you need a proper 'description' (AVCDecoderConfigurationRecord) buffer. |
| 8 | +// For a quick start, many browsers accept Annex B with parameter sets in 'description' too. |
| 9 | + |
| 10 | + |
| 11 | + var config = { |
| 12 | + codec: 'avc1.42E01E', // baseline profile example; replace if needed |
| 13 | + description: buildAvcDecoderConfigRecord(spsBytes, ppsBytes) // Uint8Array |
| 14 | + }; |
| 15 | + |
| 16 | + var decoder = new VideoDecoder({ |
| 17 | + output: async (frame) => { |
| 18 | + // Draw to canvas |
| 19 | + var bitmap = await createImageBitmap(frame); |
| 20 | + var canvas = document.createElement('canvas'); |
| 21 | + canvas.width = bitmap.width; |
| 22 | + canvas.height = bitmap.height; |
| 23 | + var ctx = canvas.getContext('2d'); |
| 24 | + ctx.drawImage(bitmap, 0, 0); |
| 25 | + bitmap.close(); |
| 26 | + frame.close(); |
| 27 | + |
| 28 | + // Export JPEG |
| 29 | + canvas.toBlob( |
| 30 | + (blob) => { |
| 31 | + // blob is a JPEG; do something with it (download, upload, etc.) |
| 32 | + // e.g., createObjectURL(blob) for preview |
| 33 | + }, |
| 34 | + 'image/jpeg', |
| 35 | + 0.92 |
| 36 | + ); |
| 37 | + }, |
| 38 | + error: (e) => console.error('Decode error', e) |
| 39 | + }); |
| 40 | + |
| 41 | + decoder.configure(config); |
| 42 | + |
| 43 | + // Wrap raw H.264 bytes into EncodedVideoChunks (Annex B or AVCC formatted appropriately) |
| 44 | + // The 'type' must be 'key' for IDR frames and 'delta' for non-key frames. |
| 45 | + |
| 46 | + function makeChunk(bytes, timestamp, isKey) { |
| 47 | + return new EncodedVideoChunk({ |
| 48 | + timestamp, // in microseconds if you care |
| 49 | + type: isKey ? 'key' : 'delta', |
| 50 | + data: bytes |
| 51 | + }); |
| 52 | + } |
| 53 | + |
| 54 | + // Feed the keyframe first |
| 55 | + decoder.decode(makeChunk(keyframeBytes, 0, true)); |
| 56 | + |
| 57 | + // Optionally feed the next frame(s) |
| 58 | + decoder.decode(makeChunk(deltaBytes, 33333, false)); // ~30fps timestamp |
0 commit comments