UNPKG

webcodecs-flv

Version:

webcodecs decode flv

146 lines (145 loc) 4.33 kB
import FLVDemuxer from './flv-demuxer.js'; import PCMPlayer from './pcm-player.js'; class player { constructor({ el }) { this.pcmPlayer = null; this.webglPlayer = null; this.fetchController = null; this.decorderVideo = null; this.decorderAudio = null; this._demuxer = null; this.canvas = document.getElementsByTagName(el)[0]; this.context = null; this.isDraw = false; this.writer = null; this.writerVideo = null; } play(url) { this._requestStream(url); this.context = this.canvas.getContext('2d', { alpha: false }); } stop() { if (this.fetchController) { this.fetchController.abort(); } } _requestStream(url) { this.fetchController = new AbortController(); const signal = this.fetchController.signal; let _this = this; fetch(url, { signal }).then(async function respond(response) { const reader = response.body.getReader(); reader.read().then(function processData({ done, value }) { if (done) { return; } _this._praseFlv(value); reader.read().then(processData); }); }); } async _praseFlv(data) { if (!this._demuxer) { this._demuxer = new FLVDemuxer(); this._demuxer.addEventListener('demuxer', (info) => { if (info.event == 'videoConfig') { this._videoDecodes(info.data); } if (info.event == 'audioConfig') { this.createAudio(); this._audioDecodes(info.data); } if (info.event == 'videoData') { this._encodedVideoChunk(info.data); } if (info.event == 'audioData') { this._encodedAudioChunk(info.data); } }); this._demuxer.parseChunks(data); } else { this._demuxer.parseChunks(data); } } _videoDecodes(data) { let decorderInit = { output: (frame) => { // this.context.drawImage(frame, 0, 0); this.writerVideo.write(frame); frame.close(); }, error: (e) => { console.log(e); }, }; this.decorderVideo = new VideoDecoder(decorderInit); const config = { codec: data.codecString, //指定解码器https://zhuanlan.zhihu.com/p/82266810 codecWidth: data.present_size.width, codecHeight: data.present_size.height, hardwareAcceleration: 'prefer-hardware', // hardwareAcceleration: 'no-preference', framerate: 22, }; this.decorderVideo.configure(config); } _encodedVideoChunk(data) { const chunk = new EncodedVideoChunk({ data: data.data, timestamp: data.pts, type: data.isKeyframe ? 'key' : 'delta', }); this.decorderVideo.decode(chunk); } _audioDecodes(data) { let decorderInit = { output: async (audioData) => { await this.writer.write(audioData); audioData.close(); }, error: (e) => { console.log(e); }, }; this.decorderAudio = new AudioDecoder(decorderInit); const config = { codec: data.codec, sampleRate: data.samplingRate, numberOfChannels: data.channelCount, }; this.decorderAudio.configure(config); if (!this.pcmPlayer) { this.pcmPlayer = new PCMPlayer({ encoding: '16bitInt', channels: data.channelCount, sampleRate: data.samplingRate, flushingTime: 1000, }); } } _encodedAudioChunk(data) { const chunk = new EncodedAudioChunk({ data: data.data, timestamp: data.timestamp, type: 'key', }); this.decorderAudio.decode(chunk); } createAudio() { const Video = document.createElement('video'); // audio.style.display = 'none'; Video.autoplay = true; document.body.appendChild(Video); const generator = new MediaStreamTrackGenerator({ kind: 'audio', }); const generatorVideo = new MediaStreamTrackGenerator({ kind: 'video', }); const { writable } = generator; this.writerVideo = generatorVideo.writable.getWriter(); this.writer = writable.getWriter(); const mediaStream = new MediaStream([generator, generatorVideo]); Video.srcObject = mediaStream; } } export default player;