diff --git a/build.sh b/build.sh index 0bba680a..7b9e5f10 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,63 @@ #!/bin/sh -uglifyjs \ + + +# Build the .wasm Module first + +# Since we're compiling a side module here, so that we can load it without the +# runtime cruft, we have to explicitly compile in support for malloc and +# friends. +# Note memcpy, memmove and memset are explicitly exported, otherwise they will +# be eliminated by the SIDE_MODULE=2 setting - not sure why that happens. +emcc \ + src/wasm/mpeg1.c \ + src/wasm/mp2.c \ + src/wasm/buffer.c \ + $EMSCRIPTEN/system/lib/emmalloc.cpp \ + $EMSCRIPTEN/system/lib/libc/musl/src/string/memcpy.c \ + $EMSCRIPTEN/system/lib/libc/musl/src/string/memmove.c \ + $EMSCRIPTEN/system/lib/libc/musl/src/string/memset.c \ + -s WASM=1 \ + -s SIDE_MODULE=2 \ + -s TOTAL_STACK=5242880\ + -s USE_PTHREADS=0 \ + -s LEGALIZE_JS_FFI=0\ + -s NO_FILESYSTEM=1 \ + -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE="[]" \ + -s "EXPORTED_FUNCTIONS=[ + '_memcpy', + '_memmove', + '_memset', + '_mpeg1_decoder_create', + '_mpeg1_decoder_destroy', + '_mpeg1_decoder_get_write_ptr', + '_mpeg1_decoder_get_index', + '_mpeg1_decoder_set_index', + '_mpeg1_decoder_did_write', + '_mpeg1_decoder_has_sequence_header', + '_mpeg1_decoder_get_frame_rate', + '_mpeg1_decoder_get_coded_size', + '_mpeg1_decoder_get_width', + '_mpeg1_decoder_get_height', + '_mpeg1_decoder_get_y_ptr', + '_mpeg1_decoder_get_cr_ptr', + '_mpeg1_decoder_get_cb_ptr', + '_mpeg1_decoder_decode', + '_mp2_decoder_create', + '_mp2_decoder_destroy', + '_mp2_decoder_get_write_ptr', + '_mp2_decoder_get_index', + '_mp2_decoder_set_index', + '_mp2_decoder_did_write', + '_mp2_decoder_get_left_channel_ptr', + '_mp2_decoder_get_right_channel_ptr', + '_mp2_decoder_get_sample_rate', + '_mp2_decoder_decode']" \ + -O3 \ + -o jsmpeg.wasm + + +# Concat all .js sources +cat \ src/jsmpeg.js \ src/video-element.js \ src/player.js \ @@ -10,8 +68,24 @@ uglifyjs \ src/ts.js \ src/decoder.js \ src/mpeg1.js \ + src/mpeg1-wasm.js \ src/mp2.js \ + src/mp2-wasm.js \ src/webgl.js \ src/canvas2d.js \ src/webaudio.js \ - -o jsmpeg.min.js + src/wasm-module.js \ + > jsmpeg.js + +# Append the .wasm module to the .js source as base64 string +echo "JSMpeg.WASM_BINARY_INLINED='$(base64 -w 0 jsmpeg.wasm)';" \ + >> jsmpeg.js + + +# Minify +uglifyjs jsmpeg.js -o jsmpeg.min.js + +# Cleanup +rm jsmpeg.js +rm jsmpeg.wasm + diff --git a/jsmpeg.min.js b/jsmpeg.min.js index 817b097b..354f160b 100644 --- a/jsmpeg.min.js +++ b/jsmpeg.min.js @@ -1,3 +1,4 @@ -var JSMpeg={Player:null,VideoElement:null,BitBuffer:null,Source:{},Demuxer:{},Decoder:{},Renderer:{},AudioOutput:{},Now:function(){return window.performance?window.performance.now()/1e3:Date.now()/1e3},CreateVideoElements:function(){var elements=document.querySelectorAll(".jsmpeg");for(var i=0;i'+''+''+"";VideoElement.UNMUTE_BUTTON=''+''+''+''+''+""+"";return VideoElement}();JSMpeg.Player=function(){"use strict";var Player=function(url,options){this.options=options||{};if(options.source){this.source=new options.source(url,options);options.streaming=!!this.source.streaming}else if(url.match(/^wss?:\/\//)){this.source=new JSMpeg.Source.WebSocket(url,options);options.streaming=true}else if(options.progressive!==false){this.source=new JSMpeg.Source.AjaxProgressive(url,options);options.streaming=false}else{this.source=new JSMpeg.Source.Ajax(url,options);options.streaming=false}this.maxAudioLag=options.maxAudioLag||.25;this.loop=options.loop!==false;this.autoplay=!!options.autoplay||options.streaming;this.demuxer=new JSMpeg.Demuxer.TS(options);this.source.connect(this.demuxer);if(options.video!==false){this.video=new JSMpeg.Decoder.MPEG1Video(options);this.renderer=!options.disableGl&&JSMpeg.Renderer.WebGL.IsSupported()?new JSMpeg.Renderer.WebGL(options):new JSMpeg.Renderer.Canvas2D(options);this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.VIDEO_1,this.video);this.video.connect(this.renderer)}if(options.audio!==false&&JSMpeg.AudioOutput.WebAudio.IsSupported()){this.audio=new JSMpeg.Decoder.MP2Audio(options);this.audioOut=new JSMpeg.AudioOutput.WebAudio(options);this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.AUDIO_1,this.audio);this.audio.connect(this.audioOut)}Object.defineProperty(this,"currentTime",{get:this.getCurrentTime,set:this.setCurrentTime});Object.defineProperty(this,"volume",{get:this.getVolume,set:this.setVolume});this.unpauseOnShow=false;if(options.pauseWhenHidden!==false){document.addEventListener("visibilitychange",this.showHide.bind(this))}this.source.start();if(this.autoplay){this.play()}};Player.prototype.showHide=function(ev){if(document.visibilityState==="hidden"){this.unpauseOnShow=this.wantsToPlay;this.pause()}else if(this.unpauseOnShow){this.play()}};Player.prototype.play=function(ev){this.animationId=requestAnimationFrame(this.update.bind(this));this.wantsToPlay=true};Player.prototype.pause=function(ev){cancelAnimationFrame(this.animationId);this.wantsToPlay=false;this.isPlaying=false;if(this.audio&&this.audio.canPlay){this.audioOut.stop();this.seek(this.currentTime)}};Player.prototype.getVolume=function(){return this.audioOut?this.audioOut.volume:0};Player.prototype.setVolume=function(volume){if(this.audioOut){this.audioOut.volume=volume}};Player.prototype.stop=function(ev){this.pause();this.seek(0);if(this.video&&this.options.decodeFirstFrame!==false){this.video.decode()}};Player.prototype.destroy=function(){this.pause();this.source.destroy();this.renderer.destroy();this.audioOut.destroy()};Player.prototype.seek=function(time){var startOffset=this.audio&&this.audio.canPlay?this.audio.startTime:this.video.startTime;if(this.video){this.video.seek(time+startOffset)}if(this.audio){this.audio.seek(time+startOffset)}this.startTime=JSMpeg.Now()-time};Player.prototype.getCurrentTime=function(){return this.audio&&this.audio.canPlay?this.audio.currentTime-this.audio.startTime:this.video.currentTime-this.video.startTime};Player.prototype.setCurrentTime=function(time){this.seek(time)};Player.prototype.update=function(){this.animationId=requestAnimationFrame(this.update.bind(this));if(!this.source.established){if(this.renderer){this.renderer.renderProgress(this.source.progress)}return}if(!this.isPlaying){this.isPlaying=true;this.startTime=JSMpeg.Now()-this.currentTime}if(this.options.streaming){this.updateForStreaming()}else{this.updateForStaticFile()}};Player.prototype.updateForStreaming=function(){if(this.video){this.video.decode()}if(this.audio){var decoded=false;do{if(this.audioOut.enqueuedTime>this.maxAudioLag){this.audioOut.resetEnqueuedTime();this.audioOut.enabled=false}decoded=this.audio.decode()}while(decoded);this.audioOut.enabled=true}};Player.prototype.updateForStaticFile=function(){var notEnoughData=false,headroom=0;if(this.audio&&this.audio.canPlay){while(!notEnoughData&&this.audio.decodedTime-this.audio.currentTime<.25){notEnoughData=!this.audio.decode()}if(this.video&&this.video.currentTime0){if(lateTime>frameTime*2){this.startTime+=lateTime}notEnoughData=!this.video.decode()}headroom=this.demuxer.currentTime-targetTime}this.source.resume(headroom);if(notEnoughData&&this.source.completed){if(this.loop){this.seek(0)}else{this.pause()}}};return Player}();JSMpeg.BitBuffer=function(){"use strict";var BitBuffer=function(bufferOrLength,mode){if(typeof bufferOrLength==="object"){this.bytes=bufferOrLength instanceof Uint8Array?bufferOrLength:new Uint8Array(bufferOrLength);this.byteLength=this.bytes.length}else{this.bytes=new Uint8Array(bufferOrLength||1024*1024);this.byteLength=0}this.mode=mode||BitBuffer.MODE.EXPAND;this.index=0};BitBuffer.prototype.resize=function(size){var newBytes=new Uint8Array(size);if(this.byteLength!==0){this.byteLength=Math.min(this.byteLength,size);newBytes.set(this.bytes,0,this.byteLength)}this.bytes=newBytes;this.index=Math.min(this.index,this.byteLength<<3)};BitBuffer.prototype.evict=function(sizeNeeded){var bytePos=this.index>>3,available=this.bytes.length-this.byteLength;if(this.index===this.byteLength<<3||sizeNeeded>available+bytePos){this.byteLength=0;this.index=0;return}else if(bytePos===0){return}if(this.bytes.copyWithin){this.bytes.copyWithin(0,bytePos,this.byteLength)}else{this.bytes.set(this.bytes.subarray(bytePos,this.byteLength))}this.byteLength=this.byteLength-bytePos;this.index-=bytePos<<3;return};BitBuffer.prototype.write=function(buffers){var isArrayOfBuffers=typeof buffers[0]==="object",totalLength=0,available=this.bytes.length-this.byteLength;if(isArrayOfBuffers){var totalLength=0;for(var i=0;iavailable){if(this.mode===BitBuffer.MODE.EXPAND){var newSize=Math.max(this.bytes.length*2,totalLength-available);this.resize(newSize)}else{this.evict(totalLength)}}if(isArrayOfBuffers){for(var i=0;i>3;i>3;return i>=this.byteLength||this.bytes[i]==0&&this.bytes[i+1]==0&&this.bytes[i+2]==1};BitBuffer.prototype.peek=function(count){var offset=this.index;var value=0;while(count){var currentByte=this.bytes[offset>>3],remaining=8-(offset&7),read=remaining>8-read;value=value<>shift;offset+=read;count-=read}return value};BitBuffer.prototype.read=function(count){var value=this.peek(count);this.index+=count;return value};BitBuffer.prototype.skip=function(count){return this.index+=count};BitBuffer.prototype.rewind=function(count){this.index=Math.max(this.index-count,0)};BitBuffer.prototype.has=function(count){return(this.byteLength<<3)-this.index>=count};BitBuffer.MODE={EVICT:1,EXPAND:2};return BitBuffer}();JSMpeg.Source.Ajax=function(){"use strict";var AjaxSource=function(url,options){this.url=url;this.destination=null;this.request=null;this.completed=false;this.established=false;this.progress=0};AjaxSource.prototype.connect=function(destination){this.destination=destination};AjaxSource.prototype.start=function(){this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE&&this.request.status===200){this.onLoad(this.request.response)}}.bind(this);this.request.onprogress=this.onProgress.bind(this);this.request.open("GET",this.url);this.request.responseType="arraybuffer";this.request.send()};AjaxSource.prototype.resume=function(secondsHeadroom){};AjaxSource.prototype.destroy=function(){this.request.abort()};AjaxSource.prototype.onProgress=function(ev){this.progress=ev.loaded/ev.total};AjaxSource.prototype.onLoad=function(data){this.established=true;this.completed=true;this.progress=1;if(this.destination){this.destination.write(data)}};return AjaxSource}();JSMpeg.Source.AjaxProgressive=function(){"use strict";var AjaxProgressiveSource=function(url,options){this.url=url;this.destination=null;this.request=null;this.completed=false;this.established=false;this.progress=0;this.fileSize=0;this.loadedSize=0;this.chunkSize=options.chunkSize||1024*1024;this.isLoading=false;this.loadStartTime=0;this.throttled=options.throttled!==false;this.aborted=false};AjaxProgressiveSource.prototype.connect=function(destination){this.destination=destination};AjaxProgressiveSource.prototype.start=function(){this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE){this.fileSize=parseInt(this.request.getResponseHeader("Content-Length"));this.loadNextChunk()}}.bind(this);this.request.onprogress=this.onProgress.bind(this);this.request.open("HEAD",this.url);this.request.send()};AjaxProgressiveSource.prototype.resume=function(secondsHeadroom){if(this.isLoading||!this.throttled){return}var worstCaseLoadingTime=this.loadTime*8+2;if(worstCaseLoadingTime>secondsHeadroom){this.loadNextChunk()}};AjaxProgressiveSource.prototype.destroy=function(){this.request.abort();this.aborted=true};AjaxProgressiveSource.prototype.loadNextChunk=function(){var start=this.loadedSize,end=Math.min(this.loadedSize+this.chunkSize-1,this.fileSize-1);if(start>=this.fileSize||this.aborted){this.completed=true;return}this.isLoading=true;this.loadStartTime=JSMpeg.Now();this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE&&this.request.status>=200&&this.request.status<300){this.onChunkLoad(this.request.response)}else if(this.request.readyState===this.request.DONE){if(this.loadFails++<3){this.loadNextChunk()}}}.bind(this);if(start===0){this.request.onprogress=this.onProgress.bind(this)}this.request.open("GET",this.url+"?"+start+"-"+end);this.request.setRequestHeader("Range","bytes="+start+"-"+end);this.request.responseType="arraybuffer";this.request.send()};AjaxProgressiveSource.prototype.onProgress=function(ev){this.progress=ev.loaded/ev.total};AjaxProgressiveSource.prototype.onChunkLoad=function(data){this.established=true;this.progress=1;this.loadedSize+=data.byteLength;this.loadFails=0;this.isLoading=false;if(this.destination){this.destination.write(data)}this.loadTime=JSMpeg.Now()-this.loadStartTime;if(!this.throttled){this.loadNextChunk()}};return AjaxProgressiveSource}();JSMpeg.Source.WebSocket=function(){"use strict";var WSSource=function(url,options){this.url=url;this.options=options;this.socket=null;this.callbacks={connect:[],data:[]};this.destination=null;this.reconnectInterval=options.reconnectInterval!==undefined?options.reconnectInterval:5;this.shouldAttemptReconnect=!!this.reconnectInterval;this.completed=false;this.established=false;this.progress=0;this.reconnectTimeoutId=0};WSSource.prototype.connect=function(destination){this.destination=destination};WSSource.prototype.destroy=function(){clearTimeout(this.reconnectTimeoutId);this.shouldAttemptReconnect=false;this.socket.close()};WSSource.prototype.start=function(){this.shouldAttemptReconnect=!!this.reconnectInterval;this.progress=0;this.established=false;this.socket=new WebSocket(this.url,this.options.protocols||null);this.socket.binaryType="arraybuffer";this.socket.onmessage=this.onMessage.bind(this);this.socket.onopen=this.onOpen.bind(this);this.socket.onerror=this.onClose.bind(this);this.socket.onclose=this.onClose.bind(this)};WSSource.prototype.resume=function(secondsHeadroom){};WSSource.prototype.onOpen=function(){this.progress=1;this.established=true};WSSource.prototype.onClose=function(){if(this.shouldAttemptReconnect){clearTimeout(this.reconnectTimeoutId);this.reconnectTimeoutId=setTimeout(function(){this.start()}.bind(this),this.reconnectInterval*1e3)}};WSSource.prototype.onMessage=function(ev){if(this.destination){this.destination.write(ev.data)}};return WSSource}();JSMpeg.Demuxer.TS=function(){"use strict";var TS=function(options){this.bits=null;this.leftoverBytes=null;this.guessVideoFrameEnd=true;this.pidsToStreamIds={};this.pesPacketInfo={};this.startTime=0;this.currentTime=0};TS.prototype.connect=function(streamId,destination){this.pesPacketInfo[streamId]={destination:destination,currentLength:0,totalLength:0,pts:0,buffers:[]}};TS.prototype.write=function(buffer){if(this.leftoverBytes){var totalLength=buffer.byteLength+this.leftoverBytes.byteLength;this.bits=new JSMpeg.BitBuffer(totalLength);this.bits.write([this.leftoverBytes,buffer])}else{this.bits=new JSMpeg.BitBuffer(buffer)}while(this.bits.has(188<<3)&&this.parsePacket()){}var leftoverCount=this.bits.byteLength-(this.bits.index>>3);this.leftoverBytes=leftoverCount>0?this.bits.bytes.subarray(this.bits.index>>3):null};TS.prototype.parsePacket=function(){if(this.bits.read(8)!==71){if(!this.resync()){return false}}var end=(this.bits.index>>3)+187;var transportError=this.bits.read(1),payloadStart=this.bits.read(1),transportPriority=this.bits.read(1),pid=this.bits.read(13),transportScrambling=this.bits.read(2),adaptationField=this.bits.read(2),continuityCounter=this.bits.read(4);var streamId=this.pidsToStreamIds[pid];if(payloadStart&&streamId){var pi=this.pesPacketInfo[streamId];if(pi&&pi.currentLength){this.packetComplete(pi)}}if(adaptationField&1){if(adaptationField&2){var adaptationFieldLength=this.bits.read(8);this.bits.skip(adaptationFieldLength<<3)}if(payloadStart&&this.bits.nextBytesAreStartCode()){this.bits.skip(24);streamId=this.bits.read(8);this.pidsToStreamIds[pid]=streamId;var packetLength=this.bits.read(16);this.bits.skip(8);var ptsDtsFlag=this.bits.read(2);this.bits.skip(6);var headerLength=this.bits.read(8);var payloadBeginIndex=this.bits.index+(headerLength<<3);var pi=this.pesPacketInfo[streamId];if(pi){var pts=0;if(ptsDtsFlag&2){this.bits.skip(4);var p32_30=this.bits.read(3);this.bits.skip(1);var p29_15=this.bits.read(15);this.bits.skip(1);var p14_0=this.bits.read(15);this.bits.skip(1);pts=(p32_30*1073741824+p29_15*32768+p14_0)/9e4;this.currentTime=pts;if(this.startTime===-1){this.startTime=pts}}var payloadLength=packetLength?packetLength-headerLength-3:0;this.packetStart(pi,pts,payloadLength)}this.bits.index=payloadBeginIndex}if(streamId){var pi=this.pesPacketInfo[streamId];if(pi){var start=this.bits.index>>3;var complete=this.packetAddData(pi,start,end);var hasPadding=!payloadStart&&adaptationField&2;if(complete||this.guessVideoFrameEnd&&hasPadding){this.packetComplete(pi)}}}}this.bits.index=end<<3;return true};TS.prototype.resync=function(){if(!this.bits.has(188*6<<3)){return false}var byteIndex=this.bits.index>>3;for(var i=0;i<187;i++){if(this.bits.bytes[byteIndex+i]===71){var foundSync=true;for(var j=1;j<5;j++){if(this.bits.bytes[byteIndex+i+188*j]!==71){foundSync=false;break}}if(foundSync){this.bits.index=byteIndex+i+1<<3;return true}}}console.warn("JSMpeg: Possible garbage data. Skipping.");this.bits.skip(187<<3);return false};TS.prototype.packetStart=function(pi,pts,payloadLength){pi.totalLength=payloadLength;pi.currentLength=0;pi.pts=pts};TS.prototype.packetAddData=function(pi,start,end){pi.buffers.push(this.bits.bytes.subarray(start,end));pi.currentLength+=end-start;var complete=pi.totalLength!==0&&pi.currentLength>=pi.totalLength;return complete};TS.prototype.packetComplete=function(pi){pi.destination.write(pi.pts,pi.buffers);pi.totalLength=0;pi.currentLength=0;pi.buffers=[]};TS.STREAM={PACK_HEADER:186,SYSTEM_HEADER:187,PROGRAM_MAP:188,PRIVATE_1:189,PADDING:190,PRIVATE_2:191,AUDIO_1:192,VIDEO_1:224,DIRECTORY:255};return TS}();JSMpeg.Decoder.Base=function(){"use strict";var BaseDecoder=function(options){this.destination=null;this.canPlay=false;this.collectTimestamps=!options.streaming;this.timestamps=[];this.timestampIndex=0;this.startTime=0;this.decodedTime=0;Object.defineProperty(this,"currentTime",{get:this.getCurrentTime})};BaseDecoder.prototype.connect=function(destination){this.destination=destination};BaseDecoder.prototype.write=function(pts,buffers){if(this.collectTimestamps){if(this.timestamps.length===0){this.startTime=pts;this.decodedTime=pts}this.timestamps.push({index:this.bits.byteLength<<3,time:pts})}this.bits.write(buffers);this.canPlay=true};BaseDecoder.prototype.seek=function(time){if(!this.collectTimestamps){return}this.timestampIndex=0;for(var i=0;itime){break}this.timestampIndex=i}var ts=this.timestamps[this.timestampIndex];if(ts){this.bits.index=ts.index;this.decodedTime=ts.time}else{this.bits.index=0;this.decodedTime=this.startTime}};BaseDecoder.prototype.decode=function(){this.advanceDecodedTime(0)};BaseDecoder.prototype.advanceDecodedTime=function(seconds){if(this.collectTimestamps){var newTimestampIndex=-1;for(var i=this.timestampIndex;ithis.bits.index){break}newTimestampIndex=i}if(newTimestampIndex!==-1&&newTimestampIndex!==this.timestampIndex){this.timestampIndex=newTimestampIndex;this.decodedTime=this.timestamps[this.timestampIndex].time;return}}this.decodedTime+=seconds};BaseDecoder.prototype.getCurrentTime=function(){return this.decodedTime};return BaseDecoder}();JSMpeg.Decoder.MPEG1Video=function(){"use strict";var MPEG1=function(options){JSMpeg.Decoder.Base.call(this,options);var bufferSize=options.videoBufferSize||512*1024;var bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.bits=new JSMpeg.BitBuffer(bufferSize,bufferMode);this.customIntraQuantMatrix=new Uint8Array(64);this.customNonIntraQuantMatrix=new Uint8Array(64);this.blockData=new Int32Array(64);this.currentFrame=0;this.decodeFirstFrame=options.decodeFirstFrame!==false};MPEG1.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MPEG1.prototype.constructor=MPEG1;MPEG1.prototype.write=function(pts,buffers){JSMpeg.Decoder.Base.prototype.write.call(this,pts,buffers);if(!this.hasSequenceHeader){if(this.bits.findStartCode(MPEG1.START.SEQUENCE)===-1){return false}this.decodeSequenceHeader();if(this.decodeFirstFrame){this.decode()}}};MPEG1.prototype.decode=function(){if(!this.hasSequenceHeader){return false}if(this.bits.findStartCode(MPEG1.START.PICTURE)===-1){var bufferedBytes=this.bits.byteLength-(this.bits.index>>3);return false}this.decodePicture();this.advanceDecodedTime(1/this.frameRate);return true};MPEG1.prototype.readHuffman=function(codeTable){var state=0;do{state=codeTable[state+this.bits.read(1)]}while(state>=0&&codeTable[state]!==0);return codeTable[state+2]};MPEG1.prototype.frameRate=30;MPEG1.prototype.decodeSequenceHeader=function(){var newWidth=this.bits.read(12),newHeight=this.bits.read(12);this.bits.skip(4);this.frameRate=MPEG1.PICTURE_RATE[this.bits.read(4)];this.bits.skip(18+1+10+1);if(newWidth!==this.width||newHeight!==this.height){this.width=newWidth;this.height=newHeight;this.initBuffers();if(this.destination){this.destination.resize(newWidth,newHeight)}}if(this.bits.read(1)){for(var i=0;i<64;i++){this.customIntraQuantMatrix[MPEG1.ZIG_ZAG[i]]=this.bits.read(8)}this.intraQuantMatrix=this.customIntraQuantMatrix}if(this.bits.read(1)){for(var i=0;i<64;i++){var idx=MPEG1.ZIG_ZAG[i];this.customNonIntraQuantMatrix[idx]=this.bits.read(8)}this.nonIntraQuantMatrix=this.customNonIntraQuantMatrix}this.hasSequenceHeader=true};MPEG1.prototype.initBuffers=function(){this.intraQuantMatrix=MPEG1.DEFAULT_INTRA_QUANT_MATRIX;this.nonIntraQuantMatrix=MPEG1.DEFAULT_NON_INTRA_QUANT_MATRIX;this.mbWidth=this.width+15>>4;this.mbHeight=this.height+15>>4;this.mbSize=this.mbWidth*this.mbHeight;this.codedWidth=this.mbWidth<<4;this.codedHeight=this.mbHeight<<4;this.codedSize=this.codedWidth*this.codedHeight;this.halfWidth=this.mbWidth<<3;this.halfHeight=this.mbHeight<<3;this.currentY=new Uint8ClampedArray(this.codedSize);this.currentY32=new Uint32Array(this.currentY.buffer);this.currentCr=new Uint8ClampedArray(this.codedSize>>2);this.currentCr32=new Uint32Array(this.currentCr.buffer);this.currentCb=new Uint8ClampedArray(this.codedSize>>2);this.currentCb32=new Uint32Array(this.currentCb.buffer);this.forwardY=new Uint8ClampedArray(this.codedSize);this.forwardY32=new Uint32Array(this.forwardY.buffer);this.forwardCr=new Uint8ClampedArray(this.codedSize>>2);this.forwardCr32=new Uint32Array(this.forwardCr.buffer);this.forwardCb=new Uint8ClampedArray(this.codedSize>>2);this.forwardCb32=new Uint32Array(this.forwardCb.buffer)};MPEG1.prototype.currentY=null;MPEG1.prototype.currentCr=null;MPEG1.prototype.currentCb=null;MPEG1.prototype.pictureType=0;MPEG1.prototype.forwardY=null;MPEG1.prototype.forwardCr=null;MPEG1.prototype.forwardCb=null;MPEG1.prototype.fullPelForward=false;MPEG1.prototype.forwardFCode=0;MPEG1.prototype.forwardRSize=0;MPEG1.prototype.forwardF=0;MPEG1.prototype.decodePicture=function(skipOutput){this.currentFrame++;this.bits.skip(10);this.pictureType=this.bits.read(3);this.bits.skip(16);if(this.pictureType<=0||this.pictureType>=MPEG1.PICTURE_TYPE.B){return}if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.fullPelForward=this.bits.read(1);this.forwardFCode=this.bits.read(3);if(this.forwardFCode===0){return}this.forwardRSize=this.forwardFCode-1;this.forwardF=1<=MPEG1.START.SLICE_FIRST&&code<=MPEG1.START.SLICE_LAST){this.decodeSlice(code&255);code=this.bits.findNextStartCode()}if(code!==-1){this.bits.rewind(32)}if(this.destination){this.destination.render(this.currentY,this.currentCr,this.currentCb)}if(this.pictureType===MPEG1.PICTURE_TYPE.INTRA||this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){var tmpY=this.forwardY,tmpY32=this.forwardY32,tmpCr=this.forwardCr,tmpCr32=this.forwardCr32,tmpCb=this.forwardCb,tmpCb32=this.forwardCb32;this.forwardY=this.currentY;this.forwardY32=this.currentY32;this.forwardCr=this.currentCr;this.forwardCr32=this.currentCr32;this.forwardCb=this.currentCb;this.forwardCb32=this.currentCb32;this.currentY=tmpY;this.currentY32=tmpY32;this.currentCr=tmpCr;this.currentCr32=tmpCr32;this.currentCb=tmpCb;this.currentCb32=tmpCb32}};MPEG1.prototype.quantizerScale=0;MPEG1.prototype.sliceBegin=false;MPEG1.prototype.decodeSlice=function(slice){this.sliceBegin=true;this.macroblockAddress=(slice-1)*this.mbWidth-1;this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0;this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;this.quantizerScale=this.bits.read(5);while(this.bits.read(1)){this.bits.skip(8)}do{this.decodeMacroblock()}while(!this.bits.nextBytesAreStartCode())};MPEG1.prototype.macroblockAddress=0;MPEG1.prototype.mbRow=0;MPEG1.prototype.mbCol=0;MPEG1.prototype.macroblockType=0;MPEG1.prototype.macroblockIntra=false;MPEG1.prototype.macroblockMotFw=false;MPEG1.prototype.motionFwH=0;MPEG1.prototype.motionFwV=0;MPEG1.prototype.motionFwHPrev=0;MPEG1.prototype.motionFwVPrev=0;MPEG1.prototype.decodeMacroblock=function(){var increment=0,t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT);while(t===34){t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT)}while(t===35){increment+=33;t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT)}increment+=t;if(this.sliceBegin){this.sliceBegin=false;this.macroblockAddress+=increment}else{if(this.macroblockAddress+increment>=this.mbSize){return}if(increment>1){this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}}while(increment>1){this.macroblockAddress++;this.mbRow=this.macroblockAddress/this.mbWidth|0;this.mbCol=this.macroblockAddress%this.mbWidth;this.copyMacroblock(this.motionFwH,this.motionFwV,this.forwardY,this.forwardCr,this.forwardCb);increment--}this.macroblockAddress++}this.mbRow=this.macroblockAddress/this.mbWidth|0;this.mbCol=this.macroblockAddress%this.mbWidth;var mbTable=MPEG1.MACROBLOCK_TYPE[this.pictureType];this.macroblockType=this.readHuffman(mbTable);this.macroblockIntra=this.macroblockType&1;this.macroblockMotFw=this.macroblockType&8;if((this.macroblockType&16)!==0){this.quantizerScale=this.bits.read(5)}if(this.macroblockIntra){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}else{this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;this.decodeMotionVectors();this.copyMacroblock(this.motionFwH,this.motionFwV,this.forwardY,this.forwardCr,this.forwardCb)}var cbp=(this.macroblockType&2)!==0?this.readHuffman(MPEG1.CODE_BLOCK_PATTERN):this.macroblockIntra?63:0;for(var block=0,mask=32;block<6;block++){if((cbp&mask)!==0){this.decodeBlock(block)}mask>>=1}};MPEG1.prototype.decodeMotionVectors=function(){var code,d,r=0;if(this.macroblockMotFw){code=this.readHuffman(MPEG1.MOTION);if(code!==0&&this.forwardF!==1){r=this.bits.read(this.forwardRSize);d=(Math.abs(code)-1<(this.forwardF<<4)-1){this.motionFwHPrev-=this.forwardF<<5}else if(this.motionFwHPrev<-this.forwardF<<4){this.motionFwHPrev+=this.forwardF<<5}this.motionFwH=this.motionFwHPrev;if(this.fullPelForward){this.motionFwH<<=1}code=this.readHuffman(MPEG1.MOTION);if(code!==0&&this.forwardF!==1){r=this.bits.read(this.forwardRSize);d=(Math.abs(code)-1<(this.forwardF<<4)-1){this.motionFwVPrev-=this.forwardF<<5}else if(this.motionFwVPrev<-this.forwardF<<4){this.motionFwVPrev+=this.forwardF<<5}this.motionFwV=this.motionFwVPrev;if(this.fullPelForward){this.motionFwV<<=1}}else if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}};MPEG1.prototype.copyMacroblock=function(motionH,motionV,sY,sCr,sCb){var width,scan,H,V,oddH,oddV,src,dest,last;var dY=this.currentY32,dCb=this.currentCb32,dCr=this.currentCr32;width=this.codedWidth;scan=width-16;H=motionH>>1;V=motionV>>1;oddH=(motionH&1)===1;oddV=(motionV&1)===1;src=((this.mbRow<<4)+V)*width+(this.mbCol<<4)+H;dest=this.mbRow*width+this.mbCol<<2;last=dest+(width<<2);var x,y1,y2,y;if(oddH){if(oddV){while(dest>2&255;y1=sY[src]+sY[src+width];src++;y|=y1+y2+2<<6&65280;y2=sY[src]+sY[src+width];src++;y|=y1+y2+2<<14&16711680;y1=sY[src]+sY[src+width];src++;y|=y1+y2+2<<22&4278190080;dY[dest++]=y}dest+=scan>>2;src+=scan-1}}else{while(dest>1&255;y1=sY[src++];y|=y1+y2+1<<7&65280;y2=sY[src++];y|=y1+y2+1<<15&16711680;y1=sY[src++];y|=y1+y2+1<<23&4278190080;dY[dest++]=y}dest+=scan>>2;src+=scan-1}}}else{if(oddV){while(dest>1&255;src++;y|=sY[src]+sY[src+width]+1<<7&65280;src++;y|=sY[src]+sY[src+width]+1<<15&16711680;src++;y|=sY[src]+sY[src+width]+1<<23&4278190080;src++;dY[dest++]=y}dest+=scan>>2;src+=scan}}else{while(dest>2;src+=scan}}}width=this.halfWidth;scan=width-8;H=motionH/2>>1;V=motionV/2>>1;oddH=(motionH/2&1)===1;oddV=(motionV/2&1)===1;src=((this.mbRow<<3)+V)*width+(this.mbCol<<3)+H;dest=this.mbRow*width+this.mbCol<<1;last=dest+(width<<1);var cr1,cr2,cr,cb1,cb2,cb;if(oddH){if(oddV){while(dest>2&255;cb=cb1+cb2+2>>2&255;cr1=sCr[src]+sCr[src+width];cb1=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<6&65280;cb|=cb1+cb2+2<<6&65280;cr2=sCr[src]+sCr[src+width];cb2=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<14&16711680;cb|=cb1+cb2+2<<14&16711680;cr1=sCr[src]+sCr[src+width];cb1=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<22&4278190080;cb|=cb1+cb2+2<<22&4278190080;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan-1}}else{while(dest>1&255;cb=cb1+cb2+1>>1&255;cr1=sCr[src];cb1=sCb[src++];cr|=cr1+cr2+1<<7&65280;cb|=cb1+cb2+1<<7&65280;cr2=sCr[src];cb2=sCb[src++];cr|=cr1+cr2+1<<15&16711680;cb|=cb1+cb2+1<<15&16711680;cr1=sCr[src];cb1=sCb[src++];cr|=cr1+cr2+1<<23&4278190080;cb|=cb1+cb2+1<<23&4278190080;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan-1}}}else{if(oddV){while(dest>1&255;cb=sCb[src]+sCb[src+width]+1>>1&255;src++;cr|=sCr[src]+sCr[src+width]+1<<7&65280;cb|=sCb[src]+sCb[src+width]+1<<7&65280;src++;cr|=sCr[src]+sCr[src+width]+1<<15&16711680;cb|=sCb[src]+sCb[src+width]+1<<15&16711680;src++;cr|=sCr[src]+sCr[src+width]+1<<23&4278190080;cb|=sCb[src]+sCb[src+width]+1<<23&4278190080;src++;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan}}else{while(dest>2;src+=scan}}}};MPEG1.prototype.dcPredictorY=0;MPEG1.prototype.dcPredictorCr=0;MPEG1.prototype.dcPredictorCb=0;MPEG1.prototype.blockData=null;MPEG1.prototype.decodeBlock=function(block){var n=0,quantMatrix;if(this.macroblockIntra){var predictor,dctSize;if(block<4){predictor=this.dcPredictorY;dctSize=this.readHuffman(MPEG1.DCT_DC_SIZE_LUMINANCE)}else{predictor=block===4?this.dcPredictorCr:this.dcPredictorCb;dctSize=this.readHuffman(MPEG1.DCT_DC_SIZE_CHROMINANCE)}if(dctSize>0){var differential=this.bits.read(dctSize);if((differential&1<0&&this.bits.read(1)===0){break}if(coeff===65535){run=this.bits.read(6);level=this.bits.read(8);if(level===0){level=this.bits.read(8)}else if(level===128){level=this.bits.read(8)-256}else if(level>128){level=level-256}}else{run=coeff>>8;level=coeff&255;if(this.bits.read(1)){level=-level}}n+=run;var dezigZagged=MPEG1.ZIG_ZAG[n];n++;level<<=1;if(!this.macroblockIntra){level+=level<0?-1:1}level=level*this.quantizerScale*quantMatrix[dezigZagged]>>4;if((level&1)===0){level-=level>0?1:-1}if(level>2047){level=2047}else if(level<-2048){level=-2048}this.blockData[dezigZagged]=level*MPEG1.PREMULTIPLIER_MATRIX[dezigZagged]}var destArray,destIndex,scan;if(block<4){destArray=this.currentY;scan=this.codedWidth-8;destIndex=this.mbRow*this.codedWidth+this.mbCol<<4;if((block&1)!==0){destIndex+=8}if((block&2)!==0){destIndex+=this.codedWidth<<3}}else{destArray=block===4?this.currentCb:this.currentCr;scan=(this.codedWidth>>1)-8;destIndex=(this.mbRow*this.codedWidth<<2)+(this.mbCol<<3)}if(this.macroblockIntra){if(n===1){MPEG1.CopyValueToDestination(this.blockData[0]+128>>8,destArray,destIndex,scan);this.blockData[0]=0}else{MPEG1.IDCT(this.blockData);MPEG1.CopyBlockToDestination(this.blockData,destArray,destIndex,scan);JSMpeg.Fill(this.blockData,0)}}else{if(n===1){MPEG1.AddValueToDestination(this.blockData[0]+128>>8,destArray,destIndex,scan);this.blockData[0]=0}else{MPEG1.IDCT(this.blockData);MPEG1.AddBlockToDestination(this.blockData,destArray,destIndex,scan);JSMpeg.Fill(this.blockData,0)}}n=0};MPEG1.CopyBlockToDestination=function(block,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]=block[n+0];dest[index+1]=block[n+1];dest[index+2]=block[n+2];dest[index+3]=block[n+3];dest[index+4]=block[n+4];dest[index+5]=block[n+5];dest[index+6]=block[n+6];dest[index+7]=block[n+7]}};MPEG1.AddBlockToDestination=function(block,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]+=block[n+0];dest[index+1]+=block[n+1];dest[index+2]+=block[n+2];dest[index+3]+=block[n+3];dest[index+4]+=block[n+4];dest[index+5]+=block[n+5];dest[index+6]+=block[n+6];dest[index+7]+=block[n+7]}};MPEG1.CopyValueToDestination=function(value,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]=value;dest[index+1]=value;dest[index+2]=value;dest[index+3]=value;dest[index+4]=value;dest[index+5]=value;dest[index+6]=value;dest[index+7]=value}};MPEG1.AddValueToDestination=function(value,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]+=value;dest[index+1]+=value;dest[index+2]+=value;dest[index+3]+=value;dest[index+4]+=value;dest[index+5]+=value;dest[index+6]+=value;dest[index+7]+=value}};MPEG1.IDCT=function(block){var b1,b3,b4,b6,b7,tmp1,tmp2,m0,x0,x1,x2,x3,x4,y3,y4,y5,y6,y7;for(var i=0;i<8;++i){b1=block[4*8+i];b3=block[2*8+i]+block[6*8+i];b4=block[5*8+i]-block[3*8+i];tmp1=block[1*8+i]+block[7*8+i];tmp2=block[3*8+i]+block[5*8+i];b6=block[1*8+i]-block[7*8+i];b7=tmp1+tmp2;m0=block[0*8+i];x4=(b6*473-b4*196+128>>8)-b7;x0=x4-((tmp1-tmp2)*362+128>>8);x1=m0-b1;x2=((block[2*8+i]-block[6*8+i])*362+128>>8)-b3;x3=m0+b1;y3=x1+x2;y4=x3+b3;y5=x1-x2;y6=x3-b3;y7=-x0-(b4*473+b6*196+128>>8);block[0*8+i]=b7+y4;block[1*8+i]=x4+y3;block[2*8+i]=y5-x0;block[3*8+i]=y6-y7;block[4*8+i]=y6+y7;block[5*8+i]=x0+y5;block[6*8+i]=y3-x4;block[7*8+i]=y4-b7}for(var i=0;i<64;i+=8){b1=block[4+i];b3=block[2+i]+block[6+i];b4=block[5+i]-block[3+i];tmp1=block[1+i]+block[7+i];tmp2=block[3+i]+block[5+i];b6=block[1+i]-block[7+i];b7=tmp1+tmp2;m0=block[0+i];x4=(b6*473-b4*196+128>>8)-b7;x0=x4-((tmp1-tmp2)*362+128>>8);x1=m0-b1;x2=((block[2+i]-block[6+i])*362+128>>8)-b3;x3=m0+b1;y3=x1+x2;y4=x3+b3;y5=x1-x2;y6=x3-b3;y7=-x0-(b4*473+b6*196+128>>8);block[0+i]=b7+y4+128>>8;block[1+i]=x4+y3+128>>8;block[2+i]=y5-x0+128>>8;block[3+i]=y6-y7+128>>8;block[4+i]=y6+y7+128>>8;block[5+i]=x0+y5+128>>8;block[6+i]=y3-x4+128>>8;block[7+i]=y4-b7+128>>8}};MPEG1.PICTURE_RATE=[0,23.976,24,25,29.97,30,50,59.94,60,0,0,0,0,0,0,0];MPEG1.ZIG_ZAG=new Uint8Array([0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63]);MPEG1.DEFAULT_INTRA_QUANT_MATRIX=new Uint8Array([8,16,19,22,26,27,29,34,16,16,22,24,27,29,34,37,19,22,26,27,29,34,34,38,22,22,26,27,29,34,37,40,22,26,27,29,32,35,40,48,26,27,29,32,35,40,48,58,26,27,29,34,38,46,56,69,27,29,35,38,46,56,69,83]);MPEG1.DEFAULT_NON_INTRA_QUANT_MATRIX=new Uint8Array([16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]);MPEG1.PREMULTIPLIER_MATRIX=new Uint8Array([32,44,42,38,32,25,17,9,44,62,58,52,44,35,24,12,42,58,55,49,42,33,23,12,38,52,49,44,38,30,20,10,32,44,42,38,32,25,17,9,25,35,33,30,25,20,14,7,17,24,23,20,17,14,9,5,9,12,12,10,9,7,5,2]);MPEG1.MACROBLOCK_ADDRESS_INCREMENT=new Int16Array([1*3,2*3,0,3*3,4*3,0,0,0,1,5*3,6*3,0,7*3,8*3,0,9*3,10*3,0,11*3,12*3,0,0,0,3,0,0,2,13*3,14*3,0,15*3,16*3,0,0,0,5,0,0,4,17*3,18*3,0,19*3,20*3,0,0,0,7,0,0,6,21*3,22*3,0,23*3,24*3,0,25*3,26*3,0,27*3,28*3,0,-1,29*3,0,-1,30*3,0,31*3,32*3,0,33*3,34*3,0,35*3,36*3,0,37*3,38*3,0,0,0,9,0,0,8,39*3,40*3,0,41*3,42*3,0,43*3,44*3,0,45*3,46*3,0,0,0,15,0,0,14,0,0,13,0,0,12,0,0,11,0,0,10,47*3,-1,0,-1,48*3,0,49*3,50*3,0,51*3,52*3,0,53*3,54*3,0,55*3,56*3,0,57*3,58*3,0,59*3,60*3,0,61*3,-1,0,-1,62*3,0,63*3,64*3,0,65*3,66*3,0,67*3,68*3,0,69*3,70*3,0,71*3,72*3,0,73*3,74*3,0,0,0,21,0,0,20,0,0,19,0,0,18,0,0,17,0,0,16,0,0,35,0,0,34,0,0,33,0,0,32,0,0,31,0,0,30,0,0,29,0,0,28,0,0,27,0,0,26,0,0,25,0,0,24,0,0,23,0,0,22]);MPEG1.MACROBLOCK_TYPE_INTRA=new Int8Array([1*3,2*3,0,-1,3*3,0,0,0,1,0,0,17]);MPEG1.MACROBLOCK_TYPE_PREDICTIVE=new Int8Array([1*3,2*3,0,3*3,4*3,0,0,0,10,5*3,6*3,0,0,0,2,7*3,8*3,0,0,0,8,9*3,10*3,0,11*3,12*3,0,-1,13*3,0,0,0,18,0,0,26,0,0,1,0,0,17]);MPEG1.MACROBLOCK_TYPE_B=new Int8Array([1*3,2*3,0,3*3,5*3,0,4*3,6*3,0,8*3,7*3,0,0,0,12,9*3,10*3,0,0,0,14,13*3,14*3,0,12*3,11*3,0,0,0,4,0,0,6,18*3,16*3,0,15*3,17*3,0,0,0,8,0,0,10,-1,19*3,0,0,0,1,20*3,21*3,0,0,0,30,0,0,17,0,0,22,0,0,26]);MPEG1.MACROBLOCK_TYPE=[null,MPEG1.MACROBLOCK_TYPE_INTRA,MPEG1.MACROBLOCK_TYPE_PREDICTIVE,MPEG1.MACROBLOCK_TYPE_B];MPEG1.CODE_BLOCK_PATTERN=new Int16Array([2*3,1*3,0,3*3,6*3,0,4*3,5*3,0,8*3,11*3,0,12*3,13*3,0,9*3,7*3,0,10*3,14*3,0,20*3,19*3,0,18*3,16*3,0,23*3,17*3,0,27*3,25*3,0,21*3,28*3,0,15*3,22*3,0,24*3,26*3,0,0,0,60,35*3,40*3,0,44*3,48*3,0,38*3,36*3,0,42*3,47*3,0,29*3,31*3,0,39*3,32*3,0,0,0,32,45*3,46*3,0,33*3,41*3,0,43*3,34*3,0,0,0,4,30*3,37*3,0,0,0,8,0,0,16,0,0,44,50*3,56*3,0,0,0,28,0,0,52,0,0,62,61*3,59*3,0,52*3,60*3,0,0,0,1,55*3,54*3,0,0,0,61,0,0,56,57*3,58*3,0,0,0,2,0,0,40,51*3,62*3,0,0,0,48,64*3,63*3,0,49*3,53*3,0,0,0,20,0,0,12,80*3,83*3,0,0,0,63,77*3,75*3,0,65*3,73*3,0,84*3,66*3,0,0,0,24,0,0,36,0,0,3,69*3,87*3,0,81*3,79*3,0,68*3,71*3,0,70*3,78*3,0,67*3,76*3,0,72*3,74*3,0,86*3,85*3,0,88*3,82*3,0,-1,94*3,0,95*3,97*3,0,0,0,33,0,0,9,106*3,110*3,0,102*3,116*3,0,0,0,5,0,0,10,93*3,89*3,0,0,0,6,0,0,18,0,0,17,0,0,34,113*3,119*3,0,103*3,104*3,0,90*3,92*3,0,109*3,107*3,0,117*3,118*3,0,101*3,99*3,0,98*3,96*3,0,100*3,91*3,0,114*3,115*3,0,105*3,108*3,0,112*3,111*3,0,121*3,125*3,0,0,0,41,0,0,14,0,0,21,124*3,122*3,0,120*3,123*3,0,0,0,11,0,0,19,0,0,7,0,0,35,0,0,13,0,0,50,0,0,49,0,0,58,0,0,37,0,0,25,0,0,45,0,0,57,0,0,26,0,0,29,0,0,38,0,0,53,0,0,23,0,0,43,0,0,46,0,0,42,0,0,22,0,0,54,0,0,51,0,0,15,0,0,30,0,0,39,0,0,47,0,0,55,0,0,27,0,0,59,0,0,31]);MPEG1.MOTION=new Int16Array([1*3,2*3,0,4*3,3*3,0,0,0,0,6*3,5*3,0,8*3,7*3,0,0,0,-1,0,0,1,9*3,10*3,0,12*3,11*3,0,0,0,2,0,0,-2,14*3,15*3,0,16*3,13*3,0,20*3,18*3,0,0,0,3,0,0,-3,17*3,19*3,0,-1,23*3,0,27*3,25*3,0,26*3,21*3,0,24*3,22*3,0,32*3,28*3,0,29*3,31*3,0,-1,33*3,0,36*3,35*3,0,0,0,-4,30*3,34*3,0,0,0,4,0,0,-7,0,0,5,37*3,41*3,0,0,0,-5,0,0,7,38*3,40*3,0,42*3,39*3,0,0,0,-6,0,0,6,51*3,54*3,0,50*3,49*3,0,45*3,46*3,0,52*3,47*3,0,43*3,53*3,0,44*3,48*3,0,0,0,10,0,0,9,0,0,8,0,0,-8,57*3,66*3,0,0,0,-9,60*3,64*3,0,56*3,61*3,0,55*3,62*3,0,58*3,63*3,0,0,0,-10,59*3,65*3,0,0,0,12,0,0,16,0,0,13,0,0,14,0,0,11,0,0,15,0,0,-16,0,0,-12,0,0,-14,0,0,-15,0,0,-11,0,0,-13]);MPEG1.DCT_DC_SIZE_LUMINANCE=new Int8Array([2*3,1*3,0,6*3,5*3,0,3*3,4*3,0,0,0,1,0,0,2,9*3,8*3,0,7*3,10*3,0,0,0,0,12*3,11*3,0,0,0,4,0,0,3,13*3,14*3,0,0,0,5,0,0,6,16*3,15*3,0,17*3,-1,0,0,0,7,0,0,8]);MPEG1.DCT_DC_SIZE_CHROMINANCE=new Int8Array([2*3,1*3,0,4*3,3*3,0,6*3,5*3,0,8*3,7*3,0,0,0,2,0,0,1,0,0,0,10*3,9*3,0,0,0,3,12*3,11*3,0,0,0,4,14*3,13*3,0,0,0,5,16*3,15*3,0,0,0,6,17*3,-1,0,0,0,7,0,0,8]);MPEG1.DCT_COEFF=new Int32Array([1*3,2*3,0,4*3,3*3,0,0,0,1,7*3,8*3,0,6*3,5*3,0,13*3,9*3,0,11*3,10*3,0,14*3,12*3,0,0,0,257,20*3,22*3,0,18*3,21*3,0,16*3,19*3,0,0,0,513,17*3,15*3,0,0,0,2,0,0,3,27*3,25*3,0,29*3,31*3,0,24*3,26*3,0,32*3,30*3,0,0,0,1025,23*3,28*3,0,0,0,769,0,0,258,0,0,1793,0,0,65535,0,0,1537,37*3,36*3,0,0,0,1281,35*3,34*3,0,39*3,38*3,0,33*3,42*3,0,40*3,41*3,0,52*3,50*3,0,54*3,53*3,0,48*3,49*3,0,43*3,45*3,0,46*3,44*3,0,0,0,2049,0,0,4,0,0,514,0,0,2305,51*3,47*3,0,55*3,57*3,0,60*3,56*3,0,59*3,58*3,0,61*3,62*3,0,0,0,2561,0,0,3329,0,0,6,0,0,259,0,0,5,0,0,770,0,0,2817,0,0,3073,76*3,75*3,0,67*3,70*3,0,73*3,71*3,0,78*3,74*3,0,72*3,77*3,0,69*3,64*3,0,68*3,63*3,0,66*3,65*3,0,81*3,87*3,0,91*3,80*3,0,82*3,79*3,0,83*3,86*3,0,93*3,92*3,0,84*3,85*3,0,90*3,94*3,0,88*3,89*3,0,0,0,515,0,0,260,0,0,7,0,0,1026,0,0,1282,0,0,4097,0,0,3841,0,0,3585,105*3,107*3,0,111*3,114*3,0,104*3,97*3,0,125*3,119*3,0,96*3,98*3,0,-1,123*3,0,95*3,101*3,0,106*3,121*3,0,99*3,102*3,0,113*3,103*3,0,112*3,116*3,0,110*3,100*3,0,124*3,115*3,0,117*3,122*3,0,109*3,118*3,0,120*3,108*3,0,127*3,136*3,0,139*3,140*3,0,130*3,126*3,0,145*3,146*3,0,128*3,129*3,0,0,0,2050,132*3,134*3,0,155*3,154*3,0,0,0,8,137*3,133*3,0,143*3,144*3,0,151*3,138*3,0,142*3,141*3,0,0,0,10,0,0,9,0,0,11,0,0,5377,0,0,1538,0,0,771,0,0,5121,0,0,1794,0,0,4353,0,0,4609,0,0,4865,148*3,152*3,0,0,0,1027,153*3,150*3,0,0,0,261,131*3,135*3,0,0,0,516,149*3,147*3,0,172*3,173*3,0,162*3,158*3,0,170*3,161*3,0,168*3,166*3,0,157*3,179*3,0,169*3,167*3,0,174*3,171*3,0,178*3,177*3,0,156*3,159*3,0,164*3,165*3,0,183*3,182*3,0,175*3,176*3,0,0,0,263,0,0,2562,0,0,2306,0,0,5633,0,0,5889,0,0,6401,0,0,6145,0,0,1283,0,0,772,0,0,13,0,0,12,0,0,14,0,0,15,0,0,517,0,0,6657,0,0,262,180*3,181*3,0,160*3,163*3,0,196*3,199*3,0,0,0,27,203*3,185*3,0,202*3,201*3,0,0,0,19,0,0,22,197*3,207*3,0,0,0,18,191*3,192*3,0,188*3,190*3,0,0,0,20,184*3,194*3,0,0,0,21,186*3,193*3,0,0,0,23,204*3,198*3,0,0,0,25,0,0,24,200*3,205*3,0,0,0,31,0,0,30,0,0,28,0,0,29,0,0,26,0,0,17,0,0,16,189*3,206*3,0,187*3,195*3,0,218*3,211*3,0,0,0,37,215*3,216*3,0,0,0,36,210*3,212*3,0,0,0,34,213*3,209*3,0,221*3,222*3,0,219*3,208*3,0,217*3,214*3,0,223*3,220*3,0,0,0,35,0,0,267,0,0,40,0,0,268,0,0,266,0,0,32,0,0,264,0,0,265,0,0,38,0,0,269,0,0,270,0,0,33,0,0,39,0,0,7937,0,0,6913,0,0,7681,0,0,4098,0,0,7425,0,0,7169,0,0,271,0,0,274,0,0,273,0,0,272,0,0,1539,0,0,2818,0,0,3586,0,0,3330,0,0,3074,0,0,3842]);MPEG1.PICTURE_TYPE={INTRA:1,PREDICTIVE:2,B:3};MPEG1.START={SEQUENCE:179,SLICE_FIRST:1,SLICE_LAST:175,PICTURE:0,EXTENSION:181,USER_DATA:178};return MPEG1}();JSMpeg.Decoder.MP2Audio=function(){"use strict";var MP2=function(options){JSMpeg.Decoder.Base.call(this,options);var bufferSize=options.audioBufferSize||128*1024;var bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.bits=new JSMpeg.BitBuffer(bufferSize,bufferMode);this.left=new Float32Array(1152);this.right=new Float32Array(1152);this.sampleRate=44100;this.D=new Float32Array(1024);this.D.set(MP2.SYNTHESIS_WINDOW,0);this.D.set(MP2.SYNTHESIS_WINDOW,512);this.V=new Float32Array(1024);this.U=new Int32Array(32);this.VPos=0;this.allocation=[new Array(32),new Array(32)];this.scaleFactorInfo=[new Uint8Array(32),new Uint8Array(32)];this.scaleFactor=[new Array(32),new Array(32)];this.sample=[new Array(32),new Array(32)];for(var j=0;j<2;j++){for(var i=0;i<32;i++){this.scaleFactor[j][i]=[0,0,0];this.sample[j][i]=[0,0,0]}}};MP2.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MP2.prototype.constructor=MP2;MP2.prototype.decode=function(){var pos=this.bits.index>>3;if(pos>=this.bits.byteLength){return false}var decoded=this.decodeFrame(this.left,this.right);this.bits.index=pos+decoded<<3;if(!decoded){return false}if(this.destination){this.destination.play(this.sampleRate,this.left,this.right)}this.advanceDecodedTime(this.left.length/this.sampleRate);return true};MP2.prototype.getCurrentTime=function(){var enqueuedTime=this.destination?this.destination.enqueuedTime:0;return this.decodedTime-enqueuedTime};MP2.prototype.decodeFrame=function(left,right){var sync=this.bits.read(11),version=this.bits.read(2),layer=this.bits.read(2),hasCRC=!this.bits.read(1);if(sync!==MP2.FRAME_SYNC||version!==MP2.VERSION.MPEG_1||layer!==MP2.LAYER.II){return 0}var bitrateIndex=this.bits.read(4)-1;if(bitrateIndex>13){return 0}var sampleRateIndex=this.bits.read(2);var sampleRate=MP2.SAMPLE_RATE[sampleRateIndex];if(sampleRateIndex===3){return 0}if(version===MP2.VERSION.MPEG_2){sampleRateIndex+=4;bitrateIndex+=14}var padding=this.bits.read(1),privat=this.bits.read(1),mode=this.bits.read(2);var bound=0;if(mode===MP2.MODE.JOINT_STEREO){bound=this.bits.read(2)+1<<2}else{this.bits.skip(2);bound=mode===MP2.MODE.MONO?0:32}this.bits.skip(4);if(hasCRC){this.bits.skip(16)}var bitrate=MP2.BIT_RATE[bitrateIndex],sampleRate=MP2.SAMPLE_RATE[sampleRateIndex],frameSize=144e3*bitrate/sampleRate+padding|0;var tab3=0;var sblimit=0;if(version===MP2.VERSION.MPEG_2){tab3=2;sblimit=30}else{var tab1=mode===MP2.MODE.MONO?0:1;var tab2=MP2.QUANT_LUT_STEP_1[tab1][bitrateIndex];tab3=MP2.QUANT_LUT_STEP_2[tab2][sampleRateIndex];sblimit=tab3&63;tab3>>=6}if(bound>sblimit){bound=sblimit}for(var sb=0;sb>1);var vIndex=this.VPos%128>>1;while(vIndex<1024){for(var i=0;i<32;++i){this.U[i]+=this.D[dIndex++]*this.V[vIndex++]}vIndex+=128-32;dIndex+=64-32}vIndex=128-32+1024-vIndex;dIndex-=512-32;while(vIndex<1024){for(var i=0;i<32;++i){this.U[i]+=this.D[dIndex++]*this.V[vIndex++]}vIndex+=128-32;dIndex+=64-32}var outChannel=ch===0?left:right;for(var j=0;j<32;j++){outChannel[outPos+j]=this.U[j]/2147418112}}outPos+=32}}}this.sampleRate=sampleRate;return frameSize};MP2.prototype.readAllocation=function(sb,tab3){var tab4=MP2.QUANT_LUT_STEP_3[tab3][sb];var qtab=MP2.QUANT_LUT_STEP4[tab4&15][this.bits.read(tab4>>4)];return qtab?MP2.QUANT_TAB[qtab-1]:0};MP2.prototype.readSamples=function(ch,sb,part){var q=this.allocation[ch][sb],sf=this.scaleFactor[ch][sb][part],sample=this.sample[ch][sb],val=0;if(!q){sample[0]=sample[1]=sample[2]=0;return}if(sf===63){sf=0}else{var shift=sf/3|0;sf=MP2.SCALEFACTOR_BASE[sf%3]+(1<>1)>>shift}var adj=q.levels;if(q.group){val=this.bits.read(q.bits);sample[0]=val%adj;val=val/adj|0;sample[1]=val%adj;sample[2]=val/adj|0}else{sample[0]=this.bits.read(q.bits);sample[1]=this.bits.read(q.bits);sample[2]=this.bits.read(q.bits)}var scale=65536/(adj+1)|0;adj=(adj+1>>1)-1;val=(adj-sample[0])*scale;sample[0]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12;val=(adj-sample[1])*scale;sample[1]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12;val=(adj-sample[2])*scale;sample[2]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12};MP2.MatrixTransform=function(s,ss,d,dp){var t01,t02,t03,t04,t05,t06,t07,t08,t09,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33;t01=s[0][ss]+s[31][ss];t02=(s[0][ss]-s[31][ss])*.500602998235;t03=s[1][ss]+s[30][ss];t04=(s[1][ss]-s[30][ss])*.505470959898;t05=s[2][ss]+s[29][ss];t06=(s[2][ss]-s[29][ss])*.515447309923;t07=s[3][ss]+s[28][ss];t08=(s[3][ss]-s[28][ss])*.53104259109;t09=s[4][ss]+s[27][ss];t10=(s[4][ss]-s[27][ss])*.553103896034;t11=s[5][ss]+s[26][ss];t12=(s[5][ss]-s[26][ss])*.582934968206;t13=s[6][ss]+s[25][ss];t14=(s[6][ss]-s[25][ss])*.622504123036;t15=s[7][ss]+s[24][ss];t16=(s[7][ss]-s[24][ss])*.674808341455;t17=s[8][ss]+s[23][ss];t18=(s[8][ss]-s[23][ss])*.744536271002;t19=s[9][ss]+s[22][ss];t20=(s[9][ss]-s[22][ss])*.839349645416;t21=s[10][ss]+s[21][ss];t22=(s[10][ss]-s[21][ss])*.972568237862;t23=s[11][ss]+s[20][ss];t24=(s[11][ss]-s[20][ss])*1.16943993343;t25=s[12][ss]+s[19][ss];t26=(s[12][ss]-s[19][ss])*1.48416461631;t27=s[13][ss]+s[18][ss];t28=(s[13][ss]-s[18][ss])*2.05778100995;t29=s[14][ss]+s[17][ss];t30=(s[14][ss]-s[17][ss])*3.40760841847;t31=s[15][ss]+s[16][ss];t32=(s[15][ss]-s[16][ss])*10.1900081235;t33=t01+t31;t31=(t01-t31)*.502419286188;t01=t03+t29;t29=(t03-t29)*.52249861494;t03=t05+t27;t27=(t05-t27)*.566944034816;t05=t07+t25;t25=(t07-t25)*.64682178336;t07=t09+t23;t23=(t09-t23)*.788154623451;t09=t11+t21;t21=(t11-t21)*1.06067768599;t11=t13+t19;t19=(t13-t19)*1.72244709824;t13=t15+t17;t17=(t15-t17)*5.10114861869;t15=t33+t13;t13=(t33-t13)*.509795579104;t33=t01+t11;t01=(t01-t11)*.601344886935;t11=t03+t09;t09=(t03-t09)*.899976223136;t03=t05+t07;t07=(t05-t07)*2.56291544774;t05=t15+t03;t15=(t15-t03)*.541196100146;t03=t33+t11;t11=(t33-t11)*1.30656296488;t33=t05+t03;t05=(t05-t03)*.707106781187;t03=t15+t11;t15=(t15-t11)*.707106781187;t03+=t15;t11=t13+t07;t13=(t13-t07)*.541196100146;t07=t01+t09;t09=(t01-t09)*1.30656296488;t01=t11+t07;t07=(t11-t07)*.707106781187;t11=t13+t09;t13=(t13-t09)*.707106781187;t11+=t13;t01+=t11;t11+=t07;t07+=t13;t09=t31+t17;t31=(t31-t17)*.509795579104;t17=t29+t19;t29=(t29-t19)*.601344886935;t19=t27+t21;t21=(t27-t21)*.899976223136;t27=t25+t23;t23=(t25-t23)*2.56291544774;t25=t09+t27;t09=(t09-t27)*.541196100146;t27=t17+t19;t19=(t17-t19)*1.30656296488;t17=t25+t27;t27=(t25-t27)*.707106781187;t25=t09+t19;t19=(t09-t19)*.707106781187;t25+=t19;t09=t31+t23;t31=(t31-t23)*.541196100146;t23=t29+t21;t21=(t29-t21)*1.30656296488;t29=t09+t23;t23=(t09-t23)*.707106781187;t09=t31+t21;t31=(t31-t21)*.707106781187;t09+=t31;t29+=t09;t09+=t23;t23+=t31;t17+=t29;t29+=t25;t25+=t09;t09+=t27;t27+=t23;t23+=t19;t19+=t31;t21=t02+t32;t02=(t02-t32)*.502419286188;t32=t04+t30;t04=(t04-t30)*.52249861494;t30=t06+t28;t28=(t06-t28)*.566944034816;t06=t08+t26;t08=(t08-t26)*.64682178336;t26=t10+t24;t10=(t10-t24)*.788154623451;t24=t12+t22;t22=(t12-t22)*1.06067768599;t12=t14+t20;t20=(t14-t20)*1.72244709824;t14=t16+t18;t16=(t16-t18)*5.10114861869;t18=t21+t14;t14=(t21-t14)*.509795579104;t21=t32+t12;t32=(t32-t12)*.601344886935;t12=t30+t24;t24=(t30-t24)*.899976223136;t30=t06+t26;t26=(t06-t26)*2.56291544774;t06=t18+t30;t18=(t18-t30)*.541196100146;t30=t21+t12;t12=(t21-t12)*1.30656296488;t21=t06+t30;t30=(t06-t30)*.707106781187;t06=t18+t12;t12=(t18-t12)*.707106781187;t06+=t12;t18=t14+t26;t26=(t14-t26)*.541196100146;t14=t32+t24;t24=(t32-t24)*1.30656296488;t32=t18+t14;t14=(t18-t14)*.707106781187;t18=t26+t24;t24=(t26-t24)*.707106781187;t18+=t24;t32+=t18;t18+=t14;t26=t14+t24;t14=t02+t16;t02=(t02-t16)*.509795579104;t16=t04+t20;t04=(t04-t20)*.601344886935;t20=t28+t22;t22=(t28-t22)*.899976223136;t28=t08+t10;t10=(t08-t10)*2.56291544774;t08=t14+t28;t14=(t14-t28)*.541196100146;t28=t16+t20;t20=(t16-t20)*1.30656296488;t16=t08+t28;t28=(t08-t28)*.707106781187;t08=t14+t20;t20=(t14-t20)*.707106781187;t08+=t20;t14=t02+t10;t02=(t02-t10)*.541196100146;t10=t04+t22;t22=(t04-t22)*1.30656296488;t04=t14+t10;t10=(t14-t10)*.707106781187;t14=t02+t22;t02=(t02-t22)*.707106781187;t14+=t02;t04+=t14;t14+=t10;t10+=t02;t16+=t04;t04+=t08;t08+=t14;t14+=t28;t28+=t10;t10+=t20;t20+=t02;t21+=t16;t16+=t32;t32+=t04;t04+=t06;t06+=t08;t08+=t18;t18+=t14;t14+=t30;t30+=t28;t28+=t26;t26+=t10;t10+=t12;t12+=t20;t20+=t24;t24+=t02;d[dp+48]=-t33;d[dp+49]=d[dp+47]=-t21;d[dp+50]=d[dp+46]=-t17;d[dp+51]=d[dp+45]=-t16;d[dp+52]=d[dp+44]=-t01;d[dp+53]=d[dp+43]=-t32;d[dp+54]=d[dp+42]=-t29;d[dp+55]=d[dp+41]=-t04;d[dp+56]=d[dp+40]=-t03;d[dp+57]=d[dp+39]=-t06;d[dp+58]=d[dp+38]=-t25;d[dp+59]=d[dp+37]=-t08;d[dp+60]=d[dp+36]=-t11;d[dp+61]=d[dp+35]=-t18;d[dp+62]=d[dp+34]=-t09;d[dp+63]=d[dp+33]=-t14;d[dp+32]=-t05;d[dp+0]=t05;d[dp+31]=-t30;d[dp+1]=t30;d[dp+30]=-t27;d[dp+2]=t27;d[dp+29]=-t28;d[dp+3]=t28;d[dp+28]=-t07;d[dp+4]=t07;d[dp+27]=-t26;d[dp+5]=t26;d[dp+26]=-t23;d[dp+6]=t23;d[dp+25]=-t10;d[dp+7]=t10;d[dp+24]=-t15;d[dp+8]=t15;d[dp+23]=-t12;d[dp+9]=t12;d[dp+22]=-t19;d[dp+10]=t19;d[dp+21]=-t20;d[dp+11]=t20;d[dp+20]=-t13;d[dp+12]=t13;d[dp+19]=-t24;d[dp+13]=t24;d[dp+18]=-t31;d[dp+14]=t31;d[dp+17]=-t02;d[dp+15]=t02;d[dp+16]=0};MP2.FRAME_SYNC=2047;MP2.VERSION={MPEG_2_5:0,MPEG_2:2,MPEG_1:3};MP2.LAYER={III:1,II:2,I:3};MP2.MODE={STEREO:0,JOINT_STEREO:1,DUAL_CHANNEL:2,MONO:3};MP2.SAMPLE_RATE=new Uint16Array([44100,48e3,32e3,0,22050,24e3,16e3,0]);MP2.BIT_RATE=new Uint16Array([32,48,56,64,80,96,112,128,160,192,224,256,320,384,8,16,24,32,40,48,56,64,80,96,112,128,144,160]);MP2.SCALEFACTOR_BASE=new Uint32Array([33554432,26632170,21137968]);MP2.SYNTHESIS_WINDOW=new Float32Array([0,-.5,-.5,-.5,-.5,-.5,-.5,-1,-1,-1,-1,-1.5,-1.5,-2,-2,-2.5,-2.5,-3,-3.5,-3.5,-4,-4.5,-5,-5.5,-6.5,-7,-8,-8.5,-9.5,-10.5,-12,-13,-14.5,-15.5,-17.5,-19,-20.5,-22.5,-24.5,-26.5,-29,-31.5,-34,-36.5,-39.5,-42.5,-45.5,-48.5,-52,-55.5,-58.5,-62.5,-66,-69.5,-73.5,-77,-80.5,-84.5,-88,-91.5,-95,-98,-101,-104,106.5,109,111,112.5,113.5,114,114,113.5,112,110.5,107.5,104,100,94.5,88.5,81.5,73,63.5,53,41.5,28.5,14.5,-1,-18,-36,-55.5,-76.5,-98.5,-122,-147,-173.5,-200.5,-229.5,-259.5,-290.5,-322.5,-355.5,-389.5,-424,-459.5,-495.5,-532,-568.5,-605,-641.5,-678,-714,-749,-783.5,-817,-849,-879.5,-908.5,-935,-959.5,-981,-1000.5,-1016,-1028.5,-1037.5,-1042.5,-1043.5,-1040,-1031.5,1018.5,1e3,976,946.5,911,869.5,822,767.5,707,640,565.5,485,397,302.5,201,92.5,-22.5,-144,-272.5,-407,-547.5,-694,-846,-1003,-1165,-1331.5,-1502,-1675.5,-1852.5,-2031.5,-2212.5,-2394,-2576.5,-2758.5,-2939.5,-3118.5,-3294.5,-3467.5,-3635.5,-3798.5,-3955,-4104.5,-4245.5,-4377.5,-4499,-4609.5,-4708,-4792.5,-4863.5,-4919,-4958,-4979.5,-4983,-4967.5,-4931.5,-4875,-4796,-4694.5,-4569.5,-4420,-4246,-4046,-3820,-3567,3287,2979.5,2644,2280.5,1888,1467.5,1018.5,541,35,-499,-1061,-1650,-2266.5,-2909,-3577,-4270,-4987.5,-5727.5,-6490,-7274,-8077.5,-8899.5,-9739,-10594.5,-11464.5,-12347,-13241,-14144.5,-15056,-15973.5,-16895.5,-17820,-18744.5,-19668,-20588,-21503,-22410.5,-23308.5,-24195,-25068.5,-25926.5,-26767,-27589,-28389,-29166.5,-29919,-30644.5,-31342,-32009.5,-32645,-33247,-33814.5,-34346,-34839.5,-35295,-35710,-36084.5,-36417.5,-36707.5,-36954,-37156.5,-37315,-37428,-37496,37519,37496,37428,37315,37156.5,36954,36707.5,36417.5,36084.5,35710,35295,34839.5,34346,33814.5,33247,32645,32009.5,31342,30644.5,29919,29166.5,28389,27589,26767,25926.5,25068.5,24195,23308.5,22410.5,21503,20588,19668,18744.5,17820,16895.5,15973.5,15056,14144.5,13241,12347,11464.5,10594.5,9739,8899.5,8077.5,7274,6490,5727.5,4987.5,4270,3577,2909,2266.5,1650,1061,499,-35,-541,-1018.5,-1467.5,-1888,-2280.5,-2644,-2979.5,3287,3567,3820,4046,4246,4420,4569.5,4694.5,4796,4875,4931.5,4967.5,4983,4979.5,4958,4919,4863.5,4792.5,4708,4609.5,4499,4377.5,4245.5,4104.5,3955,3798.5,3635.5,3467.5,3294.5,3118.5,2939.5,2758.5,2576.5,2394,2212.5,2031.5,1852.5,1675.5,1502,1331.5,1165,1003,846,694,547.5,407,272.5,144,22.5,-92.5,-201,-302.5,-397,-485,-565.5,-640,-707,-767.5,-822,-869.5,-911,-946.5,-976,-1e3,1018.5,1031.5,1040,1043.5,1042.5,1037.5,1028.5,1016,1000.5,981,959.5,935,908.5,879.5,849,817,783.5,749,714,678,641.5,605,568.5,532,495.5,459.5,424,389.5,355.5,322.5,290.5,259.5,229.5,200.5,173.5,147,122,98.5,76.5,55.5,36,18,1,-14.5,-28.5,-41.5,-53,-63.5,-73,-81.5,-88.5,-94.5,-100,-104,-107.5,-110.5,-112,-113.5,-114,-114,-113.5,-112.5,-111,-109,106.5,104,101,98,95,91.5,88,84.5,80.5,77,73.5,69.5,66,62.5,58.5,55.5,52,48.5,45.5,42.5,39.5,36.5,34,31.5,29,26.5,24.5,22.5,20.5,19,17.5,15.5,14.5,13,12,10.5,9.5,8.5,8,7,6.5,5.5,5,4.5,4,3.5,3.5,3,2.5,2.5,2,2,1.5,1.5,1,1,1,1,.5,.5,.5,.5,.5,.5]);MP2.QUANT_LUT_STEP_1=[[0,0,1,1,1,2,2,2,2,2,2,2,2,2],[0,0,0,0,0,0,1,1,1,2,2,2,2,2]];MP2.QUANT_TAB={A:27|64,B:30|64,C:8,D:12};MP2.QUANT_LUT_STEP_2=[[MP2.QUANT_TAB.C,MP2.QUANT_TAB.C,MP2.QUANT_TAB.D],[MP2.QUANT_TAB.A,MP2.QUANT_TAB.A,MP2.QUANT_TAB.A],[MP2.QUANT_TAB.B,MP2.QUANT_TAB.A,MP2.QUANT_TAB.B]];MP2.QUANT_LUT_STEP_3=[[68,68,52,52,52,52,52,52,52,52,52,52],[67,67,67,66,66,66,66,66,66,66,66,49,49,49,49,49,49,49,49,49,49,49,49,32,32,32,32,32,32,32],[69,69,69,69,52,52,52,52,52,52,52,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36]];MP2.QUANT_LUT_STEP4=[[0,1,2,17],[0,1,2,3,4,5,6,17],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17],[0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17],[0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,17],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]];MP2.QUANT_TAB=[{levels:3,group:1,bits:5},{levels:5,group:1,bits:7},{levels:7,group:0,bits:3},{levels:9,group:1,bits:10},{levels:15,group:0,bits:4},{levels:31,group:0,bits:5},{levels:63,group:0,bits:6},{levels:127,group:0,bits:7},{levels:255,group:0,bits:8},{levels:511,group:0,bits:9},{levels:1023,group:0,bits:10},{levels:2047,group:0,bits:11},{levels:4095,group:0,bits:12},{levels:8191,group:0,bits:13},{levels:16383,group:0,bits:14},{levels:32767,group:0,bits:15},{levels:65535,group:0,bits:16}];return MP2}();JSMpeg.Renderer.WebGL=function(){"use strict";var WebGLRenderer=function(options){this.canvas=options.canvas||document.createElement("canvas");this.width=this.canvas.width;this.height=this.canvas.height;this.enabled=true;var contextCreateOptions={preserveDrawingBuffer:!!options.preserveDrawingBuffer,alpha:false,depth:false,stencil:false,antialias:false};this.gl=this.canvas.getContext("webgl",contextCreateOptions)||this.canvas.getContext("experimental-webgl",contextCreateOptions);if(!this.gl){throw new Error("Failed to get WebGL Context")}var gl=this.gl;var vertexAttr=null;this.vertexBuffer=gl.createBuffer();var vertexCoords=new Float32Array([0,0,0,1,1,0,1,1]);gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,vertexCoords,gl.STATIC_DRAW);this.program=this.createProgram(WebGLRenderer.SHADER.VERTEX_IDENTITY,WebGLRenderer.SHADER.FRAGMENT_YCRCB_TO_RGBA);vertexAttr=gl.getAttribLocation(this.program,"vertex");gl.enableVertexAttribArray(vertexAttr);gl.vertexAttribPointer(vertexAttr,2,gl.FLOAT,false,0,0);this.textureY=this.createTexture(0,"textureY");this.textureCb=this.createTexture(1,"textureCb");this.textureCr=this.createTexture(2,"textureCr");this.loadingProgram=this.createProgram(WebGLRenderer.SHADER.VERTEX_IDENTITY,WebGLRenderer.SHADER.FRAGMENT_LOADING);vertexAttr=gl.getAttribLocation(this.loadingProgram,"vertex");gl.enableVertexAttribArray(vertexAttr);gl.vertexAttribPointer(vertexAttr,2,gl.FLOAT,false,0,0);this.shouldCreateUnclampedViews=!this.allowsClampedTextureData()};WebGLRenderer.prototype.destroy=function(){var gl=this.gl;gl.deleteTexture(this.textureY);gl.deleteTexture(this.textureCb);gl.deleteTexture(this.textureCr);gl.deleteProgram(this.program);gl.deleteProgram(this.loadingProgram);gl.deleteBuffer(this.vertexBuffer)};WebGLRenderer.prototype.resize=function(width,height){this.width=width|0;this.height=height|0;this.canvas.width=this.width;this.canvas.height=this.height;this.gl.useProgram(this.program);this.gl.viewport(0,0,this.width,this.height)};WebGLRenderer.prototype.createTexture=function(index,name){var gl=this.gl;var texture=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,texture);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE); -gl.uniform1i(gl.getUniformLocation(this.program,name),index);return texture};WebGLRenderer.prototype.createProgram=function(vsh,fsh){var gl=this.gl;var program=gl.createProgram();gl.attachShader(program,this.compileShader(gl.VERTEX_SHADER,vsh));gl.attachShader(program,this.compileShader(gl.FRAGMENT_SHADER,fsh));gl.linkProgram(program);gl.useProgram(program);return program};WebGLRenderer.prototype.compileShader=function(type,source){var gl=this.gl;var shader=gl.createShader(type);gl.shaderSource(shader,source);gl.compileShader(shader);if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){throw new Error(gl.getShaderInfoLog(shader))}return shader};WebGLRenderer.prototype.allowsClampedTextureData=function(){var gl=this.gl;var texture=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,texture);gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE,1,1,0,gl.LUMINANCE,gl.UNSIGNED_BYTE,new Uint8ClampedArray([0]));return gl.getError()===0};WebGLRenderer.prototype.renderProgress=function(progress){var gl=this.gl;gl.useProgram(this.loadingProgram);var loc=gl.getUniformLocation(this.loadingProgram,"progress");gl.uniform1f(loc,progress);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};WebGLRenderer.prototype.render=function(y,cb,cr){if(!this.enabled){return}var gl=this.gl;var w=this.width+15>>4<<4,h=this.height,w2=w>>1,h2=h>>1;if(this.shouldCreateUnclampedViews){y=new Uint8Array(y.buffer),cb=new Uint8Array(cb.buffer),cr=new Uint8Array(cr.buffer)}gl.useProgram(this.program);this.updateTexture(gl.TEXTURE0,this.textureY,w,h,y);this.updateTexture(gl.TEXTURE1,this.textureCb,w2,h2,cb);this.updateTexture(gl.TEXTURE2,this.textureCr,w2,h2,cr);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};WebGLRenderer.prototype.updateTexture=function(unit,texture,w,h,data){var gl=this.gl;gl.activeTexture(unit);gl.bindTexture(gl.TEXTURE_2D,texture);gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE,w,h,0,gl.LUMINANCE,gl.UNSIGNED_BYTE,data)};WebGLRenderer.IsSupported=function(){try{if(!window.WebGLRenderingContext){return false}var canvas=document.createElement("canvas");return!!(canvas.getContext("webgl")||canvas.getContext("experimental-webgl"))}catch(err){return false}};WebGLRenderer.SHADER={FRAGMENT_YCRCB_TO_RGBA:["precision mediump float;","uniform sampler2D textureY;","uniform sampler2D textureCb;","uniform sampler2D textureCr;","varying vec2 texCoord;","mat4 rec601 = mat4(","1.16438, 0.00000, 1.59603, -0.87079,","1.16438, -0.39176, -0.81297, 0.52959,","1.16438, 2.01723, 0.00000, -1.08139,","0, 0, 0, 1",");","void main() {","float y = texture2D(textureY, texCoord).r;","float cb = texture2D(textureCb, texCoord).r;","float cr = texture2D(textureCr, texCoord).r;","gl_FragColor = vec4(y, cr, cb, 1.0) * rec601;","}"].join("\n"),FRAGMENT_LOADING:["precision mediump float;","uniform float progress;","varying vec2 texCoord;","void main() {","float c = ceil(progress-(1.0-texCoord.y));","gl_FragColor = vec4(c,c,c,1);","}"].join("\n"),VERTEX_IDENTITY:["attribute vec2 vertex;","varying vec2 texCoord;","void main() {","texCoord = vertex;","gl_Position = vec4((vertex * 2.0 - 1.0) * vec2(1, -1), 0.0, 1.0);","}"].join("\n")};return WebGLRenderer}();JSMpeg.Renderer.Canvas2D=function(){"use strict";var CanvasRenderer=function(options){this.canvas=options.canvas||document.createElement("canvas");this.width=this.canvas.width;this.height=this.canvas.height;this.enabled=true;this.context=this.canvas.getContext("2d")};CanvasRenderer.prototype.destroy=function(){};CanvasRenderer.prototype.resize=function(width,height){this.width=width|0;this.height=height|0;this.canvas.width=this.width;this.canvas.height=this.height;this.imageData=this.context.getImageData(0,0,this.width,this.height);JSMpeg.Fill(this.imageData.data,255)};CanvasRenderer.prototype.renderProgress=function(progress){var w=this.canvas.width,h=this.canvas.height,ctx=this.context;ctx.fillStyle="#222";ctx.fillRect(0,0,w,h);ctx.fillStyle="#fff";ctx.fillRect(0,h-h*progress,w,h*progress)};CanvasRenderer.prototype.render=function(y,cb,cr){this.YCbCrToRGBA(y,cb,cr,this.imageData.data);this.context.putImageData(this.imageData,0,0)};CanvasRenderer.prototype.YCbCrToRGBA=function(y,cb,cr,rgba){if(!this.enabled){return}var w=this.width+15>>4<<4,w2=w>>1;var yIndex1=0,yIndex2=w,yNext2Lines=w+(w-this.width);var cIndex=0,cNextLine=w2-(this.width>>1);var rgbaIndex1=0,rgbaIndex2=this.width*4,rgbaNext2Lines=this.width*4;var cols=this.width>>1,rows=this.height>>1;var ccb,ccr,r,g,b;for(var row=0;row>8)-179;g=(ccr*88>>8)-44+(ccb*183>>8)-91;b=ccr+(ccr*198>>8)-227;var y1=y[yIndex1++];var y2=y[yIndex1++];rgba[rgbaIndex1]=y1+r;rgba[rgbaIndex1+1]=y1-g;rgba[rgbaIndex1+2]=y1+b;rgba[rgbaIndex1+4]=y2+r;rgba[rgbaIndex1+5]=y2-g;rgba[rgbaIndex1+6]=y2+b;rgbaIndex1+=8;var y3=y[yIndex2++];var y4=y[yIndex2++];rgba[rgbaIndex2]=y3+r;rgba[rgbaIndex2+1]=y3-g;rgba[rgbaIndex2+2]=y3+b;rgba[rgbaIndex2+4]=y4+r;rgba[rgbaIndex2+5]=y4-g;rgba[rgbaIndex2+6]=y4+b;rgbaIndex2+=8}yIndex1+=yNext2Lines;yIndex2+=yNext2Lines;rgbaIndex1+=rgbaNext2Lines;rgbaIndex2+=rgbaNext2Lines;cIndex+=cNextLine}};return CanvasRenderer}();JSMpeg.AudioOutput.WebAudio=function(){"use strict";var WebAudioOut=function(options){this.context=WebAudioOut.CachedContext=WebAudioOut.CachedContext||new(window.AudioContext||window.webkitAudioContext);this.gain=this.context.createGain();this.destination=this.gain;this.gain.connect(this.context.destination);this.context._connections=(this.context._connections||0)+1;this.startTime=0;this.buffer=null;this.wallclockStartTime=0;this.volume=1;this.enabled=true;this.unlocked=!WebAudioOut.NeedsUnlocking();Object.defineProperty(this,"enqueuedTime",{get:this.getEnqueuedTime})};WebAudioOut.prototype.destroy=function(){this.gain.disconnect();this.context._connections--;if(this.context._connections===0){this.context.close();WebAudioOut.CachedContext=null}};WebAudioOut.prototype.play=function(sampleRate,left,right){if(!this.enabled){return}if(!this.unlocked){var ts=JSMpeg.Now();if(this.wallclockStartTime'+''+''+"";VideoElement.UNMUTE_BUTTON=''+''+''+''+''+""+"";return VideoElement}();JSMpeg.Player=function(){"use strict";var Player=function(url,options){this.options=options||{};if(options.source){this.source=new options.source(url,options);options.streaming=!!this.source.streaming}else if(url.match(/^wss?:\/\//)){this.source=new JSMpeg.Source.WebSocket(url,options);options.streaming=true}else if(options.progressive!==false){this.source=new JSMpeg.Source.AjaxProgressive(url,options);options.streaming=false}else{this.source=new JSMpeg.Source.Ajax(url,options);options.streaming=false}this.maxAudioLag=options.maxAudioLag||.25;this.loop=options.loop!==false;this.autoplay=!!options.autoplay||options.streaming;this.demuxer=new JSMpeg.Demuxer.TS(options);this.source.connect(this.demuxer);if(!options.disableWebAssembly&&JSMpeg.WASMModule.IsSupported()){this.wasmModule=new JSMpeg.WASMModule;options.wasmModule=this.wasmModule}if(options.video!==false){this.video=options.wasmModule?new JSMpeg.Decoder.MPEG1VideoWASM(options):new JSMpeg.Decoder.MPEG1Video(options);this.renderer=!options.disableGl&&JSMpeg.Renderer.WebGL.IsSupported()?new JSMpeg.Renderer.WebGL(options):new JSMpeg.Renderer.Canvas2D(options);this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.VIDEO_1,this.video);this.video.connect(this.renderer)}if(options.audio!==false&&JSMpeg.AudioOutput.WebAudio.IsSupported()){this.audio=options.wasmModule?new JSMpeg.Decoder.MP2AudioWASM(options):new JSMpeg.Decoder.MP2Audio(options);this.audioOut=new JSMpeg.AudioOutput.WebAudio(options);this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.AUDIO_1,this.audio);this.audio.connect(this.audioOut)}Object.defineProperty(this,"currentTime",{get:this.getCurrentTime,set:this.setCurrentTime});Object.defineProperty(this,"volume",{get:this.getVolume,set:this.setVolume});this.unpauseOnShow=false;if(options.pauseWhenHidden!==false){document.addEventListener("visibilitychange",this.showHide.bind(this))}if(this.wasmModule){if(JSMpeg.WASM_BINARY_INLINED){var wasm=JSMpeg.Base64ToArrayBuffer(JSMpeg.WASM_BINARY_INLINED);this.wasmModule.loadFromBuffer(wasm,this.startLoading.bind(this))}else{this.wasmModule.loadFromFile("jsmpeg.wasm",this.startLoading.bind(this))}}else{this.startLoading()}};Player.prototype.startLoading=function(){this.source.start();if(this.autoplay){this.play()}};Player.prototype.showHide=function(ev){if(document.visibilityState==="hidden"){this.unpauseOnShow=this.wantsToPlay;this.pause()}else if(this.unpauseOnShow){this.play()}};Player.prototype.play=function(ev){this.animationId=requestAnimationFrame(this.update.bind(this));this.wantsToPlay=true};Player.prototype.pause=function(ev){cancelAnimationFrame(this.animationId);this.wantsToPlay=false;this.isPlaying=false;if(this.audio&&this.audio.canPlay){this.audioOut.stop();this.seek(this.currentTime)}};Player.prototype.getVolume=function(){return this.audioOut?this.audioOut.volume:0};Player.prototype.setVolume=function(volume){if(this.audioOut){this.audioOut.volume=volume}};Player.prototype.stop=function(ev){this.pause();this.seek(0);if(this.video&&this.options.decodeFirstFrame!==false){this.video.decode()}};Player.prototype.destroy=function(){this.pause();this.source.destroy();this.video&&this.video.destroy();this.renderer&&this.renderer.destroy();this.audio&&this.audio.destroy();this.audioOut&&this.audioOut.destroy()};Player.prototype.seek=function(time){var startOffset=this.audio&&this.audio.canPlay?this.audio.startTime:this.video.startTime;if(this.video){this.video.seek(time+startOffset)}if(this.audio){this.audio.seek(time+startOffset)}this.startTime=JSMpeg.Now()-time};Player.prototype.getCurrentTime=function(){return this.audio&&this.audio.canPlay?this.audio.currentTime-this.audio.startTime:this.video.currentTime-this.video.startTime};Player.prototype.setCurrentTime=function(time){this.seek(time)};Player.prototype.update=function(){this.animationId=requestAnimationFrame(this.update.bind(this));if(!this.source.established){if(this.renderer){this.renderer.renderProgress(this.source.progress)}return}if(!this.isPlaying){this.isPlaying=true;this.startTime=JSMpeg.Now()-this.currentTime}if(this.options.streaming){this.updateForStreaming()}else{this.updateForStaticFile()}};Player.prototype.updateForStreaming=function(){if(this.video){this.video.decode()}if(this.audio){var decoded=false;do{if(this.audioOut.enqueuedTime>this.maxAudioLag){this.audioOut.resetEnqueuedTime();this.audioOut.enabled=false}decoded=this.audio.decode()}while(decoded);this.audioOut.enabled=true}};Player.prototype.updateForStaticFile=function(){var notEnoughData=false,headroom=0;if(this.audio&&this.audio.canPlay){while(!notEnoughData&&this.audio.decodedTime-this.audio.currentTime<.25){notEnoughData=!this.audio.decode()}if(this.video&&this.video.currentTime0){if(lateTime>frameTime*2){this.startTime+=lateTime}notEnoughData=!this.video.decode()}headroom=this.demuxer.currentTime-targetTime}this.source.resume(headroom);if(notEnoughData&&this.source.completed){if(this.loop){this.seek(0)}else{this.pause()}}};return Player}();JSMpeg.BitBuffer=function(){"use strict";var BitBuffer=function(bufferOrLength,mode){if(typeof bufferOrLength==="object"){this.bytes=bufferOrLength instanceof Uint8Array?bufferOrLength:new Uint8Array(bufferOrLength);this.byteLength=this.bytes.length}else{this.bytes=new Uint8Array(bufferOrLength||1024*1024);this.byteLength=0}this.mode=mode||BitBuffer.MODE.EXPAND;this.index=0};BitBuffer.prototype.resize=function(size){var newBytes=new Uint8Array(size);if(this.byteLength!==0){this.byteLength=Math.min(this.byteLength,size);newBytes.set(this.bytes,0,this.byteLength)}this.bytes=newBytes;this.index=Math.min(this.index,this.byteLength<<3)};BitBuffer.prototype.evict=function(sizeNeeded){var bytePos=this.index>>3,available=this.bytes.length-this.byteLength;if(this.index===this.byteLength<<3||sizeNeeded>available+bytePos){this.byteLength=0;this.index=0;return}else if(bytePos===0){return}if(this.bytes.copyWithin){this.bytes.copyWithin(0,bytePos,this.byteLength)}else{this.bytes.set(this.bytes.subarray(bytePos,this.byteLength))}this.byteLength=this.byteLength-bytePos;this.index-=bytePos<<3;return};BitBuffer.prototype.write=function(buffers){var isArrayOfBuffers=typeof buffers[0]==="object",totalLength=0,available=this.bytes.length-this.byteLength;if(isArrayOfBuffers){var totalLength=0;for(var i=0;iavailable){if(this.mode===BitBuffer.MODE.EXPAND){var newSize=Math.max(this.bytes.length*2,totalLength-available);this.resize(newSize)}else{this.evict(totalLength)}}if(isArrayOfBuffers){for(var i=0;i>3;i>3;return i>=this.byteLength||this.bytes[i]==0&&this.bytes[i+1]==0&&this.bytes[i+2]==1};BitBuffer.prototype.peek=function(count){var offset=this.index;var value=0;while(count){var currentByte=this.bytes[offset>>3],remaining=8-(offset&7),read=remaining>8-read;value=value<>shift;offset+=read;count-=read}return value};BitBuffer.prototype.read=function(count){var value=this.peek(count);this.index+=count;return value};BitBuffer.prototype.skip=function(count){return this.index+=count};BitBuffer.prototype.rewind=function(count){this.index=Math.max(this.index-count,0)};BitBuffer.prototype.has=function(count){return(this.byteLength<<3)-this.index>=count};BitBuffer.MODE={EVICT:1,EXPAND:2};return BitBuffer}();JSMpeg.Source.Ajax=function(){"use strict";var AjaxSource=function(url,options){this.url=url;this.destination=null;this.request=null;this.completed=false;this.established=false;this.progress=0};AjaxSource.prototype.connect=function(destination){this.destination=destination};AjaxSource.prototype.start=function(){this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE&&this.request.status===200){this.onLoad(this.request.response)}}.bind(this);this.request.onprogress=this.onProgress.bind(this);this.request.open("GET",this.url);this.request.responseType="arraybuffer";this.request.send()};AjaxSource.prototype.resume=function(secondsHeadroom){};AjaxSource.prototype.destroy=function(){this.request.abort()};AjaxSource.prototype.onProgress=function(ev){this.progress=ev.loaded/ev.total};AjaxSource.prototype.onLoad=function(data){this.established=true;this.completed=true;this.progress=1;if(this.destination){this.destination.write(data)}};return AjaxSource}();JSMpeg.Source.AjaxProgressive=function(){"use strict";var AjaxProgressiveSource=function(url,options){this.url=url;this.destination=null;this.request=null;this.completed=false;this.established=false;this.progress=0;this.fileSize=0;this.loadedSize=0;this.chunkSize=options.chunkSize||1024*1024;this.isLoading=false;this.loadStartTime=0;this.throttled=options.throttled!==false;this.aborted=false};AjaxProgressiveSource.prototype.connect=function(destination){this.destination=destination};AjaxProgressiveSource.prototype.start=function(){this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE){this.fileSize=parseInt(this.request.getResponseHeader("Content-Length"));this.loadNextChunk()}}.bind(this);this.request.onprogress=this.onProgress.bind(this);this.request.open("HEAD",this.url);this.request.send()};AjaxProgressiveSource.prototype.resume=function(secondsHeadroom){if(this.isLoading||!this.throttled){return}var worstCaseLoadingTime=this.loadTime*8+2;if(worstCaseLoadingTime>secondsHeadroom){this.loadNextChunk()}};AjaxProgressiveSource.prototype.destroy=function(){this.request.abort();this.aborted=true};AjaxProgressiveSource.prototype.loadNextChunk=function(){var start=this.loadedSize,end=Math.min(this.loadedSize+this.chunkSize-1,this.fileSize-1);if(start>=this.fileSize||this.aborted){this.completed=true;return}this.isLoading=true;this.loadStartTime=JSMpeg.Now();this.request=new XMLHttpRequest;this.request.onreadystatechange=function(){if(this.request.readyState===this.request.DONE&&this.request.status>=200&&this.request.status<300){this.onChunkLoad(this.request.response)}else if(this.request.readyState===this.request.DONE){if(this.loadFails++<3){this.loadNextChunk()}}}.bind(this);if(start===0){this.request.onprogress=this.onProgress.bind(this)}this.request.open("GET",this.url+"?"+start+"-"+end);this.request.setRequestHeader("Range","bytes="+start+"-"+end);this.request.responseType="arraybuffer";this.request.send()};AjaxProgressiveSource.prototype.onProgress=function(ev){this.progress=ev.loaded/ev.total};AjaxProgressiveSource.prototype.onChunkLoad=function(data){this.established=true;this.progress=1;this.loadedSize+=data.byteLength;this.loadFails=0;this.isLoading=false;if(this.destination){this.destination.write(data)}this.loadTime=JSMpeg.Now()-this.loadStartTime;if(!this.throttled){this.loadNextChunk()}};return AjaxProgressiveSource}();JSMpeg.Source.WebSocket=function(){"use strict";var WSSource=function(url,options){this.url=url;this.options=options;this.socket=null;this.callbacks={connect:[],data:[]};this.destination=null;this.reconnectInterval=options.reconnectInterval!==undefined?options.reconnectInterval:5;this.shouldAttemptReconnect=!!this.reconnectInterval;this.completed=false;this.established=false;this.progress=0;this.reconnectTimeoutId=0};WSSource.prototype.connect=function(destination){this.destination=destination};WSSource.prototype.destroy=function(){clearTimeout(this.reconnectTimeoutId);this.shouldAttemptReconnect=false;this.socket.close()};WSSource.prototype.start=function(){this.shouldAttemptReconnect=!!this.reconnectInterval;this.progress=0;this.established=false;this.socket=new WebSocket(this.url,this.options.protocols||null);this.socket.binaryType="arraybuffer";this.socket.onmessage=this.onMessage.bind(this);this.socket.onopen=this.onOpen.bind(this);this.socket.onerror=this.onClose.bind(this);this.socket.onclose=this.onClose.bind(this)};WSSource.prototype.resume=function(secondsHeadroom){};WSSource.prototype.onOpen=function(){this.progress=1;this.established=true};WSSource.prototype.onClose=function(){if(this.shouldAttemptReconnect){clearTimeout(this.reconnectTimeoutId);this.reconnectTimeoutId=setTimeout(function(){this.start()}.bind(this),this.reconnectInterval*1e3)}};WSSource.prototype.onMessage=function(ev){if(this.destination){this.destination.write(ev.data)}};return WSSource}();JSMpeg.Demuxer.TS=function(){"use strict";var TS=function(options){this.bits=null;this.leftoverBytes=null;this.guessVideoFrameEnd=true;this.pidsToStreamIds={};this.pesPacketInfo={};this.startTime=0;this.currentTime=0};TS.prototype.connect=function(streamId,destination){this.pesPacketInfo[streamId]={destination:destination,currentLength:0,totalLength:0,pts:0,buffers:[]}};TS.prototype.write=function(buffer){if(this.leftoverBytes){var totalLength=buffer.byteLength+this.leftoverBytes.byteLength;this.bits=new JSMpeg.BitBuffer(totalLength);this.bits.write([this.leftoverBytes,buffer])}else{this.bits=new JSMpeg.BitBuffer(buffer)}while(this.bits.has(188<<3)&&this.parsePacket()){}var leftoverCount=this.bits.byteLength-(this.bits.index>>3);this.leftoverBytes=leftoverCount>0?this.bits.bytes.subarray(this.bits.index>>3):null};TS.prototype.parsePacket=function(){if(this.bits.read(8)!==71){if(!this.resync()){return false}}var end=(this.bits.index>>3)+187;var transportError=this.bits.read(1),payloadStart=this.bits.read(1),transportPriority=this.bits.read(1),pid=this.bits.read(13),transportScrambling=this.bits.read(2),adaptationField=this.bits.read(2),continuityCounter=this.bits.read(4);var streamId=this.pidsToStreamIds[pid];if(payloadStart&&streamId){var pi=this.pesPacketInfo[streamId];if(pi&&pi.currentLength){this.packetComplete(pi)}}if(adaptationField&1){if(adaptationField&2){var adaptationFieldLength=this.bits.read(8);this.bits.skip(adaptationFieldLength<<3)}if(payloadStart&&this.bits.nextBytesAreStartCode()){this.bits.skip(24);streamId=this.bits.read(8);this.pidsToStreamIds[pid]=streamId;var packetLength=this.bits.read(16);this.bits.skip(8);var ptsDtsFlag=this.bits.read(2);this.bits.skip(6);var headerLength=this.bits.read(8);var payloadBeginIndex=this.bits.index+(headerLength<<3);var pi=this.pesPacketInfo[streamId];if(pi){var pts=0;if(ptsDtsFlag&2){this.bits.skip(4);var p32_30=this.bits.read(3);this.bits.skip(1);var p29_15=this.bits.read(15);this.bits.skip(1);var p14_0=this.bits.read(15);this.bits.skip(1);pts=(p32_30*1073741824+p29_15*32768+p14_0)/9e4;this.currentTime=pts;if(this.startTime===-1){this.startTime=pts}}var payloadLength=packetLength?packetLength-headerLength-3:0;this.packetStart(pi,pts,payloadLength)}this.bits.index=payloadBeginIndex}if(streamId){var pi=this.pesPacketInfo[streamId];if(pi){var start=this.bits.index>>3;var complete=this.packetAddData(pi,start,end);var hasPadding=!payloadStart&&adaptationField&2;if(complete||this.guessVideoFrameEnd&&hasPadding){this.packetComplete(pi)}}}}this.bits.index=end<<3;return true};TS.prototype.resync=function(){if(!this.bits.has(188*6<<3)){return false}var byteIndex=this.bits.index>>3;for(var i=0;i<187;i++){if(this.bits.bytes[byteIndex+i]===71){var foundSync=true;for(var j=1;j<5;j++){if(this.bits.bytes[byteIndex+i+188*j]!==71){foundSync=false;break}}if(foundSync){this.bits.index=byteIndex+i+1<<3;return true}}}console.warn("JSMpeg: Possible garbage data. Skipping.");this.bits.skip(187<<3);return false};TS.prototype.packetStart=function(pi,pts,payloadLength){pi.totalLength=payloadLength;pi.currentLength=0;pi.pts=pts};TS.prototype.packetAddData=function(pi,start,end){pi.buffers.push(this.bits.bytes.subarray(start,end));pi.currentLength+=end-start;var complete=pi.totalLength!==0&&pi.currentLength>=pi.totalLength;return complete};TS.prototype.packetComplete=function(pi){pi.destination.write(pi.pts,pi.buffers);pi.totalLength=0;pi.currentLength=0;pi.buffers=[]};TS.STREAM={PACK_HEADER:186,SYSTEM_HEADER:187,PROGRAM_MAP:188,PRIVATE_1:189,PADDING:190,PRIVATE_2:191,AUDIO_1:192,VIDEO_1:224,DIRECTORY:255};return TS}();JSMpeg.Decoder.Base=function(){"use strict";var BaseDecoder=function(options){this.destination=null;this.canPlay=false;this.collectTimestamps=!options.streaming;this.bytesWritten=0;this.timestamps=[];this.timestampIndex=0;this.startTime=0;this.decodedTime=0;Object.defineProperty(this,"currentTime",{get:this.getCurrentTime})};BaseDecoder.prototype.destroy=function(){};BaseDecoder.prototype.connect=function(destination){this.destination=destination};BaseDecoder.prototype.bufferGetIndex=function(){return this.bits.index};BaseDecoder.prototype.bufferSetIndex=function(index){this.bits.index=index};BaseDecoder.prototype.bufferWrite=function(buffers){return this.bits.write(buffers)};BaseDecoder.prototype.write=function(pts,buffers){if(this.collectTimestamps){if(this.timestamps.length===0){this.startTime=pts;this.decodedTime=pts}this.timestamps.push({index:this.bytesWritten<<3,time:pts})}this.bytesWritten+=this.bufferWrite(buffers);this.canPlay=true};BaseDecoder.prototype.seek=function(time){if(!this.collectTimestamps){return}this.timestampIndex=0;for(var i=0;itime){break}this.timestampIndex=i}var ts=this.timestamps[this.timestampIndex];if(ts){this.bufferSetIndex(ts.index);this.decodedTime=ts.time}else{this.bufferSetIndex(0);this.decodedTime=this.startTime}};BaseDecoder.prototype.decode=function(){this.advanceDecodedTime(0)};BaseDecoder.prototype.advanceDecodedTime=function(seconds){if(this.collectTimestamps){var newTimestampIndex=-1;var currentIndex=this.bufferGetIndex();for(var i=this.timestampIndex;icurrentIndex){break}newTimestampIndex=i}if(newTimestampIndex!==-1&&newTimestampIndex!==this.timestampIndex){this.timestampIndex=newTimestampIndex;this.decodedTime=this.timestamps[this.timestampIndex].time;return}}this.decodedTime+=seconds};BaseDecoder.prototype.getCurrentTime=function(){return this.decodedTime};return BaseDecoder}();JSMpeg.Decoder.MPEG1Video=function(){"use strict";var MPEG1=function(options){JSMpeg.Decoder.Base.call(this,options);var bufferSize=options.videoBufferSize||512*1024;var bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.bits=new JSMpeg.BitBuffer(bufferSize,bufferMode);this.customIntraQuantMatrix=new Uint8Array(64);this.customNonIntraQuantMatrix=new Uint8Array(64);this.blockData=new Int32Array(64);this.currentFrame=0;this.decodeFirstFrame=options.decodeFirstFrame!==false};MPEG1.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MPEG1.prototype.constructor=MPEG1;MPEG1.prototype.write=function(pts,buffers){JSMpeg.Decoder.Base.prototype.write.call(this,pts,buffers);if(!this.hasSequenceHeader){if(this.bits.findStartCode(MPEG1.START.SEQUENCE)===-1){return false}this.decodeSequenceHeader();if(this.decodeFirstFrame){this.decode()}}};MPEG1.prototype.decode=function(){if(!this.hasSequenceHeader){return false}if(this.bits.findStartCode(MPEG1.START.PICTURE)===-1){var bufferedBytes=this.bits.byteLength-(this.bits.index>>3);return false}this.decodePicture();this.advanceDecodedTime(1/this.frameRate);return true};MPEG1.prototype.readHuffman=function(codeTable){var state=0;do{state=codeTable[state+this.bits.read(1)]}while(state>=0&&codeTable[state]!==0);return codeTable[state+2]};MPEG1.prototype.frameRate=30;MPEG1.prototype.decodeSequenceHeader=function(){var newWidth=this.bits.read(12),newHeight=this.bits.read(12);this.bits.skip(4);this.frameRate=MPEG1.PICTURE_RATE[this.bits.read(4)];this.bits.skip(18+1+10+1);if(newWidth!==this.width||newHeight!==this.height){this.width=newWidth;this.height=newHeight;this.initBuffers();if(this.destination){this.destination.resize(newWidth,newHeight)}}if(this.bits.read(1)){for(var i=0;i<64;i++){this.customIntraQuantMatrix[MPEG1.ZIG_ZAG[i]]=this.bits.read(8)}this.intraQuantMatrix=this.customIntraQuantMatrix}if(this.bits.read(1)){for(var i=0;i<64;i++){var idx=MPEG1.ZIG_ZAG[i];this.customNonIntraQuantMatrix[idx]=this.bits.read(8)}this.nonIntraQuantMatrix=this.customNonIntraQuantMatrix}this.hasSequenceHeader=true};MPEG1.prototype.initBuffers=function(){this.intraQuantMatrix=MPEG1.DEFAULT_INTRA_QUANT_MATRIX;this.nonIntraQuantMatrix=MPEG1.DEFAULT_NON_INTRA_QUANT_MATRIX;this.mbWidth=this.width+15>>4;this.mbHeight=this.height+15>>4;this.mbSize=this.mbWidth*this.mbHeight;this.codedWidth=this.mbWidth<<4;this.codedHeight=this.mbHeight<<4;this.codedSize=this.codedWidth*this.codedHeight;this.halfWidth=this.mbWidth<<3;this.halfHeight=this.mbHeight<<3;this.currentY=new Uint8ClampedArray(this.codedSize);this.currentY32=new Uint32Array(this.currentY.buffer);this.currentCr=new Uint8ClampedArray(this.codedSize>>2);this.currentCr32=new Uint32Array(this.currentCr.buffer);this.currentCb=new Uint8ClampedArray(this.codedSize>>2);this.currentCb32=new Uint32Array(this.currentCb.buffer);this.forwardY=new Uint8ClampedArray(this.codedSize);this.forwardY32=new Uint32Array(this.forwardY.buffer);this.forwardCr=new Uint8ClampedArray(this.codedSize>>2);this.forwardCr32=new Uint32Array(this.forwardCr.buffer);this.forwardCb=new Uint8ClampedArray(this.codedSize>>2);this.forwardCb32=new Uint32Array(this.forwardCb.buffer)};MPEG1.prototype.currentY=null;MPEG1.prototype.currentCr=null;MPEG1.prototype.currentCb=null;MPEG1.prototype.pictureType=0;MPEG1.prototype.forwardY=null;MPEG1.prototype.forwardCr=null;MPEG1.prototype.forwardCb=null;MPEG1.prototype.fullPelForward=false;MPEG1.prototype.forwardFCode=0;MPEG1.prototype.forwardRSize=0;MPEG1.prototype.forwardF=0;MPEG1.prototype.decodePicture=function(skipOutput){this.currentFrame++;this.bits.skip(10);this.pictureType=this.bits.read(3);this.bits.skip(16);if(this.pictureType<=0||this.pictureType>=MPEG1.PICTURE_TYPE.B){return}if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.fullPelForward=this.bits.read(1);this.forwardFCode=this.bits.read(3);if(this.forwardFCode===0){return}this.forwardRSize=this.forwardFCode-1;this.forwardF=1<=MPEG1.START.SLICE_FIRST&&code<=MPEG1.START.SLICE_LAST){this.decodeSlice(code&255);code=this.bits.findNextStartCode()}if(code!==-1){this.bits.rewind(32)}if(this.destination){this.destination.render(this.currentY,this.currentCr,this.currentCb,true)}if(this.pictureType===MPEG1.PICTURE_TYPE.INTRA||this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){var tmpY=this.forwardY,tmpY32=this.forwardY32,tmpCr=this.forwardCr,tmpCr32=this.forwardCr32,tmpCb=this.forwardCb,tmpCb32=this.forwardCb32;this.forwardY=this.currentY;this.forwardY32=this.currentY32;this.forwardCr=this.currentCr;this.forwardCr32=this.currentCr32;this.forwardCb=this.currentCb;this.forwardCb32=this.currentCb32;this.currentY=tmpY;this.currentY32=tmpY32;this.currentCr=tmpCr;this.currentCr32=tmpCr32;this.currentCb=tmpCb;this.currentCb32=tmpCb32}};MPEG1.prototype.quantizerScale=0;MPEG1.prototype.sliceBegin=false;MPEG1.prototype.decodeSlice=function(slice){this.sliceBegin=true;this.macroblockAddress=(slice-1)*this.mbWidth-1;this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0;this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;this.quantizerScale=this.bits.read(5);while(this.bits.read(1)){this.bits.skip(8)}do{this.decodeMacroblock()}while(!this.bits.nextBytesAreStartCode())};MPEG1.prototype.macroblockAddress=0;MPEG1.prototype.mbRow=0;MPEG1.prototype.mbCol=0;MPEG1.prototype.macroblockType=0;MPEG1.prototype.macroblockIntra=false;MPEG1.prototype.macroblockMotFw=false;MPEG1.prototype.motionFwH=0;MPEG1.prototype.motionFwV=0;MPEG1.prototype.motionFwHPrev=0;MPEG1.prototype.motionFwVPrev=0;MPEG1.prototype.decodeMacroblock=function(){var increment=0,t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT);while(t===34){t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT)}while(t===35){increment+=33;t=this.readHuffman(MPEG1.MACROBLOCK_ADDRESS_INCREMENT)}increment+=t;if(this.sliceBegin){this.sliceBegin=false;this.macroblockAddress+=increment}else{if(this.macroblockAddress+increment>=this.mbSize){return}if(increment>1){this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}}while(increment>1){this.macroblockAddress++;this.mbRow=this.macroblockAddress/this.mbWidth|0;this.mbCol=this.macroblockAddress%this.mbWidth;this.copyMacroblock(this.motionFwH,this.motionFwV,this.forwardY,this.forwardCr,this.forwardCb);increment--}this.macroblockAddress++}this.mbRow=this.macroblockAddress/this.mbWidth|0;this.mbCol=this.macroblockAddress%this.mbWidth;var mbTable=MPEG1.MACROBLOCK_TYPE[this.pictureType];this.macroblockType=this.readHuffman(mbTable);this.macroblockIntra=this.macroblockType&1;this.macroblockMotFw=this.macroblockType&8;if((this.macroblockType&16)!==0){this.quantizerScale=this.bits.read(5)}if(this.macroblockIntra){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}else{this.dcPredictorY=128;this.dcPredictorCr=128;this.dcPredictorCb=128;this.decodeMotionVectors();this.copyMacroblock(this.motionFwH,this.motionFwV,this.forwardY,this.forwardCr,this.forwardCb)}var cbp=(this.macroblockType&2)!==0?this.readHuffman(MPEG1.CODE_BLOCK_PATTERN):this.macroblockIntra?63:0;for(var block=0,mask=32;block<6;block++){if((cbp&mask)!==0){this.decodeBlock(block)}mask>>=1}};MPEG1.prototype.decodeMotionVectors=function(){var code,d,r=0;if(this.macroblockMotFw){code=this.readHuffman(MPEG1.MOTION);if(code!==0&&this.forwardF!==1){r=this.bits.read(this.forwardRSize);d=(Math.abs(code)-1<(this.forwardF<<4)-1){this.motionFwHPrev-=this.forwardF<<5}else if(this.motionFwHPrev<-this.forwardF<<4){this.motionFwHPrev+=this.forwardF<<5}this.motionFwH=this.motionFwHPrev;if(this.fullPelForward){this.motionFwH<<=1}code=this.readHuffman(MPEG1.MOTION);if(code!==0&&this.forwardF!==1){r=this.bits.read(this.forwardRSize);d=(Math.abs(code)-1<(this.forwardF<<4)-1){this.motionFwVPrev-=this.forwardF<<5}else if(this.motionFwVPrev<-this.forwardF<<4){this.motionFwVPrev+=this.forwardF<<5}this.motionFwV=this.motionFwVPrev;if(this.fullPelForward){this.motionFwV<<=1}}else if(this.pictureType===MPEG1.PICTURE_TYPE.PREDICTIVE){this.motionFwH=this.motionFwHPrev=0;this.motionFwV=this.motionFwVPrev=0}}; +MPEG1.prototype.copyMacroblock=function(motionH,motionV,sY,sCr,sCb){var width,scan,H,V,oddH,oddV,src,dest,last;var dY=this.currentY32,dCb=this.currentCb32,dCr=this.currentCr32;width=this.codedWidth;scan=width-16;H=motionH>>1;V=motionV>>1;oddH=(motionH&1)===1;oddV=(motionV&1)===1;src=((this.mbRow<<4)+V)*width+(this.mbCol<<4)+H;dest=this.mbRow*width+this.mbCol<<2;last=dest+(width<<2);var x,y1,y2,y;if(oddH){if(oddV){while(dest>2&255;y1=sY[src]+sY[src+width];src++;y|=y1+y2+2<<6&65280;y2=sY[src]+sY[src+width];src++;y|=y1+y2+2<<14&16711680;y1=sY[src]+sY[src+width];src++;y|=y1+y2+2<<22&4278190080;dY[dest++]=y}dest+=scan>>2;src+=scan-1}}else{while(dest>1&255;y1=sY[src++];y|=y1+y2+1<<7&65280;y2=sY[src++];y|=y1+y2+1<<15&16711680;y1=sY[src++];y|=y1+y2+1<<23&4278190080;dY[dest++]=y}dest+=scan>>2;src+=scan-1}}}else{if(oddV){while(dest>1&255;src++;y|=sY[src]+sY[src+width]+1<<7&65280;src++;y|=sY[src]+sY[src+width]+1<<15&16711680;src++;y|=sY[src]+sY[src+width]+1<<23&4278190080;src++;dY[dest++]=y}dest+=scan>>2;src+=scan}}else{while(dest>2;src+=scan}}}width=this.halfWidth;scan=width-8;H=motionH/2>>1;V=motionV/2>>1;oddH=(motionH/2&1)===1;oddV=(motionV/2&1)===1;src=((this.mbRow<<3)+V)*width+(this.mbCol<<3)+H;dest=this.mbRow*width+this.mbCol<<1;last=dest+(width<<1);var cr1,cr2,cr,cb1,cb2,cb;if(oddH){if(oddV){while(dest>2&255;cb=cb1+cb2+2>>2&255;cr1=sCr[src]+sCr[src+width];cb1=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<6&65280;cb|=cb1+cb2+2<<6&65280;cr2=sCr[src]+sCr[src+width];cb2=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<14&16711680;cb|=cb1+cb2+2<<14&16711680;cr1=sCr[src]+sCr[src+width];cb1=sCb[src]+sCb[src+width];src++;cr|=cr1+cr2+2<<22&4278190080;cb|=cb1+cb2+2<<22&4278190080;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan-1}}else{while(dest>1&255;cb=cb1+cb2+1>>1&255;cr1=sCr[src];cb1=sCb[src++];cr|=cr1+cr2+1<<7&65280;cb|=cb1+cb2+1<<7&65280;cr2=sCr[src];cb2=sCb[src++];cr|=cr1+cr2+1<<15&16711680;cb|=cb1+cb2+1<<15&16711680;cr1=sCr[src];cb1=sCb[src++];cr|=cr1+cr2+1<<23&4278190080;cb|=cb1+cb2+1<<23&4278190080;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan-1}}}else{if(oddV){while(dest>1&255;cb=sCb[src]+sCb[src+width]+1>>1&255;src++;cr|=sCr[src]+sCr[src+width]+1<<7&65280;cb|=sCb[src]+sCb[src+width]+1<<7&65280;src++;cr|=sCr[src]+sCr[src+width]+1<<15&16711680;cb|=sCb[src]+sCb[src+width]+1<<15&16711680;src++;cr|=sCr[src]+sCr[src+width]+1<<23&4278190080;cb|=sCb[src]+sCb[src+width]+1<<23&4278190080;src++;dCr[dest]=cr;dCb[dest]=cb;dest++}dest+=scan>>2;src+=scan}}else{while(dest>2;src+=scan}}}};MPEG1.prototype.dcPredictorY=0;MPEG1.prototype.dcPredictorCr=0;MPEG1.prototype.dcPredictorCb=0;MPEG1.prototype.blockData=null;MPEG1.prototype.decodeBlock=function(block){var n=0,quantMatrix;if(this.macroblockIntra){var predictor,dctSize;if(block<4){predictor=this.dcPredictorY;dctSize=this.readHuffman(MPEG1.DCT_DC_SIZE_LUMINANCE)}else{predictor=block===4?this.dcPredictorCr:this.dcPredictorCb;dctSize=this.readHuffman(MPEG1.DCT_DC_SIZE_CHROMINANCE)}if(dctSize>0){var differential=this.bits.read(dctSize);if((differential&1<0&&this.bits.read(1)===0){break}if(coeff===65535){run=this.bits.read(6);level=this.bits.read(8);if(level===0){level=this.bits.read(8)}else if(level===128){level=this.bits.read(8)-256}else if(level>128){level=level-256}}else{run=coeff>>8;level=coeff&255;if(this.bits.read(1)){level=-level}}n+=run;var dezigZagged=MPEG1.ZIG_ZAG[n];n++;level<<=1;if(!this.macroblockIntra){level+=level<0?-1:1}level=level*this.quantizerScale*quantMatrix[dezigZagged]>>4;if((level&1)===0){level-=level>0?1:-1}if(level>2047){level=2047}else if(level<-2048){level=-2048}this.blockData[dezigZagged]=level*MPEG1.PREMULTIPLIER_MATRIX[dezigZagged]}var destArray,destIndex,scan;if(block<4){destArray=this.currentY;scan=this.codedWidth-8;destIndex=this.mbRow*this.codedWidth+this.mbCol<<4;if((block&1)!==0){destIndex+=8}if((block&2)!==0){destIndex+=this.codedWidth<<3}}else{destArray=block===4?this.currentCb:this.currentCr;scan=(this.codedWidth>>1)-8;destIndex=(this.mbRow*this.codedWidth<<2)+(this.mbCol<<3)}if(this.macroblockIntra){if(n===1){MPEG1.CopyValueToDestination(this.blockData[0]+128>>8,destArray,destIndex,scan);this.blockData[0]=0}else{MPEG1.IDCT(this.blockData);MPEG1.CopyBlockToDestination(this.blockData,destArray,destIndex,scan);JSMpeg.Fill(this.blockData,0)}}else{if(n===1){MPEG1.AddValueToDestination(this.blockData[0]+128>>8,destArray,destIndex,scan);this.blockData[0]=0}else{MPEG1.IDCT(this.blockData);MPEG1.AddBlockToDestination(this.blockData,destArray,destIndex,scan);JSMpeg.Fill(this.blockData,0)}}n=0};MPEG1.CopyBlockToDestination=function(block,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]=block[n+0];dest[index+1]=block[n+1];dest[index+2]=block[n+2];dest[index+3]=block[n+3];dest[index+4]=block[n+4];dest[index+5]=block[n+5];dest[index+6]=block[n+6];dest[index+7]=block[n+7]}};MPEG1.AddBlockToDestination=function(block,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]+=block[n+0];dest[index+1]+=block[n+1];dest[index+2]+=block[n+2];dest[index+3]+=block[n+3];dest[index+4]+=block[n+4];dest[index+5]+=block[n+5];dest[index+6]+=block[n+6];dest[index+7]+=block[n+7]}};MPEG1.CopyValueToDestination=function(value,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]=value;dest[index+1]=value;dest[index+2]=value;dest[index+3]=value;dest[index+4]=value;dest[index+5]=value;dest[index+6]=value;dest[index+7]=value}};MPEG1.AddValueToDestination=function(value,dest,index,scan){for(var n=0;n<64;n+=8,index+=scan+8){dest[index+0]+=value;dest[index+1]+=value;dest[index+2]+=value;dest[index+3]+=value;dest[index+4]+=value;dest[index+5]+=value;dest[index+6]+=value;dest[index+7]+=value}};MPEG1.IDCT=function(block){var b1,b3,b4,b6,b7,tmp1,tmp2,m0,x0,x1,x2,x3,x4,y3,y4,y5,y6,y7;for(var i=0;i<8;++i){b1=block[4*8+i];b3=block[2*8+i]+block[6*8+i];b4=block[5*8+i]-block[3*8+i];tmp1=block[1*8+i]+block[7*8+i];tmp2=block[3*8+i]+block[5*8+i];b6=block[1*8+i]-block[7*8+i];b7=tmp1+tmp2;m0=block[0*8+i];x4=(b6*473-b4*196+128>>8)-b7;x0=x4-((tmp1-tmp2)*362+128>>8);x1=m0-b1;x2=((block[2*8+i]-block[6*8+i])*362+128>>8)-b3;x3=m0+b1;y3=x1+x2;y4=x3+b3;y5=x1-x2;y6=x3-b3;y7=-x0-(b4*473+b6*196+128>>8);block[0*8+i]=b7+y4;block[1*8+i]=x4+y3;block[2*8+i]=y5-x0;block[3*8+i]=y6-y7;block[4*8+i]=y6+y7;block[5*8+i]=x0+y5;block[6*8+i]=y3-x4;block[7*8+i]=y4-b7}for(var i=0;i<64;i+=8){b1=block[4+i];b3=block[2+i]+block[6+i];b4=block[5+i]-block[3+i];tmp1=block[1+i]+block[7+i];tmp2=block[3+i]+block[5+i];b6=block[1+i]-block[7+i];b7=tmp1+tmp2;m0=block[0+i];x4=(b6*473-b4*196+128>>8)-b7;x0=x4-((tmp1-tmp2)*362+128>>8);x1=m0-b1;x2=((block[2+i]-block[6+i])*362+128>>8)-b3;x3=m0+b1;y3=x1+x2;y4=x3+b3;y5=x1-x2;y6=x3-b3;y7=-x0-(b4*473+b6*196+128>>8);block[0+i]=b7+y4+128>>8;block[1+i]=x4+y3+128>>8;block[2+i]=y5-x0+128>>8;block[3+i]=y6-y7+128>>8;block[4+i]=y6+y7+128>>8;block[5+i]=x0+y5+128>>8;block[6+i]=y3-x4+128>>8;block[7+i]=y4-b7+128>>8}};MPEG1.PICTURE_RATE=[0,23.976,24,25,29.97,30,50,59.94,60,0,0,0,0,0,0,0];MPEG1.ZIG_ZAG=new Uint8Array([0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63]);MPEG1.DEFAULT_INTRA_QUANT_MATRIX=new Uint8Array([8,16,19,22,26,27,29,34,16,16,22,24,27,29,34,37,19,22,26,27,29,34,34,38,22,22,26,27,29,34,37,40,22,26,27,29,32,35,40,48,26,27,29,32,35,40,48,58,26,27,29,34,38,46,56,69,27,29,35,38,46,56,69,83]);MPEG1.DEFAULT_NON_INTRA_QUANT_MATRIX=new Uint8Array([16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]);MPEG1.PREMULTIPLIER_MATRIX=new Uint8Array([32,44,42,38,32,25,17,9,44,62,58,52,44,35,24,12,42,58,55,49,42,33,23,12,38,52,49,44,38,30,20,10,32,44,42,38,32,25,17,9,25,35,33,30,25,20,14,7,17,24,23,20,17,14,9,5,9,12,12,10,9,7,5,2]);MPEG1.MACROBLOCK_ADDRESS_INCREMENT=new Int16Array([1*3,2*3,0,3*3,4*3,0,0,0,1,5*3,6*3,0,7*3,8*3,0,9*3,10*3,0,11*3,12*3,0,0,0,3,0,0,2,13*3,14*3,0,15*3,16*3,0,0,0,5,0,0,4,17*3,18*3,0,19*3,20*3,0,0,0,7,0,0,6,21*3,22*3,0,23*3,24*3,0,25*3,26*3,0,27*3,28*3,0,-1,29*3,0,-1,30*3,0,31*3,32*3,0,33*3,34*3,0,35*3,36*3,0,37*3,38*3,0,0,0,9,0,0,8,39*3,40*3,0,41*3,42*3,0,43*3,44*3,0,45*3,46*3,0,0,0,15,0,0,14,0,0,13,0,0,12,0,0,11,0,0,10,47*3,-1,0,-1,48*3,0,49*3,50*3,0,51*3,52*3,0,53*3,54*3,0,55*3,56*3,0,57*3,58*3,0,59*3,60*3,0,61*3,-1,0,-1,62*3,0,63*3,64*3,0,65*3,66*3,0,67*3,68*3,0,69*3,70*3,0,71*3,72*3,0,73*3,74*3,0,0,0,21,0,0,20,0,0,19,0,0,18,0,0,17,0,0,16,0,0,35,0,0,34,0,0,33,0,0,32,0,0,31,0,0,30,0,0,29,0,0,28,0,0,27,0,0,26,0,0,25,0,0,24,0,0,23,0,0,22]);MPEG1.MACROBLOCK_TYPE_INTRA=new Int8Array([1*3,2*3,0,-1,3*3,0,0,0,1,0,0,17]);MPEG1.MACROBLOCK_TYPE_PREDICTIVE=new Int8Array([1*3,2*3,0,3*3,4*3,0,0,0,10,5*3,6*3,0,0,0,2,7*3,8*3,0,0,0,8,9*3,10*3,0,11*3,12*3,0,-1,13*3,0,0,0,18,0,0,26,0,0,1,0,0,17]);MPEG1.MACROBLOCK_TYPE_B=new Int8Array([1*3,2*3,0,3*3,5*3,0,4*3,6*3,0,8*3,7*3,0,0,0,12,9*3,10*3,0,0,0,14,13*3,14*3,0,12*3,11*3,0,0,0,4,0,0,6,18*3,16*3,0,15*3,17*3,0,0,0,8,0,0,10,-1,19*3,0,0,0,1,20*3,21*3,0,0,0,30,0,0,17,0,0,22,0,0,26]);MPEG1.MACROBLOCK_TYPE=[null,MPEG1.MACROBLOCK_TYPE_INTRA,MPEG1.MACROBLOCK_TYPE_PREDICTIVE,MPEG1.MACROBLOCK_TYPE_B];MPEG1.CODE_BLOCK_PATTERN=new Int16Array([2*3,1*3,0,3*3,6*3,0,4*3,5*3,0,8*3,11*3,0,12*3,13*3,0,9*3,7*3,0,10*3,14*3,0,20*3,19*3,0,18*3,16*3,0,23*3,17*3,0,27*3,25*3,0,21*3,28*3,0,15*3,22*3,0,24*3,26*3,0,0,0,60,35*3,40*3,0,44*3,48*3,0,38*3,36*3,0,42*3,47*3,0,29*3,31*3,0,39*3,32*3,0,0,0,32,45*3,46*3,0,33*3,41*3,0,43*3,34*3,0,0,0,4,30*3,37*3,0,0,0,8,0,0,16,0,0,44,50*3,56*3,0,0,0,28,0,0,52,0,0,62,61*3,59*3,0,52*3,60*3,0,0,0,1,55*3,54*3,0,0,0,61,0,0,56,57*3,58*3,0,0,0,2,0,0,40,51*3,62*3,0,0,0,48,64*3,63*3,0,49*3,53*3,0,0,0,20,0,0,12,80*3,83*3,0,0,0,63,77*3,75*3,0,65*3,73*3,0,84*3,66*3,0,0,0,24,0,0,36,0,0,3,69*3,87*3,0,81*3,79*3,0,68*3,71*3,0,70*3,78*3,0,67*3,76*3,0,72*3,74*3,0,86*3,85*3,0,88*3,82*3,0,-1,94*3,0,95*3,97*3,0,0,0,33,0,0,9,106*3,110*3,0,102*3,116*3,0,0,0,5,0,0,10,93*3,89*3,0,0,0,6,0,0,18,0,0,17,0,0,34,113*3,119*3,0,103*3,104*3,0,90*3,92*3,0,109*3,107*3,0,117*3,118*3,0,101*3,99*3,0,98*3,96*3,0,100*3,91*3,0,114*3,115*3,0,105*3,108*3,0,112*3,111*3,0,121*3,125*3,0,0,0,41,0,0,14,0,0,21,124*3,122*3,0,120*3,123*3,0,0,0,11,0,0,19,0,0,7,0,0,35,0,0,13,0,0,50,0,0,49,0,0,58,0,0,37,0,0,25,0,0,45,0,0,57,0,0,26,0,0,29,0,0,38,0,0,53,0,0,23,0,0,43,0,0,46,0,0,42,0,0,22,0,0,54,0,0,51,0,0,15,0,0,30,0,0,39,0,0,47,0,0,55,0,0,27,0,0,59,0,0,31]);MPEG1.MOTION=new Int16Array([1*3,2*3,0,4*3,3*3,0,0,0,0,6*3,5*3,0,8*3,7*3,0,0,0,-1,0,0,1,9*3,10*3,0,12*3,11*3,0,0,0,2,0,0,-2,14*3,15*3,0,16*3,13*3,0,20*3,18*3,0,0,0,3,0,0,-3,17*3,19*3,0,-1,23*3,0,27*3,25*3,0,26*3,21*3,0,24*3,22*3,0,32*3,28*3,0,29*3,31*3,0,-1,33*3,0,36*3,35*3,0,0,0,-4,30*3,34*3,0,0,0,4,0,0,-7,0,0,5,37*3,41*3,0,0,0,-5,0,0,7,38*3,40*3,0,42*3,39*3,0,0,0,-6,0,0,6,51*3,54*3,0,50*3,49*3,0,45*3,46*3,0,52*3,47*3,0,43*3,53*3,0,44*3,48*3,0,0,0,10,0,0,9,0,0,8,0,0,-8,57*3,66*3,0,0,0,-9,60*3,64*3,0,56*3,61*3,0,55*3,62*3,0,58*3,63*3,0,0,0,-10,59*3,65*3,0,0,0,12,0,0,16,0,0,13,0,0,14,0,0,11,0,0,15,0,0,-16,0,0,-12,0,0,-14,0,0,-15,0,0,-11,0,0,-13]);MPEG1.DCT_DC_SIZE_LUMINANCE=new Int8Array([2*3,1*3,0,6*3,5*3,0,3*3,4*3,0,0,0,1,0,0,2,9*3,8*3,0,7*3,10*3,0,0,0,0,12*3,11*3,0,0,0,4,0,0,3,13*3,14*3,0,0,0,5,0,0,6,16*3,15*3,0,17*3,-1,0,0,0,7,0,0,8]);MPEG1.DCT_DC_SIZE_CHROMINANCE=new Int8Array([2*3,1*3,0,4*3,3*3,0,6*3,5*3,0,8*3,7*3,0,0,0,2,0,0,1,0,0,0,10*3,9*3,0,0,0,3,12*3,11*3,0,0,0,4,14*3,13*3,0,0,0,5,16*3,15*3,0,0,0,6,17*3,-1,0,0,0,7,0,0,8]);MPEG1.DCT_COEFF=new Int32Array([1*3,2*3,0,4*3,3*3,0,0,0,1,7*3,8*3,0,6*3,5*3,0,13*3,9*3,0,11*3,10*3,0,14*3,12*3,0,0,0,257,20*3,22*3,0,18*3,21*3,0,16*3,19*3,0,0,0,513,17*3,15*3,0,0,0,2,0,0,3,27*3,25*3,0,29*3,31*3,0,24*3,26*3,0,32*3,30*3,0,0,0,1025,23*3,28*3,0,0,0,769,0,0,258,0,0,1793,0,0,65535,0,0,1537,37*3,36*3,0,0,0,1281,35*3,34*3,0,39*3,38*3,0,33*3,42*3,0,40*3,41*3,0,52*3,50*3,0,54*3,53*3,0,48*3,49*3,0,43*3,45*3,0,46*3,44*3,0,0,0,2049,0,0,4,0,0,514,0,0,2305,51*3,47*3,0,55*3,57*3,0,60*3,56*3,0,59*3,58*3,0,61*3,62*3,0,0,0,2561,0,0,3329,0,0,6,0,0,259,0,0,5,0,0,770,0,0,2817,0,0,3073,76*3,75*3,0,67*3,70*3,0,73*3,71*3,0,78*3,74*3,0,72*3,77*3,0,69*3,64*3,0,68*3,63*3,0,66*3,65*3,0,81*3,87*3,0,91*3,80*3,0,82*3,79*3,0,83*3,86*3,0,93*3,92*3,0,84*3,85*3,0,90*3,94*3,0,88*3,89*3,0,0,0,515,0,0,260,0,0,7,0,0,1026,0,0,1282,0,0,4097,0,0,3841,0,0,3585,105*3,107*3,0,111*3,114*3,0,104*3,97*3,0,125*3,119*3,0,96*3,98*3,0,-1,123*3,0,95*3,101*3,0,106*3,121*3,0,99*3,102*3,0,113*3,103*3,0,112*3,116*3,0,110*3,100*3,0,124*3,115*3,0,117*3,122*3,0,109*3,118*3,0,120*3,108*3,0,127*3,136*3,0,139*3,140*3,0,130*3,126*3,0,145*3,146*3,0,128*3,129*3,0,0,0,2050,132*3,134*3,0,155*3,154*3,0,0,0,8,137*3,133*3,0,143*3,144*3,0,151*3,138*3,0,142*3,141*3,0,0,0,10,0,0,9,0,0,11,0,0,5377,0,0,1538,0,0,771,0,0,5121,0,0,1794,0,0,4353,0,0,4609,0,0,4865,148*3,152*3,0,0,0,1027,153*3,150*3,0,0,0,261,131*3,135*3,0,0,0,516,149*3,147*3,0,172*3,173*3,0,162*3,158*3,0,170*3,161*3,0,168*3,166*3,0,157*3,179*3,0,169*3,167*3,0,174*3,171*3,0,178*3,177*3,0,156*3,159*3,0,164*3,165*3,0,183*3,182*3,0,175*3,176*3,0,0,0,263,0,0,2562,0,0,2306,0,0,5633,0,0,5889,0,0,6401,0,0,6145,0,0,1283,0,0,772,0,0,13,0,0,12,0,0,14,0,0,15,0,0,517,0,0,6657,0,0,262,180*3,181*3,0,160*3,163*3,0,196*3,199*3,0,0,0,27,203*3,185*3,0,202*3,201*3,0,0,0,19,0,0,22,197*3,207*3,0,0,0,18,191*3,192*3,0,188*3,190*3,0,0,0,20,184*3,194*3,0,0,0,21,186*3,193*3,0,0,0,23,204*3,198*3,0,0,0,25,0,0,24,200*3,205*3,0,0,0,31,0,0,30,0,0,28,0,0,29,0,0,26,0,0,17,0,0,16,189*3,206*3,0,187*3,195*3,0,218*3,211*3,0,0,0,37,215*3,216*3,0,0,0,36,210*3,212*3,0,0,0,34,213*3,209*3,0,221*3,222*3,0,219*3,208*3,0,217*3,214*3,0,223*3,220*3,0,0,0,35,0,0,267,0,0,40,0,0,268,0,0,266,0,0,32,0,0,264,0,0,265,0,0,38,0,0,269,0,0,270,0,0,33,0,0,39,0,0,7937,0,0,6913,0,0,7681,0,0,4098,0,0,7425,0,0,7169,0,0,271,0,0,274,0,0,273,0,0,272,0,0,1539,0,0,2818,0,0,3586,0,0,3330,0,0,3074,0,0,3842]);MPEG1.PICTURE_TYPE={INTRA:1,PREDICTIVE:2,B:3};MPEG1.START={SEQUENCE:179,SLICE_FIRST:1,SLICE_LAST:175,PICTURE:0,EXTENSION:181,USER_DATA:178};return MPEG1}();JSMpeg.Decoder.MPEG1VideoWASM=function(){"use strict";var MPEG1WASM=function(options){JSMpeg.Decoder.Base.call(this,options);this.module=options.wasmModule;this.bufferSize=options.videoBufferSize||512*1024;this.bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.decodeFirstFrame=options.decodeFirstFrame!==false;this.hasSequenceHeader=false};MPEG1WASM.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MPEG1WASM.prototype.constructor=MPEG1WASM;MPEG1WASM.prototype.initializeWasmDecoder=function(){if(!this.module.instance){console.warn("JSMpeg: WASM module not compiled yet");return}this.instance=this.module.instance;this.functions=this.module.instance.exports;this.decoder=this.functions._mpeg1_decoder_create(this.bufferSize,this.bufferMode)};MPEG1WASM.prototype.destroy=function(){this.functions._mpeg1_decoder_destroy(this.decoder)};MPEG1WASM.prototype.bufferGetIndex=function(){return this.functions._mpeg1_decoder_get_index(this.decoder)};MPEG1WASM.prototype.bufferSetIndex=function(index){this.functions._mpeg1_decoder_set_index(this.decoder,index)};MPEG1WASM.prototype.bufferWrite=function(buffers){if(!this.decoder){this.initializeWasmDecoder()}var totalLength=0;for(var i=0;i>2));var dcb=this.instance.heapU8.subarray(ptrCb,ptrCb+(this.codedSize>>2));this.destination.render(dy,dcr,dcb,false)}this.advanceDecodedTime(1/this.frameRate);return true};return MPEG1WASM}();JSMpeg.Decoder.MP2Audio=function(){"use strict";var MP2=function(options){JSMpeg.Decoder.Base.call(this,options);var bufferSize=options.audioBufferSize||128*1024;var bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.bits=new JSMpeg.BitBuffer(bufferSize,bufferMode);this.left=new Float32Array(1152);this.right=new Float32Array(1152);this.sampleRate=44100;this.D=new Float32Array(1024);this.D.set(MP2.SYNTHESIS_WINDOW,0);this.D.set(MP2.SYNTHESIS_WINDOW,512);this.V=new Float32Array(1024);this.U=new Int32Array(32);this.VPos=0;this.allocation=[new Array(32),new Array(32)];this.scaleFactorInfo=[new Uint8Array(32),new Uint8Array(32)];this.scaleFactor=[new Array(32),new Array(32)];this.sample=[new Array(32),new Array(32)];for(var j=0;j<2;j++){for(var i=0;i<32;i++){this.scaleFactor[j][i]=[0,0,0];this.sample[j][i]=[0,0,0]}}};MP2.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MP2.prototype.constructor=MP2;MP2.prototype.decode=function(){var pos=this.bits.index>>3;if(pos>=this.bits.byteLength){return false}var decoded=this.decodeFrame(this.left,this.right);this.bits.index=pos+decoded<<3;if(!decoded){return false}if(this.destination){this.destination.play(this.sampleRate,this.left,this.right)}this.advanceDecodedTime(this.left.length/this.sampleRate);return true};MP2.prototype.getCurrentTime=function(){var enqueuedTime=this.destination?this.destination.enqueuedTime:0;return this.decodedTime-enqueuedTime};MP2.prototype.decodeFrame=function(left,right){var sync=this.bits.read(11),version=this.bits.read(2),layer=this.bits.read(2),hasCRC=!this.bits.read(1);if(sync!==MP2.FRAME_SYNC||version!==MP2.VERSION.MPEG_1||layer!==MP2.LAYER.II){return 0}var bitrateIndex=this.bits.read(4)-1;if(bitrateIndex>13){return 0}var sampleRateIndex=this.bits.read(2);var sampleRate=MP2.SAMPLE_RATE[sampleRateIndex];if(sampleRateIndex===3){return 0}if(version===MP2.VERSION.MPEG_2){sampleRateIndex+=4;bitrateIndex+=14}var padding=this.bits.read(1),privat=this.bits.read(1),mode=this.bits.read(2);var bound=0;if(mode===MP2.MODE.JOINT_STEREO){bound=this.bits.read(2)+1<<2}else{this.bits.skip(2);bound=mode===MP2.MODE.MONO?0:32}this.bits.skip(4);if(hasCRC){this.bits.skip(16)}var bitrate=MP2.BIT_RATE[bitrateIndex],sampleRate=MP2.SAMPLE_RATE[sampleRateIndex],frameSize=144e3*bitrate/sampleRate+padding|0;var tab3=0;var sblimit=0;if(version===MP2.VERSION.MPEG_2){tab3=2;sblimit=30}else{var tab1=mode===MP2.MODE.MONO?0:1;var tab2=MP2.QUANT_LUT_STEP_1[tab1][bitrateIndex];tab3=MP2.QUANT_LUT_STEP_2[tab2][sampleRateIndex];sblimit=tab3&63;tab3>>=6}if(bound>sblimit){bound=sblimit}for(var sb=0;sb>1);var vIndex=this.VPos%128>>1;while(vIndex<1024){for(var i=0;i<32;++i){this.U[i]+=this.D[dIndex++]*this.V[vIndex++]}vIndex+=128-32;dIndex+=64-32}vIndex=128-32+1024-vIndex;dIndex-=512-32;while(vIndex<1024){for(var i=0;i<32;++i){this.U[i]+=this.D[dIndex++]*this.V[vIndex++]}vIndex+=128-32;dIndex+=64-32}var outChannel=ch===0?left:right;for(var j=0;j<32;j++){outChannel[outPos+j]=this.U[j]/2147418112}}outPos+=32}}}this.sampleRate=sampleRate;return frameSize};MP2.prototype.readAllocation=function(sb,tab3){var tab4=MP2.QUANT_LUT_STEP_3[tab3][sb];var qtab=MP2.QUANT_LUT_STEP4[tab4&15][this.bits.read(tab4>>4)];return qtab?MP2.QUANT_TAB[qtab-1]:0};MP2.prototype.readSamples=function(ch,sb,part){var q=this.allocation[ch][sb],sf=this.scaleFactor[ch][sb][part],sample=this.sample[ch][sb],val=0;if(!q){sample[0]=sample[1]=sample[2]=0;return}if(sf===63){sf=0}else{var shift=sf/3|0;sf=MP2.SCALEFACTOR_BASE[sf%3]+(1<>1)>>shift}var adj=q.levels;if(q.group){val=this.bits.read(q.bits);sample[0]=val%adj;val=val/adj|0;sample[1]=val%adj;sample[2]=val/adj|0}else{sample[0]=this.bits.read(q.bits);sample[1]=this.bits.read(q.bits);sample[2]=this.bits.read(q.bits)}var scale=65536/(adj+1)|0;adj=(adj+1>>1)-1;val=(adj-sample[0])*scale;sample[0]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12;val=(adj-sample[1])*scale;sample[1]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12;val=(adj-sample[2])*scale;sample[2]=val*(sf>>12)+(val*(sf&4095)+2048>>12)>>12};MP2.MatrixTransform=function(s,ss,d,dp){var t01,t02,t03,t04,t05,t06,t07,t08,t09,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33;t01=s[0][ss]+s[31][ss];t02=(s[0][ss]-s[31][ss])*.500602998235;t03=s[1][ss]+s[30][ss];t04=(s[1][ss]-s[30][ss])*.505470959898;t05=s[2][ss]+s[29][ss];t06=(s[2][ss]-s[29][ss])*.515447309923;t07=s[3][ss]+s[28][ss];t08=(s[3][ss]-s[28][ss])*.53104259109;t09=s[4][ss]+s[27][ss];t10=(s[4][ss]-s[27][ss])*.553103896034;t11=s[5][ss]+s[26][ss];t12=(s[5][ss]-s[26][ss])*.582934968206;t13=s[6][ss]+s[25][ss];t14=(s[6][ss]-s[25][ss])*.622504123036;t15=s[7][ss]+s[24][ss];t16=(s[7][ss]-s[24][ss])*.674808341455;t17=s[8][ss]+s[23][ss];t18=(s[8][ss]-s[23][ss])*.744536271002;t19=s[9][ss]+s[22][ss];t20=(s[9][ss]-s[22][ss])*.839349645416;t21=s[10][ss]+s[21][ss];t22=(s[10][ss]-s[21][ss])*.972568237862;t23=s[11][ss]+s[20][ss];t24=(s[11][ss]-s[20][ss])*1.16943993343;t25=s[12][ss]+s[19][ss];t26=(s[12][ss]-s[19][ss])*1.48416461631;t27=s[13][ss]+s[18][ss];t28=(s[13][ss]-s[18][ss])*2.05778100995;t29=s[14][ss]+s[17][ss];t30=(s[14][ss]-s[17][ss])*3.40760841847;t31=s[15][ss]+s[16][ss];t32=(s[15][ss]-s[16][ss])*10.1900081235;t33=t01+t31;t31=(t01-t31)*.502419286188;t01=t03+t29;t29=(t03-t29)*.52249861494;t03=t05+t27;t27=(t05-t27)*.566944034816;t05=t07+t25;t25=(t07-t25)*.64682178336;t07=t09+t23;t23=(t09-t23)*.788154623451;t09=t11+t21;t21=(t11-t21)*1.06067768599;t11=t13+t19;t19=(t13-t19)*1.72244709824;t13=t15+t17;t17=(t15-t17)*5.10114861869;t15=t33+t13;t13=(t33-t13)*.509795579104;t33=t01+t11;t01=(t01-t11)*.601344886935;t11=t03+t09;t09=(t03-t09)*.899976223136;t03=t05+t07;t07=(t05-t07)*2.56291544774;t05=t15+t03;t15=(t15-t03)*.541196100146;t03=t33+t11;t11=(t33-t11)*1.30656296488;t33=t05+t03;t05=(t05-t03)*.707106781187;t03=t15+t11;t15=(t15-t11)*.707106781187;t03+=t15;t11=t13+t07;t13=(t13-t07)*.541196100146;t07=t01+t09;t09=(t01-t09)*1.30656296488;t01=t11+t07;t07=(t11-t07)*.707106781187;t11=t13+t09;t13=(t13-t09)*.707106781187;t11+=t13;t01+=t11;t11+=t07;t07+=t13;t09=t31+t17;t31=(t31-t17)*.509795579104;t17=t29+t19;t29=(t29-t19)*.601344886935;t19=t27+t21;t21=(t27-t21)*.899976223136;t27=t25+t23;t23=(t25-t23)*2.56291544774;t25=t09+t27;t09=(t09-t27)*.541196100146;t27=t17+t19;t19=(t17-t19)*1.30656296488;t17=t25+t27;t27=(t25-t27)*.707106781187;t25=t09+t19;t19=(t09-t19)*.707106781187;t25+=t19;t09=t31+t23;t31=(t31-t23)*.541196100146;t23=t29+t21;t21=(t29-t21)*1.30656296488;t29=t09+t23;t23=(t09-t23)*.707106781187;t09=t31+t21;t31=(t31-t21)*.707106781187;t09+=t31;t29+=t09;t09+=t23;t23+=t31;t17+=t29;t29+=t25;t25+=t09;t09+=t27;t27+=t23;t23+=t19;t19+=t31;t21=t02+t32;t02=(t02-t32)*.502419286188;t32=t04+t30;t04=(t04-t30)*.52249861494;t30=t06+t28;t28=(t06-t28)*.566944034816;t06=t08+t26;t08=(t08-t26)*.64682178336;t26=t10+t24;t10=(t10-t24)*.788154623451;t24=t12+t22;t22=(t12-t22)*1.06067768599;t12=t14+t20;t20=(t14-t20)*1.72244709824;t14=t16+t18;t16=(t16-t18)*5.10114861869;t18=t21+t14;t14=(t21-t14)*.509795579104;t21=t32+t12;t32=(t32-t12)*.601344886935;t12=t30+t24;t24=(t30-t24)*.899976223136;t30=t06+t26;t26=(t06-t26)*2.56291544774;t06=t18+t30;t18=(t18-t30)*.541196100146;t30=t21+t12;t12=(t21-t12)*1.30656296488;t21=t06+t30;t30=(t06-t30)*.707106781187;t06=t18+t12;t12=(t18-t12)*.707106781187;t06+=t12;t18=t14+t26;t26=(t14-t26)*.541196100146;t14=t32+t24;t24=(t32-t24)*1.30656296488;t32=t18+t14;t14=(t18-t14)*.707106781187;t18=t26+t24;t24=(t26-t24)*.707106781187;t18+=t24;t32+=t18;t18+=t14;t26=t14+t24;t14=t02+t16;t02=(t02-t16)*.509795579104;t16=t04+t20;t04=(t04-t20)*.601344886935;t20=t28+t22;t22=(t28-t22)*.899976223136;t28=t08+t10;t10=(t08-t10)*2.56291544774;t08=t14+t28;t14=(t14-t28)*.541196100146;t28=t16+t20;t20=(t16-t20)*1.30656296488;t16=t08+t28;t28=(t08-t28)*.707106781187;t08=t14+t20;t20=(t14-t20)*.707106781187;t08+=t20;t14=t02+t10;t02=(t02-t10)*.541196100146;t10=t04+t22;t22=(t04-t22)*1.30656296488;t04=t14+t10;t10=(t14-t10)*.707106781187;t14=t02+t22;t02=(t02-t22)*.707106781187;t14+=t02;t04+=t14;t14+=t10;t10+=t02;t16+=t04;t04+=t08;t08+=t14;t14+=t28;t28+=t10;t10+=t20;t20+=t02;t21+=t16;t16+=t32;t32+=t04;t04+=t06;t06+=t08;t08+=t18;t18+=t14;t14+=t30;t30+=t28;t28+=t26;t26+=t10;t10+=t12;t12+=t20;t20+=t24;t24+=t02;d[dp+48]=-t33;d[dp+49]=d[dp+47]=-t21;d[dp+50]=d[dp+46]=-t17;d[dp+51]=d[dp+45]=-t16;d[dp+52]=d[dp+44]=-t01;d[dp+53]=d[dp+43]=-t32;d[dp+54]=d[dp+42]=-t29;d[dp+55]=d[dp+41]=-t04;d[dp+56]=d[dp+40]=-t03;d[dp+57]=d[dp+39]=-t06;d[dp+58]=d[dp+38]=-t25;d[dp+59]=d[dp+37]=-t08;d[dp+60]=d[dp+36]=-t11;d[dp+61]=d[dp+35]=-t18;d[dp+62]=d[dp+34]=-t09;d[dp+63]=d[dp+33]=-t14;d[dp+32]=-t05;d[dp+0]=t05;d[dp+31]=-t30;d[dp+1]=t30;d[dp+30]=-t27;d[dp+2]=t27;d[dp+29]=-t28;d[dp+3]=t28;d[dp+28]=-t07;d[dp+4]=t07;d[dp+27]=-t26;d[dp+5]=t26;d[dp+26]=-t23;d[dp+6]=t23;d[dp+25]=-t10;d[dp+7]=t10;d[dp+24]=-t15;d[dp+8]=t15;d[dp+23]=-t12;d[dp+9]=t12;d[dp+22]=-t19;d[dp+10]=t19;d[dp+21]=-t20;d[dp+11]=t20;d[dp+20]=-t13;d[dp+12]=t13;d[dp+19]=-t24;d[dp+13]=t24;d[dp+18]=-t31;d[dp+14]=t31;d[dp+17]=-t02;d[dp+15]=t02;d[dp+16]=0};MP2.FRAME_SYNC=2047;MP2.VERSION={MPEG_2_5:0,MPEG_2:2,MPEG_1:3};MP2.LAYER={III:1,II:2,I:3};MP2.MODE={STEREO:0,JOINT_STEREO:1,DUAL_CHANNEL:2,MONO:3};MP2.SAMPLE_RATE=new Uint16Array([44100,48e3,32e3,0,22050,24e3,16e3,0]);MP2.BIT_RATE=new Uint16Array([32,48,56,64,80,96,112,128,160,192,224,256,320,384,8,16,24,32,40,48,56,64,80,96,112,128,144,160]);MP2.SCALEFACTOR_BASE=new Uint32Array([33554432,26632170,21137968]);MP2.SYNTHESIS_WINDOW=new Float32Array([0,-.5,-.5,-.5,-.5,-.5,-.5,-1,-1,-1,-1,-1.5,-1.5,-2,-2,-2.5,-2.5,-3,-3.5,-3.5,-4,-4.5,-5,-5.5,-6.5,-7,-8,-8.5,-9.5,-10.5,-12,-13,-14.5,-15.5,-17.5,-19,-20.5,-22.5,-24.5,-26.5,-29,-31.5,-34,-36.5,-39.5,-42.5,-45.5,-48.5,-52,-55.5,-58.5,-62.5,-66,-69.5,-73.5,-77,-80.5,-84.5,-88,-91.5,-95,-98,-101,-104,106.5,109,111,112.5,113.5,114,114,113.5,112,110.5,107.5,104,100,94.5,88.5,81.5,73,63.5,53,41.5,28.5,14.5,-1,-18,-36,-55.5,-76.5,-98.5,-122,-147,-173.5,-200.5,-229.5,-259.5,-290.5,-322.5,-355.5,-389.5,-424,-459.5,-495.5,-532,-568.5,-605,-641.5,-678,-714,-749,-783.5,-817,-849,-879.5,-908.5,-935,-959.5,-981,-1000.5,-1016,-1028.5,-1037.5,-1042.5,-1043.5,-1040,-1031.5,1018.5,1e3,976,946.5,911,869.5,822,767.5,707,640,565.5,485,397,302.5,201,92.5,-22.5,-144,-272.5,-407,-547.5,-694,-846,-1003,-1165,-1331.5,-1502,-1675.5,-1852.5,-2031.5,-2212.5,-2394,-2576.5,-2758.5,-2939.5,-3118.5,-3294.5,-3467.5,-3635.5,-3798.5,-3955,-4104.5,-4245.5,-4377.5,-4499,-4609.5,-4708,-4792.5,-4863.5,-4919,-4958,-4979.5,-4983,-4967.5,-4931.5,-4875,-4796,-4694.5,-4569.5,-4420,-4246,-4046,-3820,-3567,3287,2979.5,2644,2280.5,1888,1467.5,1018.5,541,35,-499,-1061,-1650,-2266.5,-2909,-3577,-4270,-4987.5,-5727.5,-6490,-7274,-8077.5,-8899.5,-9739,-10594.5,-11464.5,-12347,-13241,-14144.5,-15056,-15973.5,-16895.5,-17820,-18744.5,-19668,-20588,-21503,-22410.5,-23308.5,-24195,-25068.5,-25926.5,-26767,-27589,-28389,-29166.5,-29919,-30644.5,-31342,-32009.5,-32645,-33247,-33814.5,-34346,-34839.5,-35295,-35710,-36084.5,-36417.5,-36707.5,-36954,-37156.5,-37315,-37428,-37496,37519,37496,37428,37315,37156.5,36954,36707.5,36417.5,36084.5,35710,35295,34839.5,34346,33814.5,33247,32645,32009.5,31342,30644.5,29919,29166.5,28389,27589,26767,25926.5,25068.5,24195,23308.5,22410.5,21503,20588,19668,18744.5,17820,16895.5,15973.5,15056,14144.5,13241,12347,11464.5,10594.5,9739,8899.5,8077.5,7274,6490,5727.5,4987.5,4270,3577,2909,2266.5,1650,1061,499,-35,-541,-1018.5,-1467.5,-1888,-2280.5,-2644,-2979.5,3287,3567,3820,4046,4246,4420,4569.5,4694.5,4796,4875,4931.5,4967.5,4983,4979.5,4958,4919,4863.5,4792.5,4708,4609.5,4499,4377.5,4245.5,4104.5,3955,3798.5,3635.5,3467.5,3294.5,3118.5,2939.5,2758.5,2576.5,2394,2212.5,2031.5,1852.5,1675.5,1502,1331.5,1165,1003,846,694,547.5,407,272.5,144,22.5,-92.5,-201,-302.5,-397,-485,-565.5,-640,-707,-767.5,-822,-869.5,-911,-946.5,-976,-1e3,1018.5,1031.5,1040,1043.5,1042.5,1037.5,1028.5,1016,1000.5,981,959.5,935,908.5,879.5,849,817,783.5,749,714,678,641.5,605,568.5,532,495.5,459.5,424,389.5,355.5,322.5,290.5,259.5,229.5,200.5,173.5,147,122,98.5,76.5,55.5,36,18,1,-14.5,-28.5,-41.5,-53,-63.5,-73,-81.5,-88.5,-94.5,-100,-104,-107.5,-110.5,-112,-113.5,-114,-114,-113.5,-112.5,-111,-109,106.5,104,101,98,95,91.5,88,84.5,80.5,77,73.5,69.5,66,62.5,58.5,55.5,52,48.5,45.5,42.5,39.5,36.5,34,31.5,29,26.5,24.5,22.5,20.5,19,17.5,15.5,14.5,13,12,10.5,9.5,8.5,8,7,6.5,5.5,5,4.5,4,3.5,3.5,3,2.5,2.5,2,2,1.5,1.5,1,1,1,1,.5,.5,.5,.5,.5,.5]); + +MP2.QUANT_LUT_STEP_1=[[0,0,1,1,1,2,2,2,2,2,2,2,2,2],[0,0,0,0,0,0,1,1,1,2,2,2,2,2]];MP2.QUANT_TAB={A:27|64,B:30|64,C:8,D:12};MP2.QUANT_LUT_STEP_2=[[MP2.QUANT_TAB.C,MP2.QUANT_TAB.C,MP2.QUANT_TAB.D],[MP2.QUANT_TAB.A,MP2.QUANT_TAB.A,MP2.QUANT_TAB.A],[MP2.QUANT_TAB.B,MP2.QUANT_TAB.A,MP2.QUANT_TAB.B]];MP2.QUANT_LUT_STEP_3=[[68,68,52,52,52,52,52,52,52,52,52,52],[67,67,67,66,66,66,66,66,66,66,66,49,49,49,49,49,49,49,49,49,49,49,49,32,32,32,32,32,32,32],[69,69,69,69,52,52,52,52,52,52,52,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36]];MP2.QUANT_LUT_STEP4=[[0,1,2,17],[0,1,2,3,4,5,6,17],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17],[0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17],[0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,17],[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]];MP2.QUANT_TAB=[{levels:3,group:1,bits:5},{levels:5,group:1,bits:7},{levels:7,group:0,bits:3},{levels:9,group:1,bits:10},{levels:15,group:0,bits:4},{levels:31,group:0,bits:5},{levels:63,group:0,bits:6},{levels:127,group:0,bits:7},{levels:255,group:0,bits:8},{levels:511,group:0,bits:9},{levels:1023,group:0,bits:10},{levels:2047,group:0,bits:11},{levels:4095,group:0,bits:12},{levels:8191,group:0,bits:13},{levels:16383,group:0,bits:14},{levels:32767,group:0,bits:15},{levels:65535,group:0,bits:16}];return MP2}();JSMpeg.Decoder.MP2AudioWASM=function(){"use strict";var MP2WASM=function(options){JSMpeg.Decoder.Base.call(this,options);this.module=options.wasmModule;this.bufferSize=options.audioBufferSize||128*1024;this.bufferMode=options.streaming?JSMpeg.BitBuffer.MODE.EVICT:JSMpeg.BitBuffer.MODE.EXPAND;this.sampleRate=0};MP2WASM.prototype=Object.create(JSMpeg.Decoder.Base.prototype);MP2WASM.prototype.constructor=MP2WASM;MP2WASM.prototype.initializeWasmDecoder=function(){if(!this.module.instance){console.warn("JSMpeg: WASM module not compiled yet");return}this.instance=this.module.instance;this.functions=this.module.instance.exports;this.decoder=this.functions._mp2_decoder_create(this.bufferSize,this.bufferMode)};MP2WASM.prototype.destroy=function(){this.functions._mp2_decoder_destroy(this.decoder)};MP2WASM.prototype.bufferGetIndex=function(){return this.functions._mp2_decoder_get_index(this.decoder)};MP2WASM.prototype.bufferSetIndex=function(index){this.functions._mp2_decoder_set_index(this.decoder,index)};MP2WASM.prototype.bufferWrite=function(buffers){if(!this.decoder){this.initializeWasmDecoder()}var totalLength=0;for(var i=0;i>4<<4,h=this.height,w2=w>>1,h2=h>>1;if(isClampedArray&&this.shouldCreateUnclampedViews){y=new Uint8Array(y.buffer),cb=new Uint8Array(cb.buffer),cr=new Uint8Array(cr.buffer)}gl.useProgram(this.program);this.updateTexture(gl.TEXTURE0,this.textureY,w,h,y);this.updateTexture(gl.TEXTURE1,this.textureCb,w2,h2,cb);this.updateTexture(gl.TEXTURE2,this.textureCr,w2,h2,cr);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};WebGLRenderer.prototype.updateTexture=function(unit,texture,w,h,data){var gl=this.gl;gl.activeTexture(unit);gl.bindTexture(gl.TEXTURE_2D,texture);if(this.hasTextureData[unit]){gl.texSubImage2D(gl.TEXTURE_2D,0,0,0,w,h,gl.LUMINANCE,gl.UNSIGNED_BYTE,data)}else{this.hasTextureData[unit]=true;gl.texImage2D(gl.TEXTURE_2D,0,gl.LUMINANCE,w,h,0,gl.LUMINANCE,gl.UNSIGNED_BYTE,data)}};WebGLRenderer.IsSupported=function(){try{if(!window.WebGLRenderingContext){return false}var canvas=document.createElement("canvas");return!!(canvas.getContext("webgl")||canvas.getContext("experimental-webgl"))}catch(err){return false}};WebGLRenderer.SHADER={FRAGMENT_YCRCB_TO_RGBA:["precision mediump float;","uniform sampler2D textureY;","uniform sampler2D textureCb;","uniform sampler2D textureCr;","varying vec2 texCoord;","mat4 rec601 = mat4(","1.16438, 0.00000, 1.59603, -0.87079,","1.16438, -0.39176, -0.81297, 0.52959,","1.16438, 2.01723, 0.00000, -1.08139,","0, 0, 0, 1",");","void main() {","float y = texture2D(textureY, texCoord).r;","float cb = texture2D(textureCb, texCoord).r;","float cr = texture2D(textureCr, texCoord).r;","gl_FragColor = vec4(y, cr, cb, 1.0) * rec601;","}"].join("\n"),FRAGMENT_LOADING:["precision mediump float;","uniform float progress;","varying vec2 texCoord;","void main() {","float c = ceil(progress-(1.0-texCoord.y));","gl_FragColor = vec4(c,c,c,1);","}"].join("\n"),VERTEX_IDENTITY:["attribute vec2 vertex;","varying vec2 texCoord;","void main() {","texCoord = vertex;","gl_Position = vec4((vertex * 2.0 - 1.0) * vec2(1, -1), 0.0, 1.0);","}"].join("\n")};return WebGLRenderer}();JSMpeg.Renderer.Canvas2D=function(){"use strict";var CanvasRenderer=function(options){this.canvas=options.canvas||document.createElement("canvas");this.width=this.canvas.width;this.height=this.canvas.height;this.enabled=true;this.context=this.canvas.getContext("2d")};CanvasRenderer.prototype.destroy=function(){};CanvasRenderer.prototype.resize=function(width,height){this.width=width|0;this.height=height|0;this.canvas.width=this.width;this.canvas.height=this.height;this.imageData=this.context.getImageData(0,0,this.width,this.height);JSMpeg.Fill(this.imageData.data,255)};CanvasRenderer.prototype.renderProgress=function(progress){var w=this.canvas.width,h=this.canvas.height,ctx=this.context;ctx.fillStyle="#222";ctx.fillRect(0,0,w,h);ctx.fillStyle="#fff";ctx.fillRect(0,h-h*progress,w,h*progress)};CanvasRenderer.prototype.render=function(y,cb,cr){this.YCbCrToRGBA(y,cb,cr,this.imageData.data);this.context.putImageData(this.imageData,0,0)};CanvasRenderer.prototype.YCbCrToRGBA=function(y,cb,cr,rgba){if(!this.enabled){return}var w=this.width+15>>4<<4,w2=w>>1;var yIndex1=0,yIndex2=w,yNext2Lines=w+(w-this.width);var cIndex=0,cNextLine=w2-(this.width>>1);var rgbaIndex1=0,rgbaIndex2=this.width*4,rgbaNext2Lines=this.width*4;var cols=this.width>>1,rows=this.height>>1;var ccb,ccr,r,g,b;for(var row=0;row>8)-179;g=(ccr*88>>8)-44+(ccb*183>>8)-91;b=ccr+(ccr*198>>8)-227;var y1=y[yIndex1++];var y2=y[yIndex1++];rgba[rgbaIndex1]=y1+r;rgba[rgbaIndex1+1]=y1-g;rgba[rgbaIndex1+2]=y1+b;rgba[rgbaIndex1+4]=y2+r;rgba[rgbaIndex1+5]=y2-g;rgba[rgbaIndex1+6]=y2+b;rgbaIndex1+=8;var y3=y[yIndex2++];var y4=y[yIndex2++];rgba[rgbaIndex2]=y3+r;rgba[rgbaIndex2+1]=y3-g;rgba[rgbaIndex2+2]=y3+b;rgba[rgbaIndex2+4]=y4+r;rgba[rgbaIndex2+5]=y4-g;rgba[rgbaIndex2+6]=y4+b;rgbaIndex2+=8}yIndex1+=yNext2Lines;yIndex2+=yNext2Lines;rgbaIndex1+=rgbaNext2Lines;rgbaIndex2+=rgbaNext2Lines;cIndex+=cNextLine}};return CanvasRenderer}();JSMpeg.AudioOutput.WebAudio=function(){"use strict";var WebAudioOut=function(options){this.context=WebAudioOut.CachedContext=WebAudioOut.CachedContext||new(window.AudioContext||window.webkitAudioContext);this.gain=this.context.createGain();this.destination=this.gain;this.gain.connect(this.context.destination);this.context._connections=(this.context._connections||0)+1;this.startTime=0;this.buffer=null;this.wallclockStartTime=0;this.volume=1;this.enabled=true;this.unlocked=!WebAudioOut.NeedsUnlocking();Object.defineProperty(this,"enqueuedTime",{get:this.getEnqueuedTime})};WebAudioOut.prototype.destroy=function(){this.gain.disconnect();this.context._connections--;if(this.context._connections===0){this.context.close();WebAudioOut.CachedContext=null}};WebAudioOut.prototype.play=function(sampleRate,left,right){if(!this.enabled){return}if(!this.unlocked){var ts=JSMpeg.Now();if(this.wallclockStartTimethis.memory.buffer.byteLength){var bytesNeeded=this.brk-this.memory.buffer.byteLength;var pagesNeeded=Math.ceil(bytesNeeded/this.pageSize);this.memory.grow(pagesNeeded);this.createHeapViews()}return previousBrk};WASM.prototype.c_abort=function(size){console.warn("JSMPeg: WASM abort",arguments)};WASM.prototype.c_assertFail=function(size){console.warn("JSMPeg: WASM ___assert_fail",arguments)};WASM.prototype.readDylinkSection=function(buffer){var bytes=new Uint8Array(buffer);var next=0;var readVarUint=function(){var ret=0;var mul=1;while(1){var byte=bytes[next++];ret+=(byte&127)*mul;mul*=128;if(!(byte&128)){return ret}}};var matchNextBytes=function(expected){for(var i=0;i this.bits.index) { + if (this.timestamps[i].index > currentIndex) { break; } newTimestampIndex = i; diff --git a/src/jsmpeg.js b/src/jsmpeg.js index 0bc782ff..e11dd0c6 100644 --- a/src/jsmpeg.js +++ b/src/jsmpeg.js @@ -92,7 +92,23 @@ var JSMpeg = { array[i] = value; } } - } + }, + + Base64ToArrayBuffer: function(base64) { + var binary = window.atob(base64); + var length = binary.length; + var bytes = new Uint8Array(length); + for (var i = 0; i < length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytes.buffer; + }, + + // The build process may append `JSMpeg.WASM_BINARY_INLINED = base64data;` + // to the minified source. + // If this property is present, jsmpeg will use the inlined binary data + // instead of trying to load a jsmpeg.wasm file via Ajax. + WASM_BINARY_INLINED: null }; // Automatically create players for all found
elements. @@ -103,3 +119,4 @@ else { document.addEventListener('DOMContentLoaded', JSMpeg.CreateVideoElements); } + diff --git a/src/mp2-wasm.js b/src/mp2-wasm.js new file mode 100644 index 00000000..f92205b8 --- /dev/null +++ b/src/mp2-wasm.js @@ -0,0 +1,106 @@ +JSMpeg.Decoder.MP2AudioWASM = (function(){ "use strict"; + +// Based on kjmp2 by Martin J. Fiedler +// http://keyj.emphy.de/kjmp2/ + +var MP2WASM = function(options) { + JSMpeg.Decoder.Base.call(this, options); + + this.module = options.wasmModule; + + this.bufferSize = options.audioBufferSize || 128*1024; + this.bufferMode = options.streaming + ? JSMpeg.BitBuffer.MODE.EVICT + : JSMpeg.BitBuffer.MODE.EXPAND; + + this.sampleRate = 0; +}; + +MP2WASM.prototype = Object.create(JSMpeg.Decoder.Base.prototype); +MP2WASM.prototype.constructor = MP2WASM; + +MP2WASM.prototype.initializeWasmDecoder = function() { + if (!this.module.instance) { + console.warn('JSMpeg: WASM module not compiled yet'); + return; + } + this.instance = this.module.instance; + this.functions = this.module.instance.exports; + this.decoder = this.functions._mp2_decoder_create(this.bufferSize, this.bufferMode); +}; + +MP2WASM.prototype.destroy = function() { + this.functions._mp2_decoder_destroy(this.decoder); +}; + +MP2WASM.prototype.bufferGetIndex = function() { + return this.functions._mp2_decoder_get_index(this.decoder); +}; + +MP2WASM.prototype.bufferSetIndex = function(index) { + this.functions._mp2_decoder_set_index(this.decoder, index); +}; + +MP2WASM.prototype.bufferWrite = function(buffers) { + if (!this.decoder) { + this.initializeWasmDecoder(); + } + + var totalLength = 0; + for (var i = 0; i < buffers.length; i++) { + totalLength += buffers[i].length; + } + + var ptr = this.functions._mp2_decoder_get_write_ptr(this.decoder, totalLength); + for (var i = 0; i < buffers.length; i++) { + this.instance.heapU8.set(buffers[i], ptr); + ptr += buffers[i].length; + } + + this.functions._mp2_decoder_did_write(this.decoder, totalLength); + return totalLength; +}; + +MP2WASM.prototype.decode = function() { + if (!this.decoder) { return; } + + var decodedBytes = this.functions._mp2_decoder_decode(this.decoder); + + if (decodedBytes === 0) { + return false; + } + + if (!this.sampleRate) { + this.sampleRate = this.functions._mp2_decoder_get_sample_rate(this.decoder); + } + + if (this.destination) { + // Create a Float32 View into the modules output channel data + var leftPtr = this.functions._mp2_decoder_get_left_channel_ptr(this.decoder), + rightPtr = this.functions._mp2_decoder_get_right_channel_ptr(this.decoder); + + var leftOffset = leftPtr / Float32Array.BYTES_PER_ELEMENT, + rightOffset = rightPtr / Float32Array.BYTES_PER_ELEMENT; + + var left = this.instance.heapF32.subarray(leftOffset, leftOffset + MP2WASM.SAMPLES_PER_FRAME), + right = this.instance.heapF32.subarray(rightOffset, rightOffset + MP2WASM.SAMPLES_PER_FRAME); + + this.destination.play(this.sampleRate, left, right); + } + + this.advanceDecodedTime(MP2WASM.SAMPLES_PER_FRAME / this.sampleRate); + return true; +}; + + +MP2WASM.prototype.getCurrentTime = function() { + var enqueuedTime = this.destination ? this.destination.enqueuedTime : 0; + return this.decodedTime - enqueuedTime; +}; + +MP2WASM.SAMPLES_PER_FRAME = 1152; + +return MP2WASM; + +})(); + diff --git a/src/mpeg1-wasm.js b/src/mpeg1-wasm.js new file mode 100644 index 00000000..15ceade8 --- /dev/null +++ b/src/mpeg1-wasm.js @@ -0,0 +1,115 @@ +JSMpeg.Decoder.MPEG1VideoWASM = (function(){ "use strict"; + +var MPEG1WASM = function(options) { + JSMpeg.Decoder.Base.call(this, options); + + this.module = options.wasmModule; + + this.bufferSize = options.videoBufferSize || 512*1024; + this.bufferMode = options.streaming + ? JSMpeg.BitBuffer.MODE.EVICT + : JSMpeg.BitBuffer.MODE.EXPAND; + + this.decodeFirstFrame = options.decodeFirstFrame !== false; + this.hasSequenceHeader = false; +}; + +MPEG1WASM.prototype = Object.create(JSMpeg.Decoder.Base.prototype); +MPEG1WASM.prototype.constructor = MPEG1WASM; + +MPEG1WASM.prototype.initializeWasmDecoder = function() { + if (!this.module.instance) { + console.warn('JSMpeg: WASM module not compiled yet'); + return; + } + this.instance = this.module.instance; + this.functions = this.module.instance.exports; + this.decoder = this.functions._mpeg1_decoder_create(this.bufferSize, this.bufferMode); +}; + +MPEG1WASM.prototype.destroy = function() { + this.functions._mpeg1_decoder_destroy(this.decoder); +}; + +MPEG1WASM.prototype.bufferGetIndex = function() { + return this.functions._mpeg1_decoder_get_index(this.decoder); +}; + +MPEG1WASM.prototype.bufferSetIndex = function(index) { + this.functions._mpeg1_decoder_set_index(this.decoder, index); +}; + +MPEG1WASM.prototype.bufferWrite = function(buffers) { + if (!this.decoder) { + this.initializeWasmDecoder(); + } + + var totalLength = 0; + for (var i = 0; i < buffers.length; i++) { + totalLength += buffers[i].length; + } + + var ptr = this.functions._mpeg1_decoder_get_write_ptr(this.decoder, totalLength); + for (var i = 0; i < buffers.length; i++) { + this.instance.heapU8.set(buffers[i], ptr); + ptr += buffers[i].length; + } + + this.functions._mpeg1_decoder_did_write(this.decoder, totalLength); + return totalLength; +}; + +MPEG1WASM.prototype.write = function(pts, buffers) { + JSMpeg.Decoder.Base.prototype.write.call(this, pts, buffers); + + if (!this.hasSequenceHeader && this.functions._mpeg1_decoder_has_sequence_header(this.decoder)) { + this.loadSequnceHeader(); + } +}; + +MPEG1WASM.prototype.loadSequnceHeader = function() { + this.hasSequenceHeader = true; + this.frameRate = this.functions._mpeg1_decoder_get_frame_rate(this.decoder); + this.codedSize = this.functions._mpeg1_decoder_get_coded_size(this.decoder); + + if (this.destination) { + var w = this.functions._mpeg1_decoder_get_width(this.decoder); + var h = this.functions._mpeg1_decoder_get_height(this.decoder); + this.destination.resize(w, h); + } + + if (this.decodeFirstFrame) { + this.decode(); + } +}; + +MPEG1WASM.prototype.decode = function() { + if (!this.decoder) { return; } + + var didDecode = this.functions._mpeg1_decoder_decode(this.decoder); + + if (!didDecode) { + return false; + } + + // Invoke decode callbacks + if (this.destination) { + var ptrY = this.functions._mpeg1_decoder_get_y_ptr(this.decoder), + ptrCr = this.functions._mpeg1_decoder_get_cr_ptr(this.decoder), + ptrCb = this.functions._mpeg1_decoder_get_cb_ptr(this.decoder); + + var dy = this.instance.heapU8.subarray(ptrY, ptrY + this.codedSize); + var dcr = this.instance.heapU8.subarray(ptrCr, ptrCr + (this.codedSize >> 2)); + var dcb = this.instance.heapU8.subarray(ptrCb, ptrCb + (this.codedSize >> 2)); + + this.destination.render(dy, dcr, dcb, false); + } + + this.advanceDecodedTime(1/this.frameRate); + return true; +}; + +return MPEG1WASM; + +})(); + diff --git a/src/player.js b/src/player.js index fa9a33e6..c40dc8b8 100644 --- a/src/player.js +++ b/src/player.js @@ -27,17 +27,28 @@ var Player = function(url, options) { this.demuxer = new JSMpeg.Demuxer.TS(options); this.source.connect(this.demuxer); + if (!options.disableWebAssembly && JSMpeg.WASMModule.IsSupported()) { + this.wasmModule = new JSMpeg.WASMModule(); + options.wasmModule =this.wasmModule; + } + if (options.video !== false) { - this.video = new JSMpeg.Decoder.MPEG1Video(options); + this.video = options.wasmModule + ? new JSMpeg.Decoder.MPEG1VideoWASM(options) + : new JSMpeg.Decoder.MPEG1Video(options); + this.renderer = !options.disableGl && JSMpeg.Renderer.WebGL.IsSupported() ? new JSMpeg.Renderer.WebGL(options) : new JSMpeg.Renderer.Canvas2D(options); + this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.VIDEO_1, this.video); this.video.connect(this.renderer); } if (options.audio !== false && JSMpeg.AudioOutput.WebAudio.IsSupported()) { - this.audio = new JSMpeg.Decoder.MP2Audio(options); + this.audio = options.wasmModule + ? new JSMpeg.Decoder.MP2AudioWASM(options) + : new JSMpeg.Decoder.MP2Audio(options); this.audioOut = new JSMpeg.AudioOutput.WebAudio(options); this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.AUDIO_1, this.audio); this.audio.connect(this.audioOut); @@ -57,8 +68,26 @@ var Player = function(url, options) { document.addEventListener('visibilitychange', this.showHide.bind(this)); } - this.source.start(); + // If we have WebAssembly support, wait until the module is compiled before + // loading the source. Otherwise the decoders won't know what to do with + // the source data. + if (this.wasmModule) { + if (JSMpeg.WASM_BINARY_INLINED) { + var wasm = JSMpeg.Base64ToArrayBuffer(JSMpeg.WASM_BINARY_INLINED); + this.wasmModule.loadFromBuffer(wasm, this.startLoading.bind(this)); + } + else { + this.wasmModule.loadFromFile('jsmpeg.wasm', this.startLoading.bind(this)); + } + } + else { + this.startLoading(); + + } +}; +Player.prototype.startLoading = function() { + this.source.start(); if (this.autoplay) { this.play(); } @@ -113,8 +142,10 @@ Player.prototype.stop = function(ev) { Player.prototype.destroy = function() { this.pause(); this.source.destroy(); - this.renderer.destroy(); - this.audioOut.destroy(); + this.video && this.video.destroy(); + this.renderer && this.renderer.destroy(); + this.audio && this.audio.destroy(); + this.audioOut && this.audioOut.destroy(); }; Player.prototype.seek = function(time) { diff --git a/src/wasm-module.js b/src/wasm-module.js new file mode 100644 index 00000000..9ac7a999 --- /dev/null +++ b/src/wasm-module.js @@ -0,0 +1,148 @@ +JSMpeg.WASMModule = (function(){ "use strict"; + +var WASM = function() { + this.stackSize = 5 * 1024 * 1024; // emscripten default + this.pageSize = 64 * 1024; // wasm page size + this.onInitCallback = null; +}; + +WASM.prototype.write = function(buffer) { + this.loadFromBuffer(buffer, this.onInitCallback); +}; + +WASM.prototype.loadFromFile = function(url, callback) { + this.onInitCallback = callback; + var ajax = new JSMpeg.Source.Ajax(url); + ajax.connect(this); + ajax.start(); +}; + +WASM.prototype.loadFromBuffer = function(buffer, callback) { + this.moduleInfo = this.readDylinkSection(buffer); + if (!this.moduleInfo) { + this.callback && this.callback(null); + return; + } + + this.memory = new WebAssembly.Memory({initial: 256}); + var env = { + memory: this.memory, + memoryBase: 0, + table: new WebAssembly.Table({initial: this.moduleInfo.tableSize, element: 'anyfunc'}), + tableBase: 0, + abort: this.c_abort.bind(this), + ___assert_fail: this.c_assertFail.bind(this), + _sbrk: this.c_sbrk.bind(this) + }; + + this.brk = this.align(this.moduleInfo.memorySize + this.stackSize); + WebAssembly.instantiate(buffer, {env: env}).then(function(results){ + this.instance = results.instance; + if (this.instance.exports.__post_instantiate) { + this.instance.exports.__post_instantiate(); + } + this.createHeapViews(); + callback && callback(this); + }.bind(this)) +}; + +WASM.prototype.createHeapViews = function() { + this.instance.heapU8 = new Uint8Array(this.memory.buffer); + this.instance.heapU32 = new Uint32Array(this.memory.buffer); + this.instance.heapF32 = new Float32Array(this.memory.buffer); +}; + +WASM.prototype.align = function(addr) { + var a = Math.pow(2, this.moduleInfo.memoryAlignment); + return Math.ceil(addr / a) * a; +}; + +WASM.prototype.c_sbrk = function(size) { + var previousBrk = this.brk; + this.brk += size; + + if (this.brk > this.memory.buffer.byteLength) { + var bytesNeeded = this.brk - this.memory.buffer.byteLength; + var pagesNeeded = Math.ceil(bytesNeeded / this.pageSize); + this.memory.grow(pagesNeeded); + this.createHeapViews(); + } + return previousBrk; +}; + +WASM.prototype.c_abort = function(size) { + console.warn('JSMPeg: WASM abort', arguments); +}; + +WASM.prototype.c_assertFail = function(size) { + console.warn('JSMPeg: WASM ___assert_fail', arguments); +}; + + +WASM.prototype.readDylinkSection = function(buffer) { + // Read the WASM header and dylink section of the .wasm binary data + // to get the needed table size and static data size. + + // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md + // https://github.com/kripken/emscripten/blob/20602efb955a7c6c20865a495932427e205651d2/src/support.js + + var bytes = new Uint8Array(buffer); + var next = 0; + + var readVarUint = function () { + var ret = 0; + var mul = 1; + while (1) { + var byte = bytes[next++]; + ret += ((byte & 0x7f) * mul); + mul *= 0x80; + if (!(byte & 0x80)) { + return ret + } + } + } + + var matchNextBytes = function(expected) { + for (var i = 0; i < expected.length; i++) { + var b = typeof(expected[i]) === 'string' + ? expected[i].charCodeAt(0) + : expected[i]; + if (bytes[next++] !== b) { + return false; + } + } + return true; + }; + + + + // Make sure we have a wasm header + if (!matchNextBytes([0, 'a', 's', 'm'])) { + console.warn('JSMpeg: WASM header not found'); + return null; + } + + // Make sure we have a dylink section + var next = 9; + var sectionSize = readVarUint(); + if (!matchNextBytes([6, 'd', 'y', 'l', 'i', 'n', 'k'])) { + console.warn('JSMpeg: No dylink section found in WASM'); + return null; + } + + return { + memorySize: readVarUint(), + memoryAlignment: readVarUint(), + tableSize: readVarUint(), + tableAlignment: readVarUint() + }; +}; + +WASM.IsSupported = function() { + return (!!window.WebAssembly); +}; + +return WASM; + +})(); + diff --git a/src/wasm/buffer.c b/src/wasm/buffer.c new file mode 100644 index 00000000..1396cb67 --- /dev/null +++ b/src/wasm/buffer.c @@ -0,0 +1,189 @@ +#include +#include +#include + +#include "buffer.h" + +typedef struct bit_buffer_t { + uint8_t *bytes; + unsigned int index; + unsigned int byte_capacity; + unsigned int byte_length; + bit_buffer_mode_t mode; +} bit_buffer_t; + +void bit_buffer_resize(bit_buffer_t *self, unsigned int byte_capacity); +void bit_buffer_evict(bit_buffer_t *self, unsigned int bytes_needed); + + + +bit_buffer_t *bit_buffer_create(unsigned int initial_byte_capacity, bit_buffer_mode_t mode) { + bit_buffer_t *self = malloc(sizeof(bit_buffer_t)); + self->mode = mode; + self->bytes = malloc(initial_byte_capacity); + self->byte_capacity = initial_byte_capacity; + self->byte_length = 0; + self->index = 0; + return self; +} + + +void bit_buffer_destroy(bit_buffer_t *self) { + free(self->bytes); + free(self); +} + + +int bit_buffer_get_index(bit_buffer_t *self) { + return self->index; +} + + +void bit_buffer_set_index(bit_buffer_t *self, unsigned int index) { + self->index = index; // TODO check validity! +} + + +uint8_t *bit_buffer_get_write_ptr(bit_buffer_t *self, unsigned int bytes_to_write) { + int bytes_available = self->byte_capacity - self->byte_length; + + if (bytes_to_write > bytes_available) { + if (self->mode == BIT_BUFFER_MODE_EXPAND) { + int new_byte_capacity = self->byte_capacity * 2; + if (new_byte_capacity + bytes_available < bytes_to_write) { + new_byte_capacity = bytes_to_write - bytes_available; + } + bit_buffer_resize(self, new_byte_capacity); + } + else { + bit_buffer_evict(self, bytes_to_write); + } + } + + return self->bytes + self->byte_length; +}; + + +void bit_buffer_did_write(bit_buffer_t *self, unsigned int bytes_written) { + self->byte_length += bytes_written; +} + + +int bit_buffer_find_next_start_code(bit_buffer_t *self) { + for (int i = ((self->index + 7) >> 3); i < self->byte_length; i++) { + if( + self->bytes[i] == 0x00 && + self->bytes[i+1] == 0x00 && + self->bytes[i+2] == 0x01 + ) { + self->index = (i+4) << 3; + return self->bytes[i+3]; + } + } + self->index = (self->byte_length << 3); + return -1; +} + + +int bit_buffer_find_start_code(bit_buffer_t *self, int code) { + int current = 0; + while (true) { + current = bit_buffer_find_next_start_code(self); + if (current == code || current == -1) { + return current; + } + } + return -1; +} + + +int bit_buffer_next_bytes_are_start_code(bit_buffer_t *self) { + int i = ((self->index + 7) >> 3); + return ( + i >= self->byte_length || ( + self->bytes[i] == 0x00 && + self->bytes[i+1] == 0x00 && + self->bytes[i+2] == 0x01 + ) + ); +} + + +int bit_buffer_peek(bit_buffer_t *self, unsigned int count) { + int offset = self->index; + int value = 0; + while (count) { + int current_byte = self->bytes[offset >> 3]; + int remaining = 8 - (offset & 7); // remaining bits in byte + int read = remaining < count ? remaining : count; // bits in self run + int shift = remaining - read; + int mask = (0xff >> (8-read)); + + value = (value << read) | ((current_byte & (mask << shift)) >> shift); + + offset += read; + count -= read; + } + + return value; +} + + +int bit_buffer_read(bit_buffer_t *self, unsigned int count) { + int value = bit_buffer_peek(self, count); + self->index += count; + return value; +} + + +int bit_buffer_skip(bit_buffer_t *self, unsigned int count) { + return (self->index += count); +} + + +void bit_buffer_rewind(bit_buffer_t *self, unsigned int count) { + self->index = self->index - count; + if (self->index < 0) { + self->index = 0; + } +} + + +int bit_buffer_has(bit_buffer_t *self, unsigned int count) { + return ((self->byte_length << 3) - self->index) >= count; +} + + +void bit_buffer_resize(bit_buffer_t *self, unsigned int byte_capacity) { + self->bytes = realloc(self->bytes, byte_capacity); + self->byte_capacity = byte_capacity; + if (self->index > self->byte_length << 3) { + self->index = self->byte_length << 3; + } +} + + +void bit_buffer_evict(bit_buffer_t *self, unsigned int bytes_needed) { + int byte_pos = self->index >> 3; + int bytes_available = self->byte_capacity - self->byte_length; + + // If the current index is the write position, we can simply reset both + // to 0. Also reset (and throw away yet unread data) if we won't be able + // to fit the new data in even after a normal eviction. + if ( + byte_pos == self->byte_length || + bytes_needed > bytes_available + byte_pos // emergency evac + ) { + self->byte_length = 0; + self->index = 0; + return; + } + else if (byte_pos == 0) { + // Nothing read yet - we can't evict anything + return; + } + + memmove(self->bytes, self->bytes + byte_pos, self->byte_length - byte_pos); + self->byte_length -= byte_pos; + self->index -= byte_pos << 3; +} diff --git a/src/wasm/buffer.h b/src/wasm/buffer.h new file mode 100644 index 00000000..d8572477 --- /dev/null +++ b/src/wasm/buffer.h @@ -0,0 +1,31 @@ +#ifndef BUFFER_H +#define BUFFER_H + +#include + +typedef struct bit_buffer_t bit_buffer_t; + +typedef enum { + BIT_BUFFER_MODE_EVICT = 1, + BIT_BUFFER_MODE_EXPAND = 2 +} bit_buffer_mode_t; + + +bit_buffer_t *bit_buffer_create(unsigned int initial_byte_capacity, bit_buffer_mode_t mode); +void bit_buffer_destroy(bit_buffer_t *self); + +int bit_buffer_get_index(bit_buffer_t *self); +void bit_buffer_set_index(bit_buffer_t *self, unsigned int index); + +uint8_t *bit_buffer_get_write_ptr(bit_buffer_t *self, unsigned int bytes_to_write); +void bit_buffer_did_write(bit_buffer_t *self, unsigned int bytes_written); +int bit_buffer_find_next_start_code(bit_buffer_t *self); +int bit_buffer_find_start_code(bit_buffer_t *self, int code); +int bit_buffer_next_bytes_are_start_code(bit_buffer_t *self); +int bit_buffer_peek(bit_buffer_t *self, unsigned int count); +int bit_buffer_read(bit_buffer_t *self, unsigned int count); +int bit_buffer_skip(bit_buffer_t *self, unsigned int count); +int bit_buffer_has(bit_buffer_t *self, unsigned int count); +void bit_buffer_rewind(bit_buffer_t *self, unsigned int count); + +#endif diff --git a/src/wasm/mp2.c b/src/wasm/mp2.c new file mode 100644 index 00000000..d4583791 --- /dev/null +++ b/src/wasm/mp2.c @@ -0,0 +1,703 @@ +#include +#include +#include "mp2.h" + +const static int FRAME_SYNC = 0x7ff; + +const static int VERSION_MPEG_2_5 = 0x0; +const static int VERSION_MPEG_2 = 0x2; +const static int VERSION_MPEG_1 = 0x3; + +const static int LAYER_III = 0x1; +const static int LAYER_II = 0x2; +const static int LAYER_I = 0x3; + +const static int MODE_STEREO = 0x0; +const static int MODE_JOINT_STEREO = 0x1; +const static int MODE_DUAL_CHANNEL = 0x2; +const static int MODE_MONO = 0x3; + +const static unsigned short SAMPLE_RATE[] = { + 44100, 48000, 32000, 0, // MPEG-1 + 22050, 24000, 16000, 0 // MPEG-2 +}; + +const static short BIT_RATE[] = { + 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, // MPEG-1 + 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 // MPEG-2 +}; + +const static int SCALEFACTOR_BASE[] = { + 0x02000000, 0x01965FEA, 0x01428A30 +}; + +const static float SYNTHESIS_WINDOW[] = { + 0.0, -0.5, -0.5, -0.5, -0.5, -0.5, + -0.5, -1.0, -1.0, -1.0, -1.0, -1.5, + -1.5, -2.0, -2.0, -2.5, -2.5, -3.0, + -3.5, -3.5, -4.0, -4.5, -5.0, -5.5, + -6.5, -7.0, -8.0, -8.5, -9.5, -10.5, + -12.0, -13.0, -14.5, -15.5, -17.5, -19.0, + -20.5, -22.5, -24.5, -26.5, -29.0, -31.5, + -34.0, -36.5, -39.5, -42.5, -45.5, -48.5, + -52.0, -55.5, -58.5, -62.5, -66.0, -69.5, + -73.5, -77.0, -80.5, -84.5, -88.0, -91.5, + -95.0, -98.0, -101.0, -104.0, 106.5, 109.0, + 111.0, 112.5, 113.5, 114.0, 114.0, 113.5, + 112.0, 110.5, 107.5, 104.0, 100.0, 94.5, + 88.5, 81.5, 73.0, 63.5, 53.0, 41.5, + 28.5, 14.5, -1.0, -18.0, -36.0, -55.5, + -76.5, -98.5, -122.0, -147.0, -173.5, -200.5, + -229.5, -259.5, -290.5, -322.5, -355.5, -389.5, + -424.0, -459.5, -495.5, -532.0, -568.5, -605.0, + -641.5, -678.0, -714.0, -749.0, -783.5, -817.0, + -849.0, -879.5, -908.5, -935.0, -959.5, -981.0, + -1000.5, -1016.0, -1028.5, -1037.5, -1042.5, -1043.5, + -1040.0, -1031.5, 1018.5, 1000.0, 976.0, 946.5, + 911.0, 869.5, 822.0, 767.5, 707.0, 640.0, + 565.5, 485.0, 397.0, 302.5, 201.0, 92.5, + -22.5, -144.0, -272.5, -407.0, -547.5, -694.0, + -846.0, -1003.0, -1165.0, -1331.5, -1502.0, -1675.5, + -1852.5, -2031.5, -2212.5, -2394.0, -2576.5, -2758.5, + -2939.5, -3118.5, -3294.5, -3467.5, -3635.5, -3798.5, + -3955.0, -4104.5, -4245.5, -4377.5, -4499.0, -4609.5, + -4708.0, -4792.5, -4863.5, -4919.0, -4958.0, -4979.5, + -4983.0, -4967.5, -4931.5, -4875.0, -4796.0, -4694.5, + -4569.5, -4420.0, -4246.0, -4046.0, -3820.0, -3567.0, + 3287.0, 2979.5, 2644.0, 2280.5, 1888.0, 1467.5, + 1018.5, 541.0, 35.0, -499.0, -1061.0, -1650.0, + -2266.5, -2909.0, -3577.0, -4270.0, -4987.5, -5727.5, + -6490.0, -7274.0, -8077.5, -8899.5, -9739.0, -10594.5, + -11464.5, -12347.0, -13241.0, -14144.5, -15056.0, -15973.5, + -16895.5, -17820.0, -18744.5, -19668.0, -20588.0, -21503.0, + -22410.5, -23308.5, -24195.0, -25068.5, -25926.5, -26767.0, + -27589.0, -28389.0, -29166.5, -29919.0, -30644.5, -31342.0, + -32009.5, -32645.0, -33247.0, -33814.5, -34346.0, -34839.5, + -35295.0, -35710.0, -36084.5, -36417.5, -36707.5, -36954.0, + -37156.5, -37315.0, -37428.0, -37496.0, 37519.0, 37496.0, + 37428.0, 37315.0, 37156.5, 36954.0, 36707.5, 36417.5, + 36084.5, 35710.0, 35295.0, 34839.5, 34346.0, 33814.5, + 33247.0, 32645.0, 32009.5, 31342.0, 30644.5, 29919.0, + 29166.5, 28389.0, 27589.0, 26767.0, 25926.5, 25068.5, + 24195.0, 23308.5, 22410.5, 21503.0, 20588.0, 19668.0, + 18744.5, 17820.0, 16895.5, 15973.5, 15056.0, 14144.5, + 13241.0, 12347.0, 11464.5, 10594.5, 9739.0, 8899.5, + 8077.5, 7274.0, 6490.0, 5727.5, 4987.5, 4270.0, + 3577.0, 2909.0, 2266.5, 1650.0, 1061.0, 499.0, + -35.0, -541.0, -1018.5, -1467.5, -1888.0, -2280.5, + -2644.0, -2979.5, 3287.0, 3567.0, 3820.0, 4046.0, + 4246.0, 4420.0, 4569.5, 4694.5, 4796.0, 4875.0, + 4931.5, 4967.5, 4983.0, 4979.5, 4958.0, 4919.0, + 4863.5, 4792.5, 4708.0, 4609.5, 4499.0, 4377.5, + 4245.5, 4104.5, 3955.0, 3798.5, 3635.5, 3467.5, + 3294.5, 3118.5, 2939.5, 2758.5, 2576.5, 2394.0, + 2212.5, 2031.5, 1852.5, 1675.5, 1502.0, 1331.5, + 1165.0, 1003.0, 846.0, 694.0, 547.5, 407.0, + 272.5, 144.0, 22.5, -92.5, -201.0, -302.5, + -397.0, -485.0, -565.5, -640.0, -707.0, -767.5, + -822.0, -869.5, -911.0, -946.5, -976.0, -1000.0, + 1018.5, 1031.5, 1040.0, 1043.5, 1042.5, 1037.5, + 1028.5, 1016.0, 1000.5, 981.0, 959.5, 935.0, + 908.5, 879.5, 849.0, 817.0, 783.5, 749.0, + 714.0, 678.0, 641.5, 605.0, 568.5, 532.0, + 495.5, 459.5, 424.0, 389.5, 355.5, 322.5, + 290.5, 259.5, 229.5, 200.5, 173.5, 147.0, + 122.0, 98.5, 76.5, 55.5, 36.0, 18.0, + 1.0, -14.5, -28.5, -41.5, -53.0, -63.5, + -73.0, -81.5, -88.5, -94.5, -100.0, -104.0, + -107.5, -110.5, -112.0, -113.5, -114.0, -114.0, + -113.5, -112.5, -111.0, -109.0, 106.5, 104.0, + 101.0, 98.0, 95.0, 91.5, 88.0, 84.5, + 80.5, 77.0, 73.5, 69.5, 66.0, 62.5, + 58.5, 55.5, 52.0, 48.5, 45.5, 42.5, + 39.5, 36.5, 34.0, 31.5, 29.0, 26.5, + 24.5, 22.5, 20.5, 19.0, 17.5, 15.5, + 14.5, 13.0, 12.0, 10.5, 9.5, 8.5, + 8.0, 7.0, 6.5, 5.5, 5.0, 4.5, + 4.0, 3.5, 3.5, 3.0, 2.5, 2.5, + 2.0, 2.0, 1.5, 1.5, 1.0, 1.0, + 1.0, 1.0, 0.5, 0.5, 0.5, 0.5, + 0.5, 0.5 +}; + +// Quantizer lookup, step 1: bitrate classes +const static uint8_t QUANT_LUT_STEP_1[2][16] = { + // 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384 <- bitrate + { 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, // mono + // 16, 24, 28, 32, 40, 48, 56, 64, 80, 96,112,128,160,192 <- bitrate / chan + { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2} // stereo +}; + +// Quantizer lookup, step 2: bitrate class, sample rate -> B2 table idx, sblimit +const static uint8_t QUANT_TAB_A = (27 | 64); // Table 3-B.2a: high-rate, sblimit = 27 +const static uint8_t QUANT_TAB_B = (30 | 64); // Table 3-B.2b: high-rate, sblimit = 30 +const static uint8_t QUANT_TAB_C = 8; // Table 3-B.2c: low-rate, sblimit = 8 +const static uint8_t QUANT_TAB_D = 12; // Table 3-B.2d: low-rate, sblimit = 12 + +const static uint8_t QUANT_LUT_STEP_2[3][3] = { + // 44.1 kHz, 48 kHz, 32 kHz + {QUANT_TAB_C, QUANT_TAB_C, QUANT_TAB_D}, // 32 - 48 kbit/sec/ch + {QUANT_TAB_A, QUANT_TAB_A, QUANT_TAB_A}, // 56 - 80 kbit/sec/ch + {QUANT_TAB_B, QUANT_TAB_A, QUANT_TAB_B} // 96+ kbit/sec/ch +}; + +// Quantizer lookup, step 3: B2 table, subband -> nbal, row index +// (upper 4 bits: nbal, lower 4 bits: row index) +const static uint8_t QUANT_LUT_STEP_3[3][32] = { + // Low-rate table (3-B.2c and 3-B.2d) + { + 0x44,0x44, + 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34 + }, + // High-rate table (3-B.2a and 3-B.2b) + { + 0x43,0x43,0x43, + 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, + 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20 + }, + // MPEG-2 LSR table (B.2 in ISO 13818-3) + { + 0x45,0x45,0x45,0x45, + 0x34,0x34,0x34,0x34,0x34,0x34,0x34, + 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, + 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24 + } +}; + +// Quantizer lookup, step 4: table row, allocation[] value -> quant table index +const static uint8_t QUANT_LUT_STEP4[6][16] = { + {0, 1, 2, 17}, + {0, 1, 2, 3, 4, 5, 6, 17}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17}, + {0, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, + {0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} +}; + +typedef struct quantizer_spec_t { + unsigned short levels; + unsigned char group; + unsigned char bits; +} quantizer_spec_t; + +const static quantizer_spec_t QUANT_TAB[] = { + {.levels = 3, .group = 1, .bits = 5}, // 1 + {.levels = 5, .group = 1, .bits = 7}, // 2 + {.levels = 7, .group = 0, .bits = 3}, // 3 + {.levels = 9, .group = 1, .bits = 10}, // 4 + {.levels = 15, .group = 0, .bits = 4}, // 5 + {.levels = 31, .group = 0, .bits = 5}, // 6 + {.levels = 63, .group = 0, .bits = 6}, // 7 + {.levels = 127, .group = 0, .bits = 7}, // 8 + {.levels = 255, .group = 0, .bits = 8}, // 9 + {.levels = 511, .group = 0, .bits = 9}, // 10 + {.levels = 1023, .group = 0, .bits = 10}, // 11 + {.levels = 2047, .group = 0, .bits = 11}, // 12 + {.levels = 4095, .group = 0, .bits = 12}, // 13 + {.levels = 8191, .group = 0, .bits = 13}, // 14 + {.levels = 16383, .group = 0, .bits = 14}, // 15 + {.levels = 32767, .group = 0, .bits = 15}, // 16 + {.levels = 65535, .group = 0, .bits = 16} // 17 +}; + +#define SAMPLES_PER_FRAME 1152 + +typedef struct mp2_decoder_t { + int sample_rate; + int v_pos; + + bit_buffer_t *bits; + + const quantizer_spec_t *allocation[2][32]; + uint8_t scale_factor_info[2][32]; + int scale_factor[2][32][3]; + int sample[2][32][3]; + + float channel_left[SAMPLES_PER_FRAME]; + float channel_right[SAMPLES_PER_FRAME]; + float D[1024]; + float V[1024]; + int U[32]; +} mp2_decoder_t; + + +void matrix_transform(int s[32][3], int ss, float *d, int dp); +void read_samples(mp2_decoder_t *self, int ch, int sb, int part); +const quantizer_spec_t *read_allocation(mp2_decoder_t *self, int sb, int tab3); +int decode_frame(mp2_decoder_t *self); + + +// ----------------------------------------------------------------------------- +// Public interface + +mp2_decoder_t *mp2_decoder_create(unsigned int buffer_size, bit_buffer_mode_t buffer_mode) { + mp2_decoder_t *self = malloc(sizeof(mp2_decoder_t)); + self->bits = bit_buffer_create(buffer_size, buffer_mode); + + self->sample_rate = 44100; + memcpy(self->D, SYNTHESIS_WINDOW, 512 * sizeof(float)); + memcpy(self->D + 512, SYNTHESIS_WINDOW, 512 * sizeof(float)); + + return self; +} + +void mp2_decoder_destroy(mp2_decoder_t *self) { + bit_buffer_destroy(self->bits); + free(self); +} + +void *mp2_decoder_get_write_ptr(mp2_decoder_t *self, unsigned int byte_size) { + return bit_buffer_get_write_ptr(self->bits, byte_size); +} + +int mp2_decoder_get_index(mp2_decoder_t *self) { + return bit_buffer_get_index(self->bits); +} + +void mp2_decoder_set_index(mp2_decoder_t *self, unsigned int index) { + bit_buffer_set_index(self->bits, index); +} + +void mp2_decoder_did_write(mp2_decoder_t *self, unsigned int byte_size) { + bit_buffer_did_write(self->bits, byte_size); +} + +int mp2_decoder_get_sample_rate(mp2_decoder_t *self) { + return self->sample_rate; +} + +void *mp2_decoder_get_left_channel_ptr(mp2_decoder_t *self) { + return self->channel_left; +} + +void *mp2_decoder_get_right_channel_ptr(mp2_decoder_t *self) { + return self->channel_right; +} + +int mp2_decoder_decode(mp2_decoder_t *self) { + int byte_pos = bit_buffer_get_index(self->bits) >> 3; + + if (!bit_buffer_has(self->bits, 16)) { + return 0; + } + + int decoded_bytes = decode_frame(self); + bit_buffer_set_index(self->bits, (byte_pos + decoded_bytes) << 3); + return decoded_bytes; +} + + + + +int decode_frame(mp2_decoder_t *self) { + // Check for valid header: syncword OK, MPEG-Audio Layer 2 + int sync = bit_buffer_read(self->bits, 11); + int version = bit_buffer_read(self->bits, 2); + int layer = bit_buffer_read(self->bits, 2); + int hasCRC = !bit_buffer_read(self->bits, 1); + + if ( + sync != FRAME_SYNC || + version != VERSION_MPEG_1 || + layer != LAYER_II + ) { + return 0; // Invalid header or unsupported version + } + + int bitrate_index = bit_buffer_read(self->bits, 4) - 1; + if (bitrate_index > 13) { + return 0; // Invalid bit rate or 'free format' + } + + int sample_rate_index = bit_buffer_read(self->bits, 2); + int sample_rate = SAMPLE_RATE[sample_rate_index]; + if (sample_rate_index == 3) { + return 0; // Invalid sample rate + } + if (version == VERSION_MPEG_2) { + sample_rate_index += 4; + bitrate_index += 14; + } + int padding = bit_buffer_read(self->bits, 1), + privat = bit_buffer_read(self->bits, 1), + mode = bit_buffer_read(self->bits, 2); + + // Parse the mode_extension, set up the stereo bound + int bound = 0; + if (mode == MODE_JOINT_STEREO) { + bound = (bit_buffer_read(self->bits, 2) + 1) << 2; + } + else { + bit_buffer_skip(self->bits, 2); + bound = (mode == MODE_MONO) ? 0 : 32; + } + + // Discard the last 4 bits of the header and the CRC value, if present + bit_buffer_skip(self->bits, 4); + if (hasCRC) { + bit_buffer_skip(self->bits, 16); + } + + // Compute the frame size + int bitrate = BIT_RATE[bitrate_index]; + sample_rate = SAMPLE_RATE[sample_rate_index]; + int frame_size = ((144000 * bitrate / sample_rate) + padding)|0; + + + // Prepare the quantizer table lookups + int tab3 = 0; + int sblimit = 0; + if (version == VERSION_MPEG_2) { + // MPEG-2 (LSR) + tab3 = 2; + sblimit = 30; + } + else { + // MPEG-1 + int tab1 = (mode == MODE_MONO) ? 0 : 1; + int tab2 = QUANT_LUT_STEP_1[tab1][bitrate_index]; + tab3 = QUANT_LUT_STEP_2[tab2][sample_rate_index]; + sblimit = tab3 & 63; + tab3 >>= 6; + } + + if (bound > sblimit) { + bound = sblimit; + } + + // Read the allocation information + for (int sb = 0; sb < bound; sb++) { + self->allocation[0][sb] = read_allocation(self, sb, tab3); + self->allocation[1][sb] = read_allocation(self, sb, tab3); + } + + for (int sb = bound; sb < sblimit; sb++) { + self->allocation[0][sb] = + self->allocation[1][sb] = + read_allocation(self, sb, tab3); + } + + // Read scale factor selector information + int channels = (mode == MODE_MONO) ? 1 : 2; + for (int sb = 0; sb < sblimit; sb++) { + for (int ch = 0; ch < channels; ch++) { + if (self->allocation[ch][sb]) { + self->scale_factor_info[ch][sb] = bit_buffer_read(self->bits, 2); + } + } + if (mode == MODE_MONO) { + self->scale_factor_info[1][sb] = self->scale_factor_info[0][sb]; + } + } + + // Read scale factors + for (int sb = 0; sb < sblimit; sb++) { + for (int ch = 0; ch < channels; ch++) { + if (self->allocation[ch][sb]) { + int *sf = self->scale_factor[ch][sb]; + switch (self->scale_factor_info[ch][sb]) { + case 0: + sf[0] = bit_buffer_read(self->bits, 6); + sf[1] = bit_buffer_read(self->bits, 6); + sf[2] = bit_buffer_read(self->bits, 6); + break; + case 1: + sf[0] = + sf[1] = bit_buffer_read(self->bits, 6); + sf[2] = bit_buffer_read(self->bits, 6); + break; + case 2: + sf[0] = + sf[1] = + sf[2] = bit_buffer_read(self->bits, 6); + break; + case 3: + sf[0] = bit_buffer_read(self->bits, 6); + sf[1] = + sf[2] = bit_buffer_read(self->bits, 6); + break; + } + } + } + if (mode == MODE_MONO) { + self->scale_factor[1][sb][0] = self->scale_factor[0][sb][0]; + self->scale_factor[1][sb][1] = self->scale_factor[0][sb][1]; + self->scale_factor[1][sb][2] = self->scale_factor[0][sb][2]; + } + } + + // Coefficient input and reconstruction + int out_pos = 0; + for (int part = 0; part < 3; part++) { + for (int granule = 0; granule < 4; granule++) { + + // Read the samples + for (int sb = 0; sb < bound; sb++) { + read_samples(self, 0, sb, part); + read_samples(self, 1, sb, part); + } + for (int sb = bound; sb < sblimit; sb++) { + read_samples(self, 0, sb, part); + self->sample[1][sb][0] = self->sample[0][sb][0]; + self->sample[1][sb][1] = self->sample[0][sb][1]; + self->sample[1][sb][2] = self->sample[0][sb][2]; + } + for (int sb = sblimit; sb < 32; sb++) { + self->sample[0][sb][0] = 0; + self->sample[0][sb][1] = 0; + self->sample[0][sb][2] = 0; + self->sample[1][sb][0] = 0; + self->sample[1][sb][1] = 0; + self->sample[1][sb][2] = 0; + } + + // Synthesis loop + for (int p = 0; p < 3; p++) { + // Shifting step + self->v_pos = (self->v_pos - 64) & 1023; + + for (int ch = 0; ch < 2; ch++) { + matrix_transform(self->sample[ch], p, self->V, self->v_pos); + + // Build U, windowing, calculate output + memset(self->U, 0, sizeof(self->U)); + + int d_index = 512 - (self->v_pos >> 1); + int v_index = (self->v_pos % 128) >> 1; + while (v_index < 1024) { + for (int i = 0; i < 32; ++i) { + self->U[i] += self->D[d_index++] * self->V[v_index++]; + } + + v_index += 128-32; + d_index += 64-32; + } + + v_index = (128-32 + 1024) - v_index; + d_index -= (512 - 32); + while (v_index < 1024) { + for (int i = 0; i < 32; ++i) { + self->U[i] += self->D[d_index++] * self->V[v_index++]; + } + + v_index += 128-32; + d_index += 64-32; + } + + // Output samples + float *out_channel = ch == 0 + ? self->channel_left + : self->channel_right; + for (int j = 0; j < 32; j++) { + out_channel[out_pos + j] = (float)self->U[j] / 2147418112.0; + } + } // End of synthesis channel loop + out_pos += 32; + } // End of synthesis sub-block loop + + } // Decoding of the granule finished + } + + self->sample_rate = sample_rate; + return frame_size; +} + +const quantizer_spec_t *read_allocation(mp2_decoder_t *self, int sb, int tab3) { + int tab4 = QUANT_LUT_STEP_3[tab3][sb]; + int qtab = QUANT_LUT_STEP4[tab4 & 15][bit_buffer_read(self->bits, tab4 >> 4)]; + return qtab ? (&QUANT_TAB[qtab - 1]) : 0; +} + +void read_samples(mp2_decoder_t *self, int ch, int sb, int part) { + const quantizer_spec_t *q = self->allocation[ch][sb]; + int sf = self->scale_factor[ch][sb][part]; + int *sample = self->sample[ch][sb]; + int val = 0; + + if (!q) { + // No bits allocated for this subband + sample[0] = sample[1] = sample[2] = 0; + return; + } + + // Resolve scalefactor + if (sf == 63) { + sf = 0; + } + else { + int shift = (sf / 3)|0; + sf = (SCALEFACTOR_BASE[sf % 3] + ((1 << shift) >> 1)) >> shift; + } + + // Decode samples + int adj = q->levels; + if (q->group) { + // Decode grouped samples + val = bit_buffer_read(self->bits, q->bits); + sample[0] = val % adj; + val /= adj; + sample[1] = val % adj; + sample[2] = val / adj; + } + else { + // Decode direct samples + sample[0] = bit_buffer_read(self->bits, q->bits); + sample[1] = bit_buffer_read(self->bits, q->bits); + sample[2] = bit_buffer_read(self->bits, q->bits); + } + + // Postmultiply samples + int scale = 65536 / (adj + 1); + adj = ((adj + 1) >> 1) - 1; + + val = (adj - sample[0]) * scale; + sample[0] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12; + + val = (adj - sample[1]) * scale; + sample[1] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12; + + val = (adj - sample[2]) * scale; + sample[2] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12; +} + +void matrix_transform(int s[32][3], int ss, float *d, int dp) { + float t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, + t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24, + t25, t26, t27, t28, t29, t30, t31, t32, t33; + + t01 = s[ 0][ss] + s[31][ss]; t02 = (float)(s[ 0][ss] - s[31][ss]) * 0.500602998235; + t03 = s[ 1][ss] + s[30][ss]; t04 = (float)(s[ 1][ss] - s[30][ss]) * 0.505470959898; + t05 = s[ 2][ss] + s[29][ss]; t06 = (float)(s[ 2][ss] - s[29][ss]) * 0.515447309923; + t07 = s[ 3][ss] + s[28][ss]; t08 = (float)(s[ 3][ss] - s[28][ss]) * 0.53104259109; + t09 = s[ 4][ss] + s[27][ss]; t10 = (float)(s[ 4][ss] - s[27][ss]) * 0.553103896034; + t11 = s[ 5][ss] + s[26][ss]; t12 = (float)(s[ 5][ss] - s[26][ss]) * 0.582934968206; + t13 = s[ 6][ss] + s[25][ss]; t14 = (float)(s[ 6][ss] - s[25][ss]) * 0.622504123036; + t15 = s[ 7][ss] + s[24][ss]; t16 = (float)(s[ 7][ss] - s[24][ss]) * 0.674808341455; + t17 = s[ 8][ss] + s[23][ss]; t18 = (float)(s[ 8][ss] - s[23][ss]) * 0.744536271002; + t19 = s[ 9][ss] + s[22][ss]; t20 = (float)(s[ 9][ss] - s[22][ss]) * 0.839349645416; + t21 = s[10][ss] + s[21][ss]; t22 = (float)(s[10][ss] - s[21][ss]) * 0.972568237862; + t23 = s[11][ss] + s[20][ss]; t24 = (float)(s[11][ss] - s[20][ss]) * 1.16943993343; + t25 = s[12][ss] + s[19][ss]; t26 = (float)(s[12][ss] - s[19][ss]) * 1.48416461631; + t27 = s[13][ss] + s[18][ss]; t28 = (float)(s[13][ss] - s[18][ss]) * 2.05778100995; + t29 = s[14][ss] + s[17][ss]; t30 = (float)(s[14][ss] - s[17][ss]) * 3.40760841847; + t31 = s[15][ss] + s[16][ss]; t32 = (float)(s[15][ss] - s[16][ss]) * 10.1900081235; + + t33 = t01 + t31; t31 = (t01 - t31) * 0.502419286188; + t01 = t03 + t29; t29 = (t03 - t29) * 0.52249861494; + t03 = t05 + t27; t27 = (t05 - t27) * 0.566944034816; + t05 = t07 + t25; t25 = (t07 - t25) * 0.64682178336; + t07 = t09 + t23; t23 = (t09 - t23) * 0.788154623451; + t09 = t11 + t21; t21 = (t11 - t21) * 1.06067768599; + t11 = t13 + t19; t19 = (t13 - t19) * 1.72244709824; + t13 = t15 + t17; t17 = (t15 - t17) * 5.10114861869; + t15 = t33 + t13; t13 = (t33 - t13) * 0.509795579104; + t33 = t01 + t11; t01 = (t01 - t11) * 0.601344886935; + t11 = t03 + t09; t09 = (t03 - t09) * 0.899976223136; + t03 = t05 + t07; t07 = (t05 - t07) * 2.56291544774; + t05 = t15 + t03; t15 = (t15 - t03) * 0.541196100146; + t03 = t33 + t11; t11 = (t33 - t11) * 1.30656296488; + t33 = t05 + t03; t05 = (t05 - t03) * 0.707106781187; + t03 = t15 + t11; t15 = (t15 - t11) * 0.707106781187; + t03 += t15; + t11 = t13 + t07; t13 = (t13 - t07) * 0.541196100146; + t07 = t01 + t09; t09 = (t01 - t09) * 1.30656296488; + t01 = t11 + t07; t07 = (t11 - t07) * 0.707106781187; + t11 = t13 + t09; t13 = (t13 - t09) * 0.707106781187; + t11 += t13; t01 += t11; + t11 += t07; t07 += t13; + t09 = t31 + t17; t31 = (t31 - t17) * 0.509795579104; + t17 = t29 + t19; t29 = (t29 - t19) * 0.601344886935; + t19 = t27 + t21; t21 = (t27 - t21) * 0.899976223136; + t27 = t25 + t23; t23 = (t25 - t23) * 2.56291544774; + t25 = t09 + t27; t09 = (t09 - t27) * 0.541196100146; + t27 = t17 + t19; t19 = (t17 - t19) * 1.30656296488; + t17 = t25 + t27; t27 = (t25 - t27) * 0.707106781187; + t25 = t09 + t19; t19 = (t09 - t19) * 0.707106781187; + t25 += t19; + t09 = t31 + t23; t31 = (t31 - t23) * 0.541196100146; + t23 = t29 + t21; t21 = (t29 - t21) * 1.30656296488; + t29 = t09 + t23; t23 = (t09 - t23) * 0.707106781187; + t09 = t31 + t21; t31 = (t31 - t21) * 0.707106781187; + t09 += t31; t29 += t09; t09 += t23; t23 += t31; + t17 += t29; t29 += t25; t25 += t09; t09 += t27; + t27 += t23; t23 += t19; t19 += t31; + t21 = t02 + t32; t02 = (t02 - t32) * 0.502419286188; + t32 = t04 + t30; t04 = (t04 - t30) * 0.52249861494; + t30 = t06 + t28; t28 = (t06 - t28) * 0.566944034816; + t06 = t08 + t26; t08 = (t08 - t26) * 0.64682178336; + t26 = t10 + t24; t10 = (t10 - t24) * 0.788154623451; + t24 = t12 + t22; t22 = (t12 - t22) * 1.06067768599; + t12 = t14 + t20; t20 = (t14 - t20) * 1.72244709824; + t14 = t16 + t18; t16 = (t16 - t18) * 5.10114861869; + t18 = t21 + t14; t14 = (t21 - t14) * 0.509795579104; + t21 = t32 + t12; t32 = (t32 - t12) * 0.601344886935; + t12 = t30 + t24; t24 = (t30 - t24) * 0.899976223136; + t30 = t06 + t26; t26 = (t06 - t26) * 2.56291544774; + t06 = t18 + t30; t18 = (t18 - t30) * 0.541196100146; + t30 = t21 + t12; t12 = (t21 - t12) * 1.30656296488; + t21 = t06 + t30; t30 = (t06 - t30) * 0.707106781187; + t06 = t18 + t12; t12 = (t18 - t12) * 0.707106781187; + t06 += t12; + t18 = t14 + t26; t26 = (t14 - t26) * 0.541196100146; + t14 = t32 + t24; t24 = (t32 - t24) * 1.30656296488; + t32 = t18 + t14; t14 = (t18 - t14) * 0.707106781187; + t18 = t26 + t24; t24 = (t26 - t24) * 0.707106781187; + t18 += t24; t32 += t18; + t18 += t14; t26 = t14 + t24; + t14 = t02 + t16; t02 = (t02 - t16) * 0.509795579104; + t16 = t04 + t20; t04 = (t04 - t20) * 0.601344886935; + t20 = t28 + t22; t22 = (t28 - t22) * 0.899976223136; + t28 = t08 + t10; t10 = (t08 - t10) * 2.56291544774; + t08 = t14 + t28; t14 = (t14 - t28) * 0.541196100146; + t28 = t16 + t20; t20 = (t16 - t20) * 1.30656296488; + t16 = t08 + t28; t28 = (t08 - t28) * 0.707106781187; + t08 = t14 + t20; t20 = (t14 - t20) * 0.707106781187; + t08 += t20; + t14 = t02 + t10; t02 = (t02 - t10) * 0.541196100146; + t10 = t04 + t22; t22 = (t04 - t22) * 1.30656296488; + t04 = t14 + t10; t10 = (t14 - t10) * 0.707106781187; + t14 = t02 + t22; t02 = (t02 - t22) * 0.707106781187; + t14 += t02; t04 += t14; t14 += t10; t10 += t02; + t16 += t04; t04 += t08; t08 += t14; t14 += t28; + t28 += t10; t10 += t20; t20 += t02; t21 += t16; + t16 += t32; t32 += t04; t04 += t06; t06 += t08; + t08 += t18; t18 += t14; t14 += t30; t30 += t28; + t28 += t26; t26 += t10; t10 += t12; t12 += t20; + t20 += t24; t24 += t02; + + d[dp + 48] = -t33; + d[dp + 49] = d[dp + 47] = -t21; + d[dp + 50] = d[dp + 46] = -t17; + d[dp + 51] = d[dp + 45] = -t16; + d[dp + 52] = d[dp + 44] = -t01; + d[dp + 53] = d[dp + 43] = -t32; + d[dp + 54] = d[dp + 42] = -t29; + d[dp + 55] = d[dp + 41] = -t04; + d[dp + 56] = d[dp + 40] = -t03; + d[dp + 57] = d[dp + 39] = -t06; + d[dp + 58] = d[dp + 38] = -t25; + d[dp + 59] = d[dp + 37] = -t08; + d[dp + 60] = d[dp + 36] = -t11; + d[dp + 61] = d[dp + 35] = -t18; + d[dp + 62] = d[dp + 34] = -t09; + d[dp + 63] = d[dp + 33] = -t14; + d[dp + 32] = -t05; + d[dp + 0] = t05; d[dp + 31] = -t30; + d[dp + 1] = t30; d[dp + 30] = -t27; + d[dp + 2] = t27; d[dp + 29] = -t28; + d[dp + 3] = t28; d[dp + 28] = -t07; + d[dp + 4] = t07; d[dp + 27] = -t26; + d[dp + 5] = t26; d[dp + 26] = -t23; + d[dp + 6] = t23; d[dp + 25] = -t10; + d[dp + 7] = t10; d[dp + 24] = -t15; + d[dp + 8] = t15; d[dp + 23] = -t12; + d[dp + 9] = t12; d[dp + 22] = -t19; + d[dp + 10] = t19; d[dp + 21] = -t20; + d[dp + 11] = t20; d[dp + 20] = -t13; + d[dp + 12] = t13; d[dp + 19] = -t24; + d[dp + 13] = t24; d[dp + 18] = -t31; + d[dp + 14] = t31; d[dp + 17] = -t02; + d[dp + 15] = t02; d[dp + 16] = 0.0; +}; + diff --git a/src/wasm/mp2.h b/src/wasm/mp2.h new file mode 100644 index 00000000..069b2a73 --- /dev/null +++ b/src/wasm/mp2.h @@ -0,0 +1,22 @@ +#ifndef MP2_H +#define MP2_H + +#include +#include +#include "buffer.h" + +typedef struct mp2_decoder_t mp2_decoder_t; + +mp2_decoder_t *mp2_decoder_create(unsigned int buffer_size, bit_buffer_mode_t buffer_mode); +void mp2_decoder_destroy(mp2_decoder_t *self); +void *mp2_decoder_get_write_ptr(mp2_decoder_t *self, unsigned int byte_size); +int mp2_decoder_get_index(mp2_decoder_t *self); +void mp2_decoder_set_index(mp2_decoder_t *self, unsigned int index); +void mp2_decoder_did_write(mp2_decoder_t *self, unsigned int byte_size); + +void *mp2_decoder_get_left_channel_ptr(mp2_decoder_t *self); +void *mp2_decoder_get_right_channel_ptr(mp2_decoder_t *self); +int mp2_decoder_get_sample_rate(mp2_decoder_t *self); +int mp2_decoder_decode(mp2_decoder_t *self); + +#endif diff --git a/src/wasm/mpeg1.c b/src/wasm/mpeg1.c new file mode 100644 index 00000000..0a11c760 --- /dev/null +++ b/src/wasm/mpeg1.c @@ -0,0 +1,1746 @@ +#include +#include +#include "mpeg1.h" + +static const float PICTURE_RATE[] = { + 0.000, 23.976, 24.000, 25.000, 29.970, 30.000, 50.000, 59.940, + 60.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000 +}; + +static const uint8_t ZIG_ZAG[] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const uint8_t DEFAULT_INTRA_QUANT_MATRIX[] = { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +}; + +static const uint8_t DEFAULT_NON_INTRA_QUANT_MATRIX[] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16 +}; + +static const uint8_t PREMULTIPLIER_MATRIX[] = { + 32, 44, 42, 38, 32, 25, 17, 9, + 44, 62, 58, 52, 44, 35, 24, 12, + 42, 58, 55, 49, 42, 33, 23, 12, + 38, 52, 49, 44, 38, 30, 20, 10, + 32, 44, 42, 38, 32, 25, 17, 9, + 25, 35, 33, 30, 25, 20, 14, 7, + 17, 24, 23, 20, 17, 14, 9, 5, + 9, 12, 12, 10, 9, 7, 5, 2 +}; + +// MPEG-1 VLC + +// macroblock_stuffing decodes as 34. +// macroblock_escape decodes as 35. + +static const int MACROBLOCK_ADDRESS_INCREMENT[] = { + 1*3, 2*3, 0, // 0 + 3*3, 4*3, 0, // 1 0 + 0, 0, 1, // 2 1. + 5*3, 6*3, 0, // 3 00 + 7*3, 8*3, 0, // 4 01 + 9*3, 10*3, 0, // 5 000 + 11*3, 12*3, 0, // 6 001 + 0, 0, 3, // 7 010. + 0, 0, 2, // 8 011. + 13*3, 14*3, 0, // 9 0000 + 15*3, 16*3, 0, // 10 0001 + 0, 0, 5, // 11 0010. + 0, 0, 4, // 12 0011. + 17*3, 18*3, 0, // 13 0000 0 + 19*3, 20*3, 0, // 14 0000 1 + 0, 0, 7, // 15 0001 0. + 0, 0, 6, // 16 0001 1. + 21*3, 22*3, 0, // 17 0000 00 + 23*3, 24*3, 0, // 18 0000 01 + 25*3, 26*3, 0, // 19 0000 10 + 27*3, 28*3, 0, // 20 0000 11 + -1, 29*3, 0, // 21 0000 000 + -1, 30*3, 0, // 22 0000 001 + 31*3, 32*3, 0, // 23 0000 010 + 33*3, 34*3, 0, // 24 0000 011 + 35*3, 36*3, 0, // 25 0000 100 + 37*3, 38*3, 0, // 26 0000 101 + 0, 0, 9, // 27 0000 110. + 0, 0, 8, // 28 0000 111. + 39*3, 40*3, 0, // 29 0000 0001 + 41*3, 42*3, 0, // 30 0000 0011 + 43*3, 44*3, 0, // 31 0000 0100 + 45*3, 46*3, 0, // 32 0000 0101 + 0, 0, 15, // 33 0000 0110. + 0, 0, 14, // 34 0000 0111. + 0, 0, 13, // 35 0000 1000. + 0, 0, 12, // 36 0000 1001. + 0, 0, 11, // 37 0000 1010. + 0, 0, 10, // 38 0000 1011. + 47*3, -1, 0, // 39 0000 0001 0 + -1, 48*3, 0, // 40 0000 0001 1 + 49*3, 50*3, 0, // 41 0000 0011 0 + 51*3, 52*3, 0, // 42 0000 0011 1 + 53*3, 54*3, 0, // 43 0000 0100 0 + 55*3, 56*3, 0, // 44 0000 0100 1 + 57*3, 58*3, 0, // 45 0000 0101 0 + 59*3, 60*3, 0, // 46 0000 0101 1 + 61*3, -1, 0, // 47 0000 0001 00 + -1, 62*3, 0, // 48 0000 0001 11 + 63*3, 64*3, 0, // 49 0000 0011 00 + 65*3, 66*3, 0, // 50 0000 0011 01 + 67*3, 68*3, 0, // 51 0000 0011 10 + 69*3, 70*3, 0, // 52 0000 0011 11 + 71*3, 72*3, 0, // 53 0000 0100 00 + 73*3, 74*3, 0, // 54 0000 0100 01 + 0, 0, 21, // 55 0000 0100 10. + 0, 0, 20, // 56 0000 0100 11. + 0, 0, 19, // 57 0000 0101 00. + 0, 0, 18, // 58 0000 0101 01. + 0, 0, 17, // 59 0000 0101 10. + 0, 0, 16, // 60 0000 0101 11. + 0, 0, 35, // 61 0000 0001 000. -- macroblock_escape + 0, 0, 34, // 62 0000 0001 111. -- macroblock_stuffing + 0, 0, 33, // 63 0000 0011 000. + 0, 0, 32, // 64 0000 0011 001. + 0, 0, 31, // 65 0000 0011 010. + 0, 0, 30, // 66 0000 0011 011. + 0, 0, 29, // 67 0000 0011 100. + 0, 0, 28, // 68 0000 0011 101. + 0, 0, 27, // 69 0000 0011 110. + 0, 0, 26, // 70 0000 0011 111. + 0, 0, 25, // 71 0000 0100 000. + 0, 0, 24, // 72 0000 0100 001. + 0, 0, 23, // 73 0000 0100 010. + 0, 0, 22 // 74 0000 0100 011. +}; + +// macroblock_type bitmap: +// 0x10 macroblock_quant +// 0x08 macroblock_motion_forward +// 0x04 macroblock_motion_backward +// 0x02 macrobkock_pattern +// 0x01 macroblock_intra +// + +static const int MACROBLOCK_TYPE_INTRA[] = { + 1*3, 2*3, 0, // 0 + -1, 3*3, 0, // 1 0 + 0, 0, 0x01, // 2 1. + 0, 0, 0x11 // 3 01. +}; + +static const int MACROBLOCK_TYPE_PREDICTIVE[] = { + 1*3, 2*3, 0, // 0 + 3*3, 4*3, 0, // 1 0 + 0, 0, 0x0a, // 2 1. + 5*3, 6*3, 0, // 3 00 + 0, 0, 0x02, // 4 01. + 7*3, 8*3, 0, // 5 000 + 0, 0, 0x08, // 6 001. + 9*3, 10*3, 0, // 7 0000 + 11*3, 12*3, 0, // 8 0001 + -1, 13*3, 0, // 9 00000 + 0, 0, 0x12, // 10 00001. + 0, 0, 0x1a, // 11 00010. + 0, 0, 0x01, // 12 00011. + 0, 0, 0x11 // 13 000001. +}; + +static const int MACROBLOCK_TYPE_B[] = { + 1*3, 2*3, 0, // 0 + 3*3, 5*3, 0, // 1 0 + 4*3, 6*3, 0, // 2 1 + 8*3, 7*3, 0, // 3 00 + 0, 0, 0x0c, // 4 10. + 9*3, 10*3, 0, // 5 01 + 0, 0, 0x0e, // 6 11. + 13*3, 14*3, 0, // 7 001 + 12*3, 11*3, 0, // 8 000 + 0, 0, 0x04, // 9 010. + 0, 0, 0x06, // 10 011. + 18*3, 16*3, 0, // 11 0001 + 15*3, 17*3, 0, // 12 0000 + 0, 0, 0x08, // 13 0010. + 0, 0, 0x0a, // 14 0011. + -1, 19*3, 0, // 15 00000 + 0, 0, 0x01, // 16 00011. + 20*3, 21*3, 0, // 17 00001 + 0, 0, 0x1e, // 18 00010. + 0, 0, 0x11, // 19 000001. + 0, 0, 0x16, // 20 000010. + 0, 0, 0x1a // 21 000011. +}; + +static const int *MACROBLOCK_TYPE[] = { + NULL, + MACROBLOCK_TYPE_INTRA, + MACROBLOCK_TYPE_PREDICTIVE, + MACROBLOCK_TYPE_B +}; + +static const int CODE_BLOCK_PATTERN[] = { + 2*3, 1*3, 0, // 0 + 3*3, 6*3, 0, // 1 1 + 4*3, 5*3, 0, // 2 0 + 8*3, 11*3, 0, // 3 10 + 12*3, 13*3, 0, // 4 00 + 9*3, 7*3, 0, // 5 01 + 10*3, 14*3, 0, // 6 11 + 20*3, 19*3, 0, // 7 011 + 18*3, 16*3, 0, // 8 100 + 23*3, 17*3, 0, // 9 010 + 27*3, 25*3, 0, // 10 110 + 21*3, 28*3, 0, // 11 101 + 15*3, 22*3, 0, // 12 000 + 24*3, 26*3, 0, // 13 001 + 0, 0, 60, // 14 111. + 35*3, 40*3, 0, // 15 0000 + 44*3, 48*3, 0, // 16 1001 + 38*3, 36*3, 0, // 17 0101 + 42*3, 47*3, 0, // 18 1000 + 29*3, 31*3, 0, // 19 0111 + 39*3, 32*3, 0, // 20 0110 + 0, 0, 32, // 21 1010. + 45*3, 46*3, 0, // 22 0001 + 33*3, 41*3, 0, // 23 0100 + 43*3, 34*3, 0, // 24 0010 + 0, 0, 4, // 25 1101. + 30*3, 37*3, 0, // 26 0011 + 0, 0, 8, // 27 1100. + 0, 0, 16, // 28 1011. + 0, 0, 44, // 29 0111 0. + 50*3, 56*3, 0, // 30 0011 0 + 0, 0, 28, // 31 0111 1. + 0, 0, 52, // 32 0110 1. + 0, 0, 62, // 33 0100 0. + 61*3, 59*3, 0, // 34 0010 1 + 52*3, 60*3, 0, // 35 0000 0 + 0, 0, 1, // 36 0101 1. + 55*3, 54*3, 0, // 37 0011 1 + 0, 0, 61, // 38 0101 0. + 0, 0, 56, // 39 0110 0. + 57*3, 58*3, 0, // 40 0000 1 + 0, 0, 2, // 41 0100 1. + 0, 0, 40, // 42 1000 0. + 51*3, 62*3, 0, // 43 0010 0 + 0, 0, 48, // 44 1001 0. + 64*3, 63*3, 0, // 45 0001 0 + 49*3, 53*3, 0, // 46 0001 1 + 0, 0, 20, // 47 1000 1. + 0, 0, 12, // 48 1001 1. + 80*3, 83*3, 0, // 49 0001 10 + 0, 0, 63, // 50 0011 00. + 77*3, 75*3, 0, // 51 0010 00 + 65*3, 73*3, 0, // 52 0000 00 + 84*3, 66*3, 0, // 53 0001 11 + 0, 0, 24, // 54 0011 11. + 0, 0, 36, // 55 0011 10. + 0, 0, 3, // 56 0011 01. + 69*3, 87*3, 0, // 57 0000 10 + 81*3, 79*3, 0, // 58 0000 11 + 68*3, 71*3, 0, // 59 0010 11 + 70*3, 78*3, 0, // 60 0000 01 + 67*3, 76*3, 0, // 61 0010 10 + 72*3, 74*3, 0, // 62 0010 01 + 86*3, 85*3, 0, // 63 0001 01 + 88*3, 82*3, 0, // 64 0001 00 + -1, 94*3, 0, // 65 0000 000 + 95*3, 97*3, 0, // 66 0001 111 + 0, 0, 33, // 67 0010 100. + 0, 0, 9, // 68 0010 110. + 106*3, 110*3, 0, // 69 0000 100 + 102*3, 116*3, 0, // 70 0000 010 + 0, 0, 5, // 71 0010 111. + 0, 0, 10, // 72 0010 010. + 93*3, 89*3, 0, // 73 0000 001 + 0, 0, 6, // 74 0010 011. + 0, 0, 18, // 75 0010 001. + 0, 0, 17, // 76 0010 101. + 0, 0, 34, // 77 0010 000. + 113*3, 119*3, 0, // 78 0000 011 + 103*3, 104*3, 0, // 79 0000 111 + 90*3, 92*3, 0, // 80 0001 100 + 109*3, 107*3, 0, // 81 0000 110 + 117*3, 118*3, 0, // 82 0001 001 + 101*3, 99*3, 0, // 83 0001 101 + 98*3, 96*3, 0, // 84 0001 110 + 100*3, 91*3, 0, // 85 0001 011 + 114*3, 115*3, 0, // 86 0001 010 + 105*3, 108*3, 0, // 87 0000 101 + 112*3, 111*3, 0, // 88 0001 000 + 121*3, 125*3, 0, // 89 0000 0011 + 0, 0, 41, // 90 0001 1000. + 0, 0, 14, // 91 0001 0111. + 0, 0, 21, // 92 0001 1001. + 124*3, 122*3, 0, // 93 0000 0010 + 120*3, 123*3, 0, // 94 0000 0001 + 0, 0, 11, // 95 0001 1110. + 0, 0, 19, // 96 0001 1101. + 0, 0, 7, // 97 0001 1111. + 0, 0, 35, // 98 0001 1100. + 0, 0, 13, // 99 0001 1011. + 0, 0, 50, // 100 0001 0110. + 0, 0, 49, // 101 0001 1010. + 0, 0, 58, // 102 0000 0100. + 0, 0, 37, // 103 0000 1110. + 0, 0, 25, // 104 0000 1111. + 0, 0, 45, // 105 0000 1010. + 0, 0, 57, // 106 0000 1000. + 0, 0, 26, // 107 0000 1101. + 0, 0, 29, // 108 0000 1011. + 0, 0, 38, // 109 0000 1100. + 0, 0, 53, // 110 0000 1001. + 0, 0, 23, // 111 0001 0001. + 0, 0, 43, // 112 0001 0000. + 0, 0, 46, // 113 0000 0110. + 0, 0, 42, // 114 0001 0100. + 0, 0, 22, // 115 0001 0101. + 0, 0, 54, // 116 0000 0101. + 0, 0, 51, // 117 0001 0010. + 0, 0, 15, // 118 0001 0011. + 0, 0, 30, // 119 0000 0111. + 0, 0, 39, // 120 0000 0001 0. + 0, 0, 47, // 121 0000 0011 0. + 0, 0, 55, // 122 0000 0010 1. + 0, 0, 27, // 123 0000 0001 1. + 0, 0, 59, // 124 0000 0010 0. + 0, 0, 31 // 125 0000 0011 1. +}; + +static const int MOTION[] = { + 1*3, 2*3, 0, // 0 + 4*3, 3*3, 0, // 1 0 + 0, 0, 0, // 2 1. + 6*3, 5*3, 0, // 3 01 + 8*3, 7*3, 0, // 4 00 + 0, 0, -1, // 5 011. + 0, 0, 1, // 6 010. + 9*3, 10*3, 0, // 7 001 + 12*3, 11*3, 0, // 8 000 + 0, 0, 2, // 9 0010. + 0, 0, -2, // 10 0011. + 14*3, 15*3, 0, // 11 0001 + 16*3, 13*3, 0, // 12 0000 + 20*3, 18*3, 0, // 13 0000 1 + 0, 0, 3, // 14 0001 0. + 0, 0, -3, // 15 0001 1. + 17*3, 19*3, 0, // 16 0000 0 + -1, 23*3, 0, // 17 0000 00 + 27*3, 25*3, 0, // 18 0000 11 + 26*3, 21*3, 0, // 19 0000 01 + 24*3, 22*3, 0, // 20 0000 10 + 32*3, 28*3, 0, // 21 0000 011 + 29*3, 31*3, 0, // 22 0000 101 + -1, 33*3, 0, // 23 0000 001 + 36*3, 35*3, 0, // 24 0000 100 + 0, 0, -4, // 25 0000 111. + 30*3, 34*3, 0, // 26 0000 010 + 0, 0, 4, // 27 0000 110. + 0, 0, -7, // 28 0000 0111. + 0, 0, 5, // 29 0000 1010. + 37*3, 41*3, 0, // 30 0000 0100 + 0, 0, -5, // 31 0000 1011. + 0, 0, 7, // 32 0000 0110. + 38*3, 40*3, 0, // 33 0000 0011 + 42*3, 39*3, 0, // 34 0000 0101 + 0, 0, -6, // 35 0000 1001. + 0, 0, 6, // 36 0000 1000. + 51*3, 54*3, 0, // 37 0000 0100 0 + 50*3, 49*3, 0, // 38 0000 0011 0 + 45*3, 46*3, 0, // 39 0000 0101 1 + 52*3, 47*3, 0, // 40 0000 0011 1 + 43*3, 53*3, 0, // 41 0000 0100 1 + 44*3, 48*3, 0, // 42 0000 0101 0 + 0, 0, 10, // 43 0000 0100 10. + 0, 0, 9, // 44 0000 0101 00. + 0, 0, 8, // 45 0000 0101 10. + 0, 0, -8, // 46 0000 0101 11. + 57*3, 66*3, 0, // 47 0000 0011 11 + 0, 0, -9, // 48 0000 0101 01. + 60*3, 64*3, 0, // 49 0000 0011 01 + 56*3, 61*3, 0, // 50 0000 0011 00 + 55*3, 62*3, 0, // 51 0000 0100 00 + 58*3, 63*3, 0, // 52 0000 0011 10 + 0, 0, -10, // 53 0000 0100 11. + 59*3, 65*3, 0, // 54 0000 0100 01 + 0, 0, 12, // 55 0000 0100 000. + 0, 0, 16, // 56 0000 0011 000. + 0, 0, 13, // 57 0000 0011 110. + 0, 0, 14, // 58 0000 0011 100. + 0, 0, 11, // 59 0000 0100 010. + 0, 0, 15, // 60 0000 0011 010. + 0, 0, -16, // 61 0000 0011 001. + 0, 0, -12, // 62 0000 0100 001. + 0, 0, -14, // 63 0000 0011 101. + 0, 0, -15, // 64 0000 0011 011. + 0, 0, -11, // 65 0000 0100 011. + 0, 0, -13 // 66 0000 0011 111. +}; + +static const int DCT_DC_SIZE_LUMINANCE[] = { + 2*3, 1*3, 0, // 0 + 6*3, 5*3, 0, // 1 1 + 3*3, 4*3, 0, // 2 0 + 0, 0, 1, // 3 00. + 0, 0, 2, // 4 01. + 9*3, 8*3, 0, // 5 11 + 7*3, 10*3, 0, // 6 10 + 0, 0, 0, // 7 100. + 12*3, 11*3, 0, // 8 111 + 0, 0, 4, // 9 110. + 0, 0, 3, // 10 101. + 13*3, 14*3, 0, // 11 1111 + 0, 0, 5, // 12 1110. + 0, 0, 6, // 13 1111 0. + 16*3, 15*3, 0, // 14 1111 1 + 17*3, -1, 0, // 15 1111 11 + 0, 0, 7, // 16 1111 10. + 0, 0, 8 // 17 1111 110. +}; + +static const int DCT_DC_SIZE_CHROMINANCE[] = { + 2*3, 1*3, 0, // 0 + 4*3, 3*3, 0, // 1 1 + 6*3, 5*3, 0, // 2 0 + 8*3, 7*3, 0, // 3 11 + 0, 0, 2, // 4 10. + 0, 0, 1, // 5 01. + 0, 0, 0, // 6 00. + 10*3, 9*3, 0, // 7 111 + 0, 0, 3, // 8 110. + 12*3, 11*3, 0, // 9 1111 + 0, 0, 4, // 10 1110. + 14*3, 13*3, 0, // 11 1111 1 + 0, 0, 5, // 12 1111 0. + 16*3, 15*3, 0, // 13 1111 11 + 0, 0, 6, // 14 1111 10. + 17*3, -1, 0, // 15 1111 111 + 0, 0, 7, // 16 1111 110. + 0, 0, 8 // 17 1111 1110. +}; + +// dct_coeff bitmap: +// 0xff00 run +// 0x00ff level + +// Decoded values are unsigned. Sign bit follows in the stream. + +// Interpretation of the value 0x0001 +// for dc_coeff_first: run=0, level=1 +// for dc_coeff_next: If the next bit is 1: run=0, level=1 +// If the next bit is 0: end_of_block + +// escape decodes as 0xffff. + +static const int DCT_COEFF[] = { + 1*3, 2*3, 0, // 0 + 4*3, 3*3, 0, // 1 0 + 0, 0, 0x0001, // 2 1. + 7*3, 8*3, 0, // 3 01 + 6*3, 5*3, 0, // 4 00 + 13*3, 9*3, 0, // 5 001 + 11*3, 10*3, 0, // 6 000 + 14*3, 12*3, 0, // 7 010 + 0, 0, 0x0101, // 8 011. + 20*3, 22*3, 0, // 9 0011 + 18*3, 21*3, 0, // 10 0001 + 16*3, 19*3, 0, // 11 0000 + 0, 0, 0x0201, // 12 0101. + 17*3, 15*3, 0, // 13 0010 + 0, 0, 0x0002, // 14 0100. + 0, 0, 0x0003, // 15 0010 1. + 27*3, 25*3, 0, // 16 0000 0 + 29*3, 31*3, 0, // 17 0010 0 + 24*3, 26*3, 0, // 18 0001 0 + 32*3, 30*3, 0, // 19 0000 1 + 0, 0, 0x0401, // 20 0011 0. + 23*3, 28*3, 0, // 21 0001 1 + 0, 0, 0x0301, // 22 0011 1. + 0, 0, 0x0102, // 23 0001 10. + 0, 0, 0x0701, // 24 0001 00. + 0, 0, 0xffff, // 25 0000 01. -- escape + 0, 0, 0x0601, // 26 0001 01. + 37*3, 36*3, 0, // 27 0000 00 + 0, 0, 0x0501, // 28 0001 11. + 35*3, 34*3, 0, // 29 0010 00 + 39*3, 38*3, 0, // 30 0000 11 + 33*3, 42*3, 0, // 31 0010 01 + 40*3, 41*3, 0, // 32 0000 10 + 52*3, 50*3, 0, // 33 0010 010 + 54*3, 53*3, 0, // 34 0010 001 + 48*3, 49*3, 0, // 35 0010 000 + 43*3, 45*3, 0, // 36 0000 001 + 46*3, 44*3, 0, // 37 0000 000 + 0, 0, 0x0801, // 38 0000 111. + 0, 0, 0x0004, // 39 0000 110. + 0, 0, 0x0202, // 40 0000 100. + 0, 0, 0x0901, // 41 0000 101. + 51*3, 47*3, 0, // 42 0010 011 + 55*3, 57*3, 0, // 43 0000 0010 + 60*3, 56*3, 0, // 44 0000 0001 + 59*3, 58*3, 0, // 45 0000 0011 + 61*3, 62*3, 0, // 46 0000 0000 + 0, 0, 0x0a01, // 47 0010 0111. + 0, 0, 0x0d01, // 48 0010 0000. + 0, 0, 0x0006, // 49 0010 0001. + 0, 0, 0x0103, // 50 0010 0101. + 0, 0, 0x0005, // 51 0010 0110. + 0, 0, 0x0302, // 52 0010 0100. + 0, 0, 0x0b01, // 53 0010 0011. + 0, 0, 0x0c01, // 54 0010 0010. + 76*3, 75*3, 0, // 55 0000 0010 0 + 67*3, 70*3, 0, // 56 0000 0001 1 + 73*3, 71*3, 0, // 57 0000 0010 1 + 78*3, 74*3, 0, // 58 0000 0011 1 + 72*3, 77*3, 0, // 59 0000 0011 0 + 69*3, 64*3, 0, // 60 0000 0001 0 + 68*3, 63*3, 0, // 61 0000 0000 0 + 66*3, 65*3, 0, // 62 0000 0000 1 + 81*3, 87*3, 0, // 63 0000 0000 01 + 91*3, 80*3, 0, // 64 0000 0001 01 + 82*3, 79*3, 0, // 65 0000 0000 11 + 83*3, 86*3, 0, // 66 0000 0000 10 + 93*3, 92*3, 0, // 67 0000 0001 10 + 84*3, 85*3, 0, // 68 0000 0000 00 + 90*3, 94*3, 0, // 69 0000 0001 00 + 88*3, 89*3, 0, // 70 0000 0001 11 + 0, 0, 0x0203, // 71 0000 0010 11. + 0, 0, 0x0104, // 72 0000 0011 00. + 0, 0, 0x0007, // 73 0000 0010 10. + 0, 0, 0x0402, // 74 0000 0011 11. + 0, 0, 0x0502, // 75 0000 0010 01. + 0, 0, 0x1001, // 76 0000 0010 00. + 0, 0, 0x0f01, // 77 0000 0011 01. + 0, 0, 0x0e01, // 78 0000 0011 10. + 105*3, 107*3, 0, // 79 0000 0000 111 + 111*3, 114*3, 0, // 80 0000 0001 011 + 104*3, 97*3, 0, // 81 0000 0000 010 + 125*3, 119*3, 0, // 82 0000 0000 110 + 96*3, 98*3, 0, // 83 0000 0000 100 + -1, 123*3, 0, // 84 0000 0000 000 + 95*3, 101*3, 0, // 85 0000 0000 001 + 106*3, 121*3, 0, // 86 0000 0000 101 + 99*3, 102*3, 0, // 87 0000 0000 011 + 113*3, 103*3, 0, // 88 0000 0001 110 + 112*3, 116*3, 0, // 89 0000 0001 111 + 110*3, 100*3, 0, // 90 0000 0001 000 + 124*3, 115*3, 0, // 91 0000 0001 010 + 117*3, 122*3, 0, // 92 0000 0001 101 + 109*3, 118*3, 0, // 93 0000 0001 100 + 120*3, 108*3, 0, // 94 0000 0001 001 + 127*3, 136*3, 0, // 95 0000 0000 0010 + 139*3, 140*3, 0, // 96 0000 0000 1000 + 130*3, 126*3, 0, // 97 0000 0000 0101 + 145*3, 146*3, 0, // 98 0000 0000 1001 + 128*3, 129*3, 0, // 99 0000 0000 0110 + 0, 0, 0x0802, // 100 0000 0001 0001. + 132*3, 134*3, 0, // 101 0000 0000 0011 + 155*3, 154*3, 0, // 102 0000 0000 0111 + 0, 0, 0x0008, // 103 0000 0001 1101. + 137*3, 133*3, 0, // 104 0000 0000 0100 + 143*3, 144*3, 0, // 105 0000 0000 1110 + 151*3, 138*3, 0, // 106 0000 0000 1010 + 142*3, 141*3, 0, // 107 0000 0000 1111 + 0, 0, 0x000a, // 108 0000 0001 0011. + 0, 0, 0x0009, // 109 0000 0001 1000. + 0, 0, 0x000b, // 110 0000 0001 0000. + 0, 0, 0x1501, // 111 0000 0001 0110. + 0, 0, 0x0602, // 112 0000 0001 1110. + 0, 0, 0x0303, // 113 0000 0001 1100. + 0, 0, 0x1401, // 114 0000 0001 0111. + 0, 0, 0x0702, // 115 0000 0001 0101. + 0, 0, 0x1101, // 116 0000 0001 1111. + 0, 0, 0x1201, // 117 0000 0001 1010. + 0, 0, 0x1301, // 118 0000 0001 1001. + 148*3, 152*3, 0, // 119 0000 0000 1101 + 0, 0, 0x0403, // 120 0000 0001 0010. + 153*3, 150*3, 0, // 121 0000 0000 1011 + 0, 0, 0x0105, // 122 0000 0001 1011. + 131*3, 135*3, 0, // 123 0000 0000 0001 + 0, 0, 0x0204, // 124 0000 0001 0100. + 149*3, 147*3, 0, // 125 0000 0000 1100 + 172*3, 173*3, 0, // 126 0000 0000 0101 1 + 162*3, 158*3, 0, // 127 0000 0000 0010 0 + 170*3, 161*3, 0, // 128 0000 0000 0110 0 + 168*3, 166*3, 0, // 129 0000 0000 0110 1 + 157*3, 179*3, 0, // 130 0000 0000 0101 0 + 169*3, 167*3, 0, // 131 0000 0000 0001 0 + 174*3, 171*3, 0, // 132 0000 0000 0011 0 + 178*3, 177*3, 0, // 133 0000 0000 0100 1 + 156*3, 159*3, 0, // 134 0000 0000 0011 1 + 164*3, 165*3, 0, // 135 0000 0000 0001 1 + 183*3, 182*3, 0, // 136 0000 0000 0010 1 + 175*3, 176*3, 0, // 137 0000 0000 0100 0 + 0, 0, 0x0107, // 138 0000 0000 1010 1. + 0, 0, 0x0a02, // 139 0000 0000 1000 0. + 0, 0, 0x0902, // 140 0000 0000 1000 1. + 0, 0, 0x1601, // 141 0000 0000 1111 1. + 0, 0, 0x1701, // 142 0000 0000 1111 0. + 0, 0, 0x1901, // 143 0000 0000 1110 0. + 0, 0, 0x1801, // 144 0000 0000 1110 1. + 0, 0, 0x0503, // 145 0000 0000 1001 0. + 0, 0, 0x0304, // 146 0000 0000 1001 1. + 0, 0, 0x000d, // 147 0000 0000 1100 1. + 0, 0, 0x000c, // 148 0000 0000 1101 0. + 0, 0, 0x000e, // 149 0000 0000 1100 0. + 0, 0, 0x000f, // 150 0000 0000 1011 1. + 0, 0, 0x0205, // 151 0000 0000 1010 0. + 0, 0, 0x1a01, // 152 0000 0000 1101 1. + 0, 0, 0x0106, // 153 0000 0000 1011 0. + 180*3, 181*3, 0, // 154 0000 0000 0111 1 + 160*3, 163*3, 0, // 155 0000 0000 0111 0 + 196*3, 199*3, 0, // 156 0000 0000 0011 10 + 0, 0, 0x001b, // 157 0000 0000 0101 00. + 203*3, 185*3, 0, // 158 0000 0000 0010 01 + 202*3, 201*3, 0, // 159 0000 0000 0011 11 + 0, 0, 0x0013, // 160 0000 0000 0111 00. + 0, 0, 0x0016, // 161 0000 0000 0110 01. + 197*3, 207*3, 0, // 162 0000 0000 0010 00 + 0, 0, 0x0012, // 163 0000 0000 0111 01. + 191*3, 192*3, 0, // 164 0000 0000 0001 10 + 188*3, 190*3, 0, // 165 0000 0000 0001 11 + 0, 0, 0x0014, // 166 0000 0000 0110 11. + 184*3, 194*3, 0, // 167 0000 0000 0001 01 + 0, 0, 0x0015, // 168 0000 0000 0110 10. + 186*3, 193*3, 0, // 169 0000 0000 0001 00 + 0, 0, 0x0017, // 170 0000 0000 0110 00. + 204*3, 198*3, 0, // 171 0000 0000 0011 01 + 0, 0, 0x0019, // 172 0000 0000 0101 10. + 0, 0, 0x0018, // 173 0000 0000 0101 11. + 200*3, 205*3, 0, // 174 0000 0000 0011 00 + 0, 0, 0x001f, // 175 0000 0000 0100 00. + 0, 0, 0x001e, // 176 0000 0000 0100 01. + 0, 0, 0x001c, // 177 0000 0000 0100 11. + 0, 0, 0x001d, // 178 0000 0000 0100 10. + 0, 0, 0x001a, // 179 0000 0000 0101 01. + 0, 0, 0x0011, // 180 0000 0000 0111 10. + 0, 0, 0x0010, // 181 0000 0000 0111 11. + 189*3, 206*3, 0, // 182 0000 0000 0010 11 + 187*3, 195*3, 0, // 183 0000 0000 0010 10 + 218*3, 211*3, 0, // 184 0000 0000 0001 010 + 0, 0, 0x0025, // 185 0000 0000 0010 011. + 215*3, 216*3, 0, // 186 0000 0000 0001 000 + 0, 0, 0x0024, // 187 0000 0000 0010 100. + 210*3, 212*3, 0, // 188 0000 0000 0001 110 + 0, 0, 0x0022, // 189 0000 0000 0010 110. + 213*3, 209*3, 0, // 190 0000 0000 0001 111 + 221*3, 222*3, 0, // 191 0000 0000 0001 100 + 219*3, 208*3, 0, // 192 0000 0000 0001 101 + 217*3, 214*3, 0, // 193 0000 0000 0001 001 + 223*3, 220*3, 0, // 194 0000 0000 0001 011 + 0, 0, 0x0023, // 195 0000 0000 0010 101. + 0, 0, 0x010b, // 196 0000 0000 0011 100. + 0, 0, 0x0028, // 197 0000 0000 0010 000. + 0, 0, 0x010c, // 198 0000 0000 0011 011. + 0, 0, 0x010a, // 199 0000 0000 0011 101. + 0, 0, 0x0020, // 200 0000 0000 0011 000. + 0, 0, 0x0108, // 201 0000 0000 0011 111. + 0, 0, 0x0109, // 202 0000 0000 0011 110. + 0, 0, 0x0026, // 203 0000 0000 0010 010. + 0, 0, 0x010d, // 204 0000 0000 0011 010. + 0, 0, 0x010e, // 205 0000 0000 0011 001. + 0, 0, 0x0021, // 206 0000 0000 0010 111. + 0, 0, 0x0027, // 207 0000 0000 0010 001. + 0, 0, 0x1f01, // 208 0000 0000 0001 1011. + 0, 0, 0x1b01, // 209 0000 0000 0001 1111. + 0, 0, 0x1e01, // 210 0000 0000 0001 1100. + 0, 0, 0x1002, // 211 0000 0000 0001 0101. + 0, 0, 0x1d01, // 212 0000 0000 0001 1101. + 0, 0, 0x1c01, // 213 0000 0000 0001 1110. + 0, 0, 0x010f, // 214 0000 0000 0001 0011. + 0, 0, 0x0112, // 215 0000 0000 0001 0000. + 0, 0, 0x0111, // 216 0000 0000 0001 0001. + 0, 0, 0x0110, // 217 0000 0000 0001 0010. + 0, 0, 0x0603, // 218 0000 0000 0001 0100. + 0, 0, 0x0b02, // 219 0000 0000 0001 1010. + 0, 0, 0x0e02, // 220 0000 0000 0001 0111. + 0, 0, 0x0d02, // 221 0000 0000 0001 1000. + 0, 0, 0x0c02, // 222 0000 0000 0001 1001. + 0, 0, 0x0f02 // 223 0000 0000 0001 0110. +}; + +static const int PICTURE_TYPE_INTRA = 1; +static const int PICTURE_TYPE_PREDICTIVE = 2; +static const int PICTURE_TYPE_B = 3; + +static const int START_SEQUENCE = 0xB3; +static const int START_SLICE_FIRST = 0x01; +static const int START_SLICE_LAST = 0xAF; +static const int START_PICTURE = 0x00; +static const int START_EXTENSION = 0xB5; +static const int START_USER_DATA = 0xB2; + + +typedef struct mpeg1_planes_t { + uint8_t *y; + uint8_t *cr; + uint8_t *cb; +} mpeg1_planes_t; + +typedef struct mpeg1_decoder_t { + float frame_rate; + int width; + int height; + int mb_width; + int mb_height; + int mb_size; + + int coded_width; + int coded_height; + int coded_size; + + int half_width; + int half_height; + + int picture_type; + int full_pel_forward; + int forward_f_code; + int forward_r_size; + int forward_f; + + int has_sequence_header; + + int quantizer_scale; + int slice_begin; + int macroblock_address; + + int mb_row; + int mb_col; + + int macroblock_type; + int macroblock_intra; + int macroblock_motion_fw; + + int motion_fw_h; + int motion_fw_v; + int motion_fw_h_prev; + int motion_fw_v_prev; + + int dc_predictor_y; + int dc_predictor_cr; + int dc_predictor_cb; + + bit_buffer_t *bits; + + mpeg1_planes_t planes_current; + mpeg1_planes_t planes_forward; + + int block_data[64]; + uint8_t intra_quant_matrix[64]; + uint8_t non_intra_quant_matrix[64]; +} mpeg1_decoder_t; + + +void decode_sequence_header(mpeg1_decoder_t *self); +void decode_picture(mpeg1_decoder_t *self); +void init_buffers(mpeg1_decoder_t *self); +void decode_slice(mpeg1_decoder_t *self, int slice); +void decode_macroblock(mpeg1_decoder_t *self); +void decode_motion_vectors(mpeg1_decoder_t *self); +void copy_macroblock(mpeg1_decoder_t *self, int motion_h, int motion_v, uint8_t *s_y, uint8_t *s_cr, uint8_t *s_cb); +void decode_block(mpeg1_decoder_t *self, int block); + +void copy_block_to_destination(int *block, uint8_t *dest, int index, int scan); +void add_block_to_destination(int *block, uint8_t *dest, int index, int scan); +void copy_value_to_destination(int value, uint8_t *dest, int index, int scan); +void add_value_to_destination(int value, uint8_t *dest, int index, int scan); +void idct(int *block); +void zero_block_data(mpeg1_decoder_t *self); +int read_huffman(bit_buffer_t *bits, const int *code_table); + + + + +// ----------------------------------------------------------------------------- +// Public interface + +mpeg1_decoder_t *mpeg1_decoder_create(unsigned int buffer_size, bit_buffer_mode_t buffer_mode) { + mpeg1_decoder_t *self = malloc(sizeof(mpeg1_decoder_t)); + self->bits = bit_buffer_create(buffer_size, buffer_mode); + return self; +} + +void mpeg1_decoder_destroy(mpeg1_decoder_t *self) { + bit_buffer_destroy(self->bits); + + if (self->has_sequence_header) { + free(self->planes_current.y); + free(self->planes_current.cr); + free(self->planes_current.cb); + + free(self->planes_forward.y); + free(self->planes_forward.cr); + free(self->planes_forward.cb); + } + + free(self); +} + +void *mpeg1_decoder_get_write_ptr(mpeg1_decoder_t *self, unsigned int byte_size) { + return bit_buffer_get_write_ptr(self->bits, byte_size); +} + +int mpeg1_decoder_get_index(mpeg1_decoder_t *self) { + return bit_buffer_get_index(self->bits); +} + +void mpeg1_decoder_set_index(mpeg1_decoder_t *self, unsigned int index) { + bit_buffer_set_index(self->bits, index); +} + +void mpeg1_decoder_did_write(mpeg1_decoder_t *self, unsigned int byte_size) { + bit_buffer_did_write(self->bits, byte_size); + if (!self->has_sequence_header) { + if (bit_buffer_find_start_code(self->bits, START_SEQUENCE) != -1) { + decode_sequence_header(self); + } + } +} + +int mpeg1_decoder_has_sequence_header(mpeg1_decoder_t *self) { + return self->has_sequence_header; +} + +float mpeg1_decoder_get_frame_rate(mpeg1_decoder_t *self) { + return self->frame_rate; +} + +int mpeg1_decoder_get_coded_size(mpeg1_decoder_t *self) { + return self->coded_size; +} + +int mpeg1_decoder_get_width(mpeg1_decoder_t *self) { + return self->width; +} + +int mpeg1_decoder_get_height(mpeg1_decoder_t *self) { + return self->height; +} + +void *mpeg1_decoder_get_y_ptr(mpeg1_decoder_t *self) { + return self->planes_forward.y; +} + +void *mpeg1_decoder_get_cr_ptr(mpeg1_decoder_t *self) { + return self->planes_forward.cr; +} + +void *mpeg1_decoder_get_cb_ptr(mpeg1_decoder_t *self) { + return self->planes_forward.cb; +} + +bool mpeg1_decoder_decode(mpeg1_decoder_t *self) { + if (!self->has_sequence_header) { + return false; + } + + if (bit_buffer_find_start_code(self->bits, START_PICTURE) == -1) { + return false; + } + + decode_picture(self); + return true; +} + + + + +// ----------------------------------------------------------------------------- +// Private methods + +void decode_sequence_header(mpeg1_decoder_t *self) { + int previous_width = self->width; + int previous_height = self->height; + + self->width = bit_buffer_read(self->bits, 12); + self->height = bit_buffer_read(self->bits, 12); + + // skip pixel aspect ratio + bit_buffer_skip(self->bits, 4); + + self->frame_rate = PICTURE_RATE[bit_buffer_read(self->bits, 4)]; + + // skip bitRate, marker, bufferSize and constrained bit + bit_buffer_skip(self->bits, 18 + 1 + 10 + 1); + + if (bit_buffer_read(self->bits, 1)) { // load custom intra quant matrix? + for (int i = 0; i < 64; i++) { + self->intra_quant_matrix[ZIG_ZAG[i]] = bit_buffer_read(self->bits, 8); + } + } + else { + memcpy(self->intra_quant_matrix, DEFAULT_INTRA_QUANT_MATRIX, 64); + } + + if (bit_buffer_read(self->bits, 1)) { // load custom non intra quant matrix? + for (int i = 0; i < 64; i++) { + int idx = ZIG_ZAG[i]; + self->non_intra_quant_matrix[idx] = bit_buffer_read(self->bits, 8); + } + } + else { + memcpy(self->non_intra_quant_matrix, DEFAULT_NON_INTRA_QUANT_MATRIX, 64); + } + + if (self->has_sequence_header) { + if (self->width == previous_width && self->height == previous_height) { + // We already had a sequence header with the same width/height; + // nothing else to do here. + return; + } + + // We had a sequence header but with different dimensions; + // delete the previous planes and allocate new. + free(self->planes_current.y); + free(self->planes_current.cr); + free(self->planes_current.cb); + + free(self->planes_forward.y); + free(self->planes_forward.cr); + free(self->planes_forward.cb); + } + + self->mb_width = (self->width + 15) >> 4; + self->mb_height = (self->height + 15) >> 4; + self->mb_size = self->mb_width * self->mb_height; + + self->coded_width = self->mb_width << 4; + self->coded_height = self->mb_height << 4; + self->coded_size = self->coded_width * self->coded_height; + + self->half_width = self->mb_width << 3; + self->half_height = self->mb_height << 3; + + self->planes_current.y = (uint8_t*)malloc(self->coded_size); + self->planes_current.cr = (uint8_t*)malloc(self->coded_size >> 2); + self->planes_current.cb = (uint8_t*)malloc(self->coded_size >> 2); + + self->planes_forward.y = (uint8_t*)malloc(self->coded_size); + self->planes_forward.cr = (uint8_t*)malloc(self->coded_size >> 2); + self->planes_forward.cb = (uint8_t*)malloc(self->coded_size >> 2); + + self->has_sequence_header = true; +} + + +void decode_picture(mpeg1_decoder_t *self) { + bit_buffer_skip(self->bits, 10); // skip temporalReference + self->picture_type = bit_buffer_read(self->bits, 3); + bit_buffer_skip(self->bits, 16); // skip vbv_delay + + // Skip B and D frames or unknown coding type + if (self->picture_type <= 0 || self->picture_type >= PICTURE_TYPE_B) { + return; + } + + // full_pel_forward, forward_f_code + if (self->picture_type == PICTURE_TYPE_PREDICTIVE) { + self->full_pel_forward = bit_buffer_read(self->bits, 1); + self->forward_f_code = bit_buffer_read(self->bits, 3); + if (self->forward_f_code == 0) { + // Ignore picture with zero self->forward_f_code + return; + } + self->forward_r_size = self->forward_f_code - 1; + self->forward_f = 1 << self->forward_r_size; + } + + int code = 0; + do { + code = bit_buffer_find_next_start_code(self->bits); + } while (code == START_EXTENSION || code == START_USER_DATA); + + + while (code >= START_SLICE_FIRST && code <= START_SLICE_LAST) { + decode_slice(self, code & 0x000000FF); + code = bit_buffer_find_next_start_code(self->bits); + } + + if (code != -1) { + // We found the next start code; rewind 32self->bits and let the main loop + // handle it. + bit_buffer_rewind(self->bits, 32); + } + + // If this is a reference picutre then rotate the prediction pointers + if ( + self->picture_type == PICTURE_TYPE_INTRA || + self->picture_type == PICTURE_TYPE_PREDICTIVE + ) { + mpeg1_planes_t temp = self->planes_forward; + self->planes_forward = self->planes_current; + self->planes_current = temp; + } +} + + +// Slice Layer + +void decode_slice(mpeg1_decoder_t *self, int slice) { + self->slice_begin = true; + self->macroblock_address = (slice - 1) * self->mb_width - 1; + + // Reset motion vectors and DC predictors + self->motion_fw_h = self->motion_fw_h_prev = 0; + self->motion_fw_v = self->motion_fw_v_prev = 0; + self->dc_predictor_y = 128; + self->dc_predictor_cr = 128; + self->dc_predictor_cb = 128; + + self->quantizer_scale = bit_buffer_read(self->bits, 5); + + // skip extra self->bits + while (bit_buffer_read(self->bits, 1)) { + bit_buffer_skip(self->bits, 8); + } + + do { + decode_macroblock(self); + } while (!bit_buffer_next_bytes_are_start_code(self->bits)); +}; + + +// Macroblock Layer + +void decode_macroblock(mpeg1_decoder_t *self) { + // Decode self->macroblock_address_increment + int increment = 0; + int x = 0; + int t = read_huffman(self->bits, MACROBLOCK_ADDRESS_INCREMENT); + + while (t == 34) { + // macroblock_stuffing + x = 1; + t = read_huffman(self->bits, MACROBLOCK_ADDRESS_INCREMENT); + } + while (t == 35) { + // macroblock_escape + increment += 33; + x = + t = read_huffman(self->bits, MACROBLOCK_ADDRESS_INCREMENT); + } + increment += t; + + // Process any skipped macroblocks + if (self->slice_begin) { + // The first self->macroblock_address_increment of each slice is relative + // to beginning of the preverious row, not the preverious macroblock + self->slice_begin = false; + self->macroblock_address += increment; + } + else { + if (self->macroblock_address + increment >= self->mb_size) { + // Illegal (too large) self->macroblock_address_increment + // abort(); + return; + } + if (increment > 1) { + // Skipped macroblocks reset DC predictors + self->dc_predictor_y = 128; + self->dc_predictor_cr = 128; + self->dc_predictor_cb = 128; + + // Skipped macroblocks in P-pictures reset motion vectors + if (self->picture_type == PICTURE_TYPE_PREDICTIVE) { + self->motion_fw_h = self->motion_fw_h_prev = 0; + self->motion_fw_v = self->motion_fw_v_prev = 0; + } + } + + // Predict skipped macroblocks + while (increment > 1) { + self->macroblock_address++; + self->mb_row = (self->macroblock_address / self->mb_width)|0; + self->mb_col = self->macroblock_address % self->mb_width; + copy_macroblock( + self, + self->motion_fw_h, self->motion_fw_v, + self->planes_forward.y, self->planes_forward.cr, self->planes_forward.cb + ); + increment--; + } + self->macroblock_address++; + } + + self->mb_row = (self->macroblock_address / self->mb_width)|0; + self->mb_col = self->macroblock_address % self->mb_width; + + // Process the current macroblock + // static const s16 *mbTable = MACROBLOCK_TYPE[self->picture_type]; + // macroblock_type = read_huffman(self->bits, mbTable); + if (self->picture_type == PICTURE_TYPE_INTRA) { + self->macroblock_type = read_huffman(self->bits, MACROBLOCK_TYPE_INTRA); + } + else if (self->picture_type == PICTURE_TYPE_PREDICTIVE) { + self->macroblock_type = read_huffman(self->bits, MACROBLOCK_TYPE_PREDICTIVE); + } + else { + // Unhandled picture type + // abort(); + } + self->macroblock_intra = (self->macroblock_type & 0x01); + self->macroblock_motion_fw = (self->macroblock_type & 0x08); + + // Quantizer scale + if ((self->macroblock_type & 0x10) != 0) { + self->quantizer_scale = bit_buffer_read(self->bits, 5); + } + + if (self->macroblock_intra) { + // Intra-coded macroblocks reset motion vectors + self->motion_fw_h = self->motion_fw_h_prev = 0; + self->motion_fw_v = self->motion_fw_v_prev = 0; + } + else { + // Non-intra macroblocks reset DC predictors + self->dc_predictor_y = 128; + self->dc_predictor_cr = 128; + self->dc_predictor_cb = 128; + + decode_motion_vectors(self); + copy_macroblock( + self, + self->motion_fw_h, self->motion_fw_v, + self->planes_forward.y, self->planes_forward.cr, self->planes_forward.cb + ); + } + + // Decode blocks + int cbp = ((self->macroblock_type & 0x02) != 0) + ? read_huffman(self->bits, CODE_BLOCK_PATTERN) + : (self->macroblock_intra ? 0x3f : 0); + + for (int block = 0, mask = 0x20; block < 6; block++) { + if ((cbp & mask) != 0) { + decode_block(self, block); + } + mask >>= 1; + } +}; + + +void decode_motion_vectors(mpeg1_decoder_t *self) { + int code, d, r = 0; + + // Forward + if (self->macroblock_motion_fw) { + // Horizontal forward + code = read_huffman(self->bits, MOTION); + if ((code != 0) && (self->forward_f != 1)) { + r = bit_buffer_read(self->bits, self->forward_r_size); + d = ((abs(code) - 1) << self->forward_r_size) + r + 1; + if (code < 0) { + d = -d; + } + } + else { + d = code; + } + + self->motion_fw_h_prev += d; + if (self->motion_fw_h_prev > (self->forward_f << 4) - 1) { + self->motion_fw_h_prev -= self->forward_f << 5; + } + else if (self->motion_fw_h_prev < ((-self->forward_f) << 4)) { + self->motion_fw_h_prev += self->forward_f << 5; + } + + self->motion_fw_h = self->motion_fw_h_prev; + if (self->full_pel_forward) { + self->motion_fw_h <<= 1; + } + + // Vertical forward + code = read_huffman(self->bits, MOTION); + if ((code != 0) && (self->forward_f != 1)) { + r = bit_buffer_read(self->bits, self->forward_r_size); + d = ((abs(code) - 1) << self->forward_r_size) + r + 1; + if (code < 0) { + d = -d; + } + } + else { + d = code; + } + + self->motion_fw_v_prev += d; + if (self->motion_fw_v_prev > (self->forward_f << 4) - 1) { + self->motion_fw_v_prev -= self->forward_f << 5; + } + else if (self->motion_fw_v_prev < ((-self->forward_f) << 4)) { + self->motion_fw_v_prev += self->forward_f << 5; + } + + self->motion_fw_v = self->motion_fw_v_prev; + if (self->full_pel_forward) { + self->motion_fw_v <<= 1; + } + } + else if (self->picture_type == PICTURE_TYPE_PREDICTIVE) { + // No motion information in P-picture, reset vectors + self->motion_fw_h = self->motion_fw_h_prev = 0; + self->motion_fw_v = self->motion_fw_v_prev = 0; + } +} + + +void copy_macroblock(mpeg1_decoder_t *self, int motion_h, int motion_v, uint8_t *s_y, uint8_t *s_cr, uint8_t *s_cb) { + int + width, scan, + H, V, + src, dest, last; + bool odd_h, odd_v; + + // We use 32bit writes here + int *d_y = (int*)self->planes_current.y; + int *d_cb = (int*)self->planes_current.cb; + int *d_cr = (int*)self->planes_current.cr; + + // Luminance + width = self->coded_width; + scan = width - 16; + + H = motion_h >> 1; + V = motion_v >> 1; + odd_h = (motion_h & 1) == 1; + odd_v = (motion_v & 1) == 1; + + src = ((self->mb_row << 4) + V) * width + (self->mb_col << 4) + H; + dest = (self->mb_row * width + self->mb_col) << 2; + last = dest + (width << 2); + + int x, y1, y2, y; + if (odd_h) { + if (odd_v) { + while (dest < last) { + y1 = s_y[src] + s_y[src+width]; src++; + for (x = 0; x < 4; x++) { + y2 = s_y[src] + s_y[src+width]; src++; + y = (((y1 + y2 + 2) >> 2) & 0xff); + + y1 = s_y[src] + s_y[src+width]; src++; + y |= (((y1 + y2 + 2) << 6) & 0xff00); + + y2 = s_y[src] + s_y[src+width]; src++; + y |= (((y1 + y2 + 2) << 14) & 0xff0000); + + y1 = s_y[src] + s_y[src+width]; src++; + y |= (((y1 + y2 + 2) << 22) & 0xff000000); + + d_y[dest++] = y; + } + dest += scan >> 2; src += scan-1; + } + } + else { + while (dest < last) { + y1 = s_y[src++]; + for (x = 0; x < 4; x++) { + y2 = s_y[src++]; + y = (((y1 + y2 + 1) >> 1) & 0xff); + + y1 = s_y[src++]; + y |= (((y1 + y2 + 1) << 7) & 0xff00); + + y2 = s_y[src++]; + y |= (((y1 + y2 + 1) << 15) & 0xff0000); + + y1 = s_y[src++]; + y |= (((y1 + y2 + 1) << 23) & 0xff000000); + + d_y[dest++] = y; + } + dest += scan >> 2; src += scan-1; + } + } + } + else { + if (odd_v) { + while (dest < last) { + for (x = 0; x < 4; x++) { + y = (((s_y[src] + s_y[src+width] + 1) >> 1) & 0xff); src++; + y |= (((s_y[src] + s_y[src+width] + 1) << 7) & 0xff00); src++; + y |= (((s_y[src] + s_y[src+width] + 1) << 15) & 0xff0000); src++; + y |= (((s_y[src] + s_y[src+width] + 1) << 23) & 0xff000000); src++; + + d_y[dest++] = y; + } + dest += scan >> 2; src += scan; + } + } + else { + while (dest < last) { + for (x = 0; x < 4; x++) { + y = s_y[src]; src++; + y |= s_y[src] << 8; src++; + y |= s_y[src] << 16; src++; + y |= s_y[src] << 24; src++; + + d_y[dest++] = y; + } + dest += scan >> 2; src += scan; + } + } + } + + // Chrominance + + width = self->half_width; + scan = width - 8; + + H = (motion_h/2) >> 1; + V = (motion_v/2) >> 1; + odd_h = ((motion_h/2) & 1) == 1; + odd_v = ((motion_v/2) & 1) == 1; + + src = ((self->mb_row << 3) + V) * width + (self->mb_col << 3) + H; + dest = (self->mb_row * width + self->mb_col) << 1; + last = dest + (width << 1); + + int cr1, cr2, cr, + cb1, cb2, cb; + if (odd_h) { + if (odd_v) { + while (dest < last) { + cr1 = s_cr[src] + s_cr[src+width]; + cb1 = s_cb[src] + s_cb[src+width]; + src++; + for (x = 0; x < 2; x++) { + cr2 = s_cr[src] + s_cr[src+width]; + cb2 = s_cb[src] + s_cb[src+width]; src++; + cr = (((cr1 + cr2 + 2) >> 2) & 0xff); + cb = (((cb1 + cb2 + 2) >> 2) & 0xff); + + cr1 = s_cr[src] + s_cr[src+width]; + cb1 = s_cb[src] + s_cb[src+width]; src++; + cr |= (((cr1 + cr2 + 2) << 6) & 0xff00); + cb |= (((cb1 + cb2 + 2) << 6) & 0xff00); + + cr2 = s_cr[src] + s_cr[src+width]; + cb2 = s_cb[src] + s_cb[src+width]; src++; + cr |= (((cr1 + cr2 + 2) << 14) & 0xff0000); + cb |= (((cb1 + cb2 + 2) << 14) & 0xff0000); + + cr1 = s_cr[src] + s_cr[src+width]; + cb1 = s_cb[src] + s_cb[src+width]; src++; + cr |= (((cr1 + cr2 + 2) << 22) & 0xff000000); + cb |= (((cb1 + cb2 + 2) << 22) & 0xff000000); + + d_cr[dest] = cr; + d_cb[dest] = cb; + dest++; + } + dest += scan >> 2; src += scan-1; + } + } + else { + while (dest < last) { + cr1 = s_cr[src]; + cb1 = s_cb[src]; + src++; + for (x = 0; x < 2; x++) { + cr2 = s_cr[src]; + cb2 = s_cb[src++]; + cr = (((cr1 + cr2 + 1) >> 1) & 0xff); + cb = (((cb1 + cb2 + 1) >> 1) & 0xff); + + cr1 = s_cr[src]; + cb1 = s_cb[src++]; + cr |= (((cr1 + cr2 + 1) << 7) & 0xff00); + cb |= (((cb1 + cb2 + 1) << 7) & 0xff00); + + cr2 = s_cr[src]; + cb2 = s_cb[src++]; + cr |= (((cr1 + cr2 + 1) << 15) & 0xff0000); + cb |= (((cb1 + cb2 + 1) << 15) & 0xff0000); + + cr1 = s_cr[src]; + cb1 = s_cb[src++]; + cr |= (((cr1 + cr2 + 1) << 23) & 0xff000000); + cb |= (((cb1 + cb2 + 1) << 23) & 0xff000000); + + d_cr[dest] = cr; + d_cb[dest] = cb; + dest++; + } + dest += scan >> 2; src += scan-1; + } + } + } + else { + if (odd_v) { + while (dest < last) { + for (x = 0; x < 2; x++) { + cr = (((s_cr[src] + s_cr[src+width] + 1) >> 1) & 0xff); + cb = (((s_cb[src] + s_cb[src+width] + 1) >> 1) & 0xff); src++; + + cr |= (((s_cr[src] + s_cr[src+width] + 1) << 7) & 0xff00); + cb |= (((s_cb[src] + s_cb[src+width] + 1) << 7) & 0xff00); src++; + + cr |= (((s_cr[src] + s_cr[src+width] + 1) << 15) & 0xff0000); + cb |= (((s_cb[src] + s_cb[src+width] + 1) << 15) & 0xff0000); src++; + + cr |= (((s_cr[src] + s_cr[src+width] + 1) << 23) & 0xff000000); + cb |= (((s_cb[src] + s_cb[src+width] + 1) << 23) & 0xff000000); src++; + + d_cr[dest] = cr; + d_cb[dest] = cb; + dest++; + } + dest += scan >> 2; src += scan; + } + } + else { + while (dest < last) { + for (x = 0; x < 2; x++) { + cr = s_cr[src]; + cb = s_cb[src]; src++; + + cr |= s_cr[src] << 8; + cb |= s_cb[src] << 8; src++; + + cr |= s_cr[src] << 16; + cb |= s_cb[src] << 16; src++; + + cr |= s_cr[src] << 24; + cb |= s_cb[src] << 24; src++; + + d_cr[dest] = cr; + d_cb[dest] = cb; + dest++; + } + dest += scan >> 2; src += scan; + } + } + } +} + + +// Block layer + +void decode_block(mpeg1_decoder_t *self, int block) { + + int n = 0; + uint8_t *quant_matrix; + + // Decode DC coefficient of intra-coded blocks + if (self->macroblock_intra) { + int predictor; + int dctSize; + + // DC prediction + + if (block < 4) { + predictor = self->dc_predictor_y; + dctSize = read_huffman(self->bits, DCT_DC_SIZE_LUMINANCE); + } + else { + predictor = (block == 4 ? self->dc_predictor_cr : self->dc_predictor_cb); + dctSize = read_huffman(self->bits, DCT_DC_SIZE_CHROMINANCE); + } + + // Read DC coeff + if (dctSize > 0) { + int differential = bit_buffer_read(self->bits, dctSize); + if ((differential & (1 << (dctSize - 1))) != 0) { + self->block_data[0] = predictor + differential; + } + else { + self->block_data[0] = predictor + ((-1 << dctSize)|(differential+1)); + } + } + else { + self->block_data[0] = predictor; + } + + // Save predictor value + if (block < 4) { + self->dc_predictor_y = self->block_data[0]; + } + else if (block == 4) { + self->dc_predictor_cr = self->block_data[0]; + } + else { + self->dc_predictor_cb = self->block_data[0]; + } + + // Dequantize + premultiply + self->block_data[0] <<= (3 + 5); + + quant_matrix = self->intra_quant_matrix; + n = 1; + } + else { + quant_matrix = self->non_intra_quant_matrix; + } + + // Decode AC coefficients (+DC for non-intra) + int level = 0; + while (true) { + int run = 0; + int coeff = read_huffman(self->bits, DCT_COEFF); + + if ((coeff == 0x0001) && (n > 0) && (bit_buffer_read(self->bits, 1) == 0)) { + // end_of_block + break; + } + if (coeff == 0xffff) { + // escape + run = bit_buffer_read(self->bits, 6); + level = bit_buffer_read(self->bits, 8); + if (level == 0) { + level = bit_buffer_read(self->bits, 8); + } + else if (level == 128) { + level = bit_buffer_read(self->bits, 8) - 256; + } + else if (level > 128) { + level = level - 256; + } + } + else { + run = coeff >> 8; + level = coeff & 0xff; + if (bit_buffer_read(self->bits, 1)) { + level = -level; + } + } + + n += run; + int dezigZagged = ZIG_ZAG[n]; + n++; + + // Dequantize, oddify, clip + level <<= 1; + if (!self->macroblock_intra) { + level += (level < 0 ? -1 : 1); + } + level = (level * self->quantizer_scale * quant_matrix[dezigZagged]) >> 4; + if ((level & 1) == 0) { + level -= level > 0 ? 1 : -1; + } + if (level > 2047) { + level = 2047; + } + else if (level < -2048) { + level = -2048; + } + + // Save premultiplied coefficient + self->block_data[dezigZagged] = level * PREMULTIPLIER_MATRIX[dezigZagged]; + } + + // Move block to its place + uint8_t *dest_array; + int dest_index; + int scan; + + if (block < 4) { + dest_array = self->planes_current.y; + scan = self->coded_width - 8; + dest_index = (self->mb_row * self->coded_width + self->mb_col) << 4; + if ((block & 1) != 0) { + dest_index += 8; + } + if ((block & 2) != 0) { + dest_index += self->coded_width << 3; + } + } + else { + dest_array = (block == 4) ? self->planes_current.cb : self->planes_current.cr; + scan = (self->coded_width >> 1) - 8; + dest_index = ((self->mb_row * self->coded_width) << 2) + (self->mb_col << 3); + } + + if (self->macroblock_intra) { + // Overwrite (no prediction) + if (n == 1) { + copy_value_to_destination((self->block_data[0] + 128) >> 8, dest_array, dest_index, scan); + self->block_data[0] = 0; + } + else { + idct(self->block_data); + copy_block_to_destination(self->block_data, dest_array, dest_index, scan); + zero_block_data(self); + } + } + else { + // Add data to the predicted macroblock + if (n == 1) { + add_value_to_destination((self->block_data[0] + 128) >> 8, dest_array, dest_index, scan); + self->block_data[0] = 0; + } + else { + idct(self->block_data); + add_block_to_destination(self->block_data, dest_array, dest_index, scan); + zero_block_data(self); + } + } + + n = 0; +} + + +// ----------------------------------------------------------------------------- +// Private functions + +void zero_block_data(mpeg1_decoder_t *self) { + for (int i = 0; i < 64; i++) { + self->block_data[i] = 0; + } +} + +inline uint8_t clamp_to_uint8(int n) { + return n > 255 + ? 255 + : (n < 0 ? 0 : n); +} + +void copy_block_to_destination(int *block, uint8_t *dest, int index, int scan) { + for (int n = 0; n < 64; n += 8, index += scan+8) { + dest[index+0] = clamp_to_uint8(block[n+0]); + dest[index+1] = clamp_to_uint8(block[n+1]); + dest[index+2] = clamp_to_uint8(block[n+2]); + dest[index+3] = clamp_to_uint8(block[n+3]); + dest[index+4] = clamp_to_uint8(block[n+4]); + dest[index+5] = clamp_to_uint8(block[n+5]); + dest[index+6] = clamp_to_uint8(block[n+6]); + dest[index+7] = clamp_to_uint8(block[n+7]); + } +} + +void add_block_to_destination(int *block, uint8_t *dest, int index, int scan) { + for (int n = 0; n < 64; n += 8, index += scan+8) { + dest[index+0] = clamp_to_uint8(dest[index+0] + block[n+0]); + dest[index+1] = clamp_to_uint8(dest[index+1] + block[n+1]); + dest[index+2] = clamp_to_uint8(dest[index+2] + block[n+2]); + dest[index+3] = clamp_to_uint8(dest[index+3] + block[n+3]); + dest[index+4] = clamp_to_uint8(dest[index+4] + block[n+4]); + dest[index+5] = clamp_to_uint8(dest[index+5] + block[n+5]); + dest[index+6] = clamp_to_uint8(dest[index+6] + block[n+6]); + dest[index+7] = clamp_to_uint8(dest[index+7] + block[n+7]); + } +} + +void copy_value_to_destination(int value, uint8_t *dest, int index, int scan) { + for (int n = 0; n < 64; n += 8, index += scan+8) { + dest[index+0] = value; + dest[index+1] = value; + dest[index+2] = value; + dest[index+3] = value; + dest[index+4] = value; + dest[index+5] = value; + dest[index+6] = value; + dest[index+7] = value; + } +} + +void add_value_to_destination(int value, uint8_t *dest, int index, int scan) { + for (int n = 0; n < 64; n += 8, index += scan+8) { + dest[index+0] += value; + dest[index+1] += value; + dest[index+2] += value; + dest[index+3] += value; + dest[index+4] += value; + dest[index+5] += value; + dest[index+6] += value; + dest[index+7] += value; + } +} + +void idct(int *block) { + // See http://vsr.informatik.tu-chemnitz.de/~jan/MPEG/HTML/IDCT.html + // for more info. + + int + b1, b3, b4, b6, b7, tmp1, tmp2, m0, + x0, x1, x2, x3, x4, y3, y4, y5, y6, y7; + + // Transform columns + for (int i = 0; i < 8; ++i) { + b1 = block[4*8+i]; + b3 = block[2*8+i] + block[6*8+i]; + b4 = block[5*8+i] - block[3*8+i]; + tmp1 = block[1*8+i] + block[7*8+i]; + tmp2 = block[3*8+i] + block[5*8+i]; + b6 = block[1*8+i] - block[7*8+i]; + b7 = tmp1 + tmp2; + m0 = block[0*8+i]; + x4 = ((b6*473 - b4*196 + 128) >> 8) - b7; + x0 = x4 - (((tmp1 - tmp2)*362 + 128) >> 8); + x1 = m0 - b1; + x2 = (((block[2*8+i] - block[6*8+i])*362 + 128) >> 8) - b3; + x3 = m0 + b1; + y3 = x1 + x2; + y4 = x3 + b3; + y5 = x1 - x2; + y6 = x3 - b3; + y7 = -x0 - ((b4*473 + b6*196 + 128) >> 8); + block[0*8+i] = b7 + y4; + block[1*8+i] = x4 + y3; + block[2*8+i] = y5 - x0; + block[3*8+i] = y6 - y7; + block[4*8+i] = y6 + y7; + block[5*8+i] = x0 + y5; + block[6*8+i] = y3 - x4; + block[7*8+i] = y4 - b7; + } + + // Transform rows + for (int i = 0; i < 64; i += 8) { + b1 = block[4+i]; + b3 = block[2+i] + block[6+i]; + b4 = block[5+i] - block[3+i]; + tmp1 = block[1+i] + block[7+i]; + tmp2 = block[3+i] + block[5+i]; + b6 = block[1+i] - block[7+i]; + b7 = tmp1 + tmp2; + m0 = block[0+i]; + x4 = ((b6*473 - b4*196 + 128) >> 8) - b7; + x0 = x4 - (((tmp1 - tmp2)*362 + 128) >> 8); + x1 = m0 - b1; + x2 = (((block[2+i] - block[6+i])*362 + 128) >> 8) - b3; + x3 = m0 + b1; + y3 = x1 + x2; + y4 = x3 + b3; + y5 = x1 - x2; + y6 = x3 - b3; + y7 = -x0 - ((b4*473 + b6*196 + 128) >> 8); + block[0+i] = (b7 + y4 + 128) >> 8; + block[1+i] = (x4 + y3 + 128) >> 8; + block[2+i] = (y5 - x0 + 128) >> 8; + block[3+i] = (y6 - y7 + 128) >> 8; + block[4+i] = (y6 + y7 + 128) >> 8; + block[5+i] = (x0 + y5 + 128) >> 8; + block[6+i] = (y3 - x4 + 128) >> 8; + block[7+i] = (y4 - b7 + 128) >> 8; + } +} + +int read_huffman(bit_buffer_t *bits, const int *code_table) { + int state = 0; + do { + state = code_table[state + bit_buffer_read(bits, 1)]; + } while (state >= 0 && code_table[state] != 0); + return code_table[state+2]; +} diff --git a/src/wasm/mpeg1.h b/src/wasm/mpeg1.h new file mode 100644 index 00000000..2f9d8a3d --- /dev/null +++ b/src/wasm/mpeg1.h @@ -0,0 +1,27 @@ +#ifndef MPEG1_H +#define MPEG1_H + +#include +#include +#include "buffer.h" + +typedef struct mpeg1_decoder_t mpeg1_decoder_t; + +mpeg1_decoder_t *mpeg1_decoder_create(unsigned int buffer_size, bit_buffer_mode_t buffer_mode); +void mpeg1_decoder_destroy(mpeg1_decoder_t *self); +void *mpeg1_decoder_get_write_ptr(mpeg1_decoder_t *self, unsigned int byte_size); +int mpeg1_decoder_get_index(mpeg1_decoder_t *self); +void mpeg1_decoder_set_index(mpeg1_decoder_t *self, unsigned int index); +void mpeg1_decoder_did_write(mpeg1_decoder_t *self, unsigned int byte_size); + +int mpeg1_decoder_has_sequence_header(mpeg1_decoder_t *self); +float mpeg1_decoder_get_frame_rate(mpeg1_decoder_t *self); +int mpeg1_decoder_get_coded_size(mpeg1_decoder_t *self); +int mpeg1_decoder_get_width(mpeg1_decoder_t *self); +int mpeg1_decoder_get_height(mpeg1_decoder_t *self); +void *mpeg1_decoder_get_y_ptr(mpeg1_decoder_t *self); +void *mpeg1_decoder_get_cr_ptr(mpeg1_decoder_t *self); +void *mpeg1_decoder_get_cb_ptr(mpeg1_decoder_t *self); +bool mpeg1_decoder_decode(mpeg1_decoder_t *self); + +#endif