UNPKG

mfx

Version:

In-browser video editing toolkit, with effects accelerated by WebGL

121 lines (103 loc) 3.37 kB
import JsWebm from "jswebm"; import { ContainerDecoder } from "../ContainerDecoder"; import { type AudioTrack, TrackType, type VideoTrack } from "../Track"; import { next } from "../../utils"; /** * @group Decode */ export class WebMContainerDecoder extends ContainerDecoder<any> { get identifier() { return "WebMContainerDecoder"; } constructor({ videoCodec = "vp8", audioCodec = "" }) { const demuxer = new JsWebm(); super({ transform: async (chunk) => { demuxer.queueData(chunk.buffer); }, flush: async () => { while (!demuxer.videoTrack && !demuxer.eof) { await demuxer.demux(); } let videoCursor = 0; let audioCursor = 0; const { videoTrack, audioTrack } = demuxer; const processedVideoTrack: VideoTrack<any> | null = videoTrack ? { id: videoTrack.trackUID, type: TrackType.Video, duration: 0, config: { codec: videoCodec, codedHeight: videoTrack.height, codedWidth: videoTrack.width, }, toChunk: (sample) => new EncodedVideoChunk({ type: sample.isKeyframe ? "key" : "delta", timestamp: sample.timestamp * demuxer.segmentInfo.timecodeScale, data: sample.data, transfer: [sample.data], }), } : null; const processedAudioTrack: AudioTrack<any> | null = audioTrack ? { id: audioTrack.trackUID, type: TrackType.Audio, config: { codec: audioCodec || demuxer.audioCodec, numberOfChannels: audioTrack.channels, sampleRate: audioTrack.rate, }, toChunk: (sample) => new EncodedAudioChunk({ type: "key", data: sample.data, timestamp: sample.timestamp * demuxer.segmentInfo.timecodeScale, }), } : null; const tracks = [ /** * @note * Skip video if not available to support * audio only (m4a) files */ ...(processedVideoTrack ? [processedVideoTrack] : []), ...(processedAudioTrack ? [processedAudioTrack] : []), ]; this.start(tracks); while (!demuxer.eof) { await demuxer.demux(); await next(0); if (!this.desiredSize) { await next(0); continue; } while (videoCursor < demuxer.videoPackets.length) { const packet = demuxer.videoPackets[videoCursor]; if (videoCursor === 0) { packet.isKeyframe = true; } this.queue({ track: processedVideoTrack, samples: [packet], }); videoCursor++; } while (audioCursor < demuxer.audioPackets.length) { const packet = demuxer.audioPackets[audioCursor]; this.queue({ track: processedAudioTrack, samples: [packet], }); audioCursor++; } } }, }); } }