UNPKG

realview.js

Version:

RealView.js - High-performance video decoder for the browser

107 lines (106 loc) 3.33 kB
import { parseSPS } from "./SPSParser"; import { parseNALStream } from "./nalstream"; // Merge NAL Units from all packets into a single // continuous buffer, separated by 4-byte length headers function mergeNALUs(nalus, length) { const arr = new Uint8Array(length); const view = new DataView(arr.buffer); for (let i = 0, offset = 0; offset < length; i++) { const unit = nalus[i]; view.setUint32(offset, unit.byteLength); arr.set(unit, offset + 4); offset += unit.byteLength + 4; } return arr; } export class VideoStream { constructor() { this.last_packet = null; this.nalus = []; this.pps = null; this.sps = null; this.samples = []; this.duration = 0; this.frame_sum = 0; this.frame_count = 0; this.zeroes = 0; this.byteLength = 0; } process(packet) { if (!this.last_packet) { this.last_packet = packet; return; } const { nalus } = this; const next = packet; packet = this.last_packet; let size = 0; let isIDR = false; for (const nalUnit of parseNALStream(packet.data)) { switch (nalUnit[0] & 0x1f) { case 7: this.sps = nalUnit; break; case 8: this.pps = nalUnit; break; case 5: isIDR = true; size += nalUnit.length + 4; nalus.push(nalUnit); break; default: // eslint-disable-line no-fallthrough size += nalUnit.length + 4; nalus.push(nalUnit); } } const dts_delta = next.dts - packet.dts; this.samples.push({ size, isIDR, offset: this.byteLength, pts: packet.pts, dts: packet.dts, cts: packet.pts - packet.dts, duration: dts_delta, }); if (dts_delta) { this.duration += dts_delta; this.frame_sum += dts_delta; this.frame_count++; } else { this.zeroes++; } this.byteLength += size; this.last_packet = next; } getTrack() { const { frame_count, frame_sum, zeroes, samples, sps, pps, nalus, byteLength, } = this; const frame_rate = Math.round(frame_sum / frame_count); const duration = this.duration + zeroes * frame_rate; if (!sps) { return null; } const spsInfo = parseSPS(sps); const cropping = spsInfo.frame_cropping; let track = { type: "video", pps, sps, spsInfo, width: spsInfo.pic_width_in_mbs * 16 - (cropping.left + cropping.right) * 2, height: (2 - spsInfo.frame_mbs_only_flag) * (spsInfo.pic_height_in_map_units * 16) - (cropping.top + cropping.bottom) * 2, samples, duration, byte_offset: 0, data: mergeNALUs(nalus, byteLength), }; this.samples = []; this.nalus = []; this.byteLength = 0; return track; } }