self . Module = {
onRuntimeInitialized : function ( ) {
onWasmLoaded ( ) ;
}
} ;
var LOG_LEVEL_JS = 0 ;
var LOG_LEVEL_WASM = 1 ;
var LOG_LEVEL_FFMPEG = 2 ;
var DECODER_H264 = 0 ;
var DECODER_H265 = 1 ;
self . importScripts ( "common.js" ) ;
// self.importScripts("libffmpeg_264_265.js");
// self.importScripts("libffmpeg_265.js")
self . importScripts ( "libffmpeg_265.js" )
var decoder_type = DECODER_H265 ;
var pts = 0 ;
H265Frame = [ ] ;
AudioFrame = [ ] ;
function Decoder ( ) {
// this.timer=null;
this . decodeTimer = null ;
this . wasmLoaded = false ;
this . tmpReqQue = [ ] ;
}
Decoder . prototype . cacheReq = function ( req ) {
if ( req ) {
this . tmpReqQue . push ( req ) ;
}
} ;
Decoder . prototype . onWasmLoaded = function ( ) {
console . log ( "Wasm loaded." ) ;
this . wasmLoaded = true ;
while ( this . tmpReqQue . length > 0 ) {
var req = this . tmpReqQue . shift ( ) ;
this . processReq ( req ) ;
}
}
Decoder . prototype . initDecoder = function ( ) {
// var ret = Module._initDecoder(fileSize, this.coreLogLevel);
var ret = 0 ;
console . log ( "initDecoder return " + ret + "." ) ;
// if (0 == ret) {
// this.cacheBuffer = Module._malloc(chunkSize);
// }
// this.frameBuffer.length=0;
var objData = {
t : kInitDecoderRsp ,
e : ret
} ;
self . postMessage ( objData ) ;
} ;
Decoder . prototype . uninitDecoder = function ( ) {
var ret = 0 ; //Module._uninitDecoder();
console . log ( "Uninit ffmpeg decoder return " + ret + "." ) ;
// if (this.cacheBuffer != null) {
// Module._free(this.cacheBuffer);
// this.cacheBuffer = null;
// }
} ;
const MIN_FRAME_FOR_DECODE = 0
var decodet1 = new Date ( ) . getTime ( ) ;
Decoder . prototype . decode = function ( ) {
if ( H265Frame . length > MIN_FRAME_FOR_DECODE ) {
// decodet1=new Date().getTime();
// var typedArray=H265Frame[0];//new Uint8Array(H265Frame[0]);
// var size = typedArray.length
// console.log("decode len: " + size)
// var cacheBuffer = Module._malloc(size);
// Module.HEAPU8.set(typedArray, cacheBuffer);
decodet1 = new Date ( ) . getTime ( ) ;
var typedArray = H265Frame [ 0 ] ; //new Uint8Array(H265Frame[0]);
var packet = typedArray . d ;
var size = typedArray . size ;
// console.log("decode len: " + size)
console . log ( "decode pts:" , typedArray . pts , " packet len:" , size , " H265Frame total" , H265Frame . length )
var cacheBuffer = Module . _ malloc ( size ) ;
Module . HEAPU8 . set ( packet , cacheBuffer ) ;
// totalSize += size
// console.log("[" + (++readerIndex) + "] Read len = ", size + ", Total size = " + totalSize)
// console.log(typedArray.toString(16));
Module . _ decodeData ( cacheBuffer , size , typedArray . pts )
if ( cacheBuffer != null ) {
Module . _ free ( cacheBuffer ) ;
cacheBuffer = null ;
}
H265Frame . shift ( ) ;
}
}
Decoder . prototype . startDecoding = function ( interval ) {
console . log ( "Start decoding." ) ;
if ( this . decodeTimer ) {
clearInterval ( this . decodeTimer ) ;
}
this . decodeTimer = setInterval ( this . decode , 0 ) ; //interval);
} ;
Decoder . prototype . pauseDecoding = function ( ) {
console . log ( "Pause decoding." ) ;
if ( this . decodeTimer ) {
clearInterval ( this . decodeTimer ) ;
this . decodeTimer = null ;
}
} ;
// Decoder.prototype.startdecode=function(){
// // this.timer = requestAnimationFrame(function fn() {
// // // if(this.decodertimer++>=60)
// // this.decodertimer=0;
// // this.decode();
// // requestAnimationFrame(fn);
// // })
// // move = parseInt(getComputedStyle(box).left);
// // if (move < 800) {
// // box.style.left = move + 8 + 'px';
// // requestAnimationFrame(fn);
// // } else {
// // cancelAnimationFrame(timer);
// }
Decoder . prototype . displayVideoFrame = function displayVideoFrame ( obj ) {
// var obj = {
// data: data,
// width,
// height
// }
var objData = {
t : kVideoFrame ,
s : pts ,
d : obj
} ;
self . postMessage ( objData , [ objData . d . data . buffer ] ) ;
const t2 = new Date ( ) . getTime ( ) - decodet1 ;
console . log ( "decode time:" + t2 + " len:" + size ) ; //+" data:"+typedArray.toString(16));
// decodet1=new Date().getTime();
// displayVideoFrame(obj);
}
IsGreyData = function ( data ) {
var isgray = false ;
var len = data . length < 100 ? data . length : 100 ;
for ( var i = 0 ; i < len ; i ++ ) {
isgray = data [ i ] === 128 ? true : false ;
}
return isgray ;
}
Decoder . prototype . decode_seq = function ( ) {
var start_time = new Date ( ) ;
var videoSize = 0 ;
var videoCallback = Module . addFunction ( function ( addr_y , addr_u , addr_v , stride_y , stride_u , stride_v , width , height , pts ) {
console . log ( "[%d]In video callback, size = %d * %d, pts = %d" , ++ videoSize , width , height , pts )
let out_y = HEAPU8 . subarray ( addr_y , addr_y + stride_y * height )
// if(IsGreyData(out_y)===true) {
// return;
// }
var isgray = false ;
var len = out_y . length < 100 ? out_y . length : 100 ;
// for(var i=0; i<len;i++){
// isgray=out_y[i]===128?true:false;
// }
// if( isgray === true) {
// return;
// }
//if (out_y[0]===128 & out_y[0]===128 & out_y[0]===128 & out_y[0]===128
let out_u = HEAPU8 . subarray ( addr_u , addr_u + ( stride_u * height ) / 2 )
let out_v = HEAPU8 . subarray ( addr_v , addr_v + ( stride_v * height ) / 2 )
let buf_y = new Uint8Array ( out_y )
let buf_u = new Uint8Array ( out_u )
let buf_v = new Uint8Array ( out_v )
let data = new Uint8Array ( buf_y . length + buf_u . length + buf_v . length )
data . set ( buf_y , 0 )
data . set ( buf_u , buf_y . length )
data . set ( buf_v , buf_y . length + buf_u . length )
var obj = {
s : pts ,
data : data ,
width ,
height
}
var objData = {
t : kVideoFrame ,
d : obj
} ;
self . postMessage ( objData , [ objData . d . data . buffer ] ) ;
const t2 = new Date ( ) . getTime ( ) - decodet1 ;
console . log ( "decode time:" + t2 ) ; //+" data:"+typedArray.toString(16));
// this.displayVideoFrame(obj);
} , 'viiiiiiiii' ) ;
// typedef void(*VideoCallback)(unsigned char* data_y, unsigned char* data_u, unsigned char* data_v, int line1, int line2, int line3, int width, int height, long pts);
// 'v': void type
// 'i': 32-bit integer type
// 'j': 64-bit integer type (currently does not exist in JavaScript)
// 'f': 32-bit float type
// 'd': 64-bit float type
// ————————————————
// 版权声明:本文为CSDN博主「xw-何妨吟啸且徐行」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
// 原文链接:https://blog.csdn.net/xuw_xy/article/details/117787294
// var videoSize = 0;
// // typedef void(*VideoCallback)(unsigned char* data_y, unsigned char* data_u, unsigned char* data_v, int line1, int line2, int line3, int width, int height, long pts);
// var videoCallback = Module.addFunction(function (addr_y, addr_u, addr_v, stride_y, stride_u, stride_v, width, height, pts) {
// console.log("[%d]In video callback, size = %d * %d, pts = %d", ++videoSize, width, height, pts)
// // if (pts===2147483647){
// // return;
// // }
// let size = width * height + (width / 2) * (height / 2) + (width / 2) * (height / 2)
// let data = new Uint8Array(size)
// let pos = 0
// for(let i=0; i< height; i++) {
// let src = addr_y + i * stride_y
// let tmp = HEAPU8.subarray(src, src + width)
// tmp = new Uint8Array(tmp)
// data.set(tmp, pos)
// pos += tmp.length
// }
// for(let i=0; i< height / 2; i++) {
// let src = addr_u + i * stride_u
// let tmp = HEAPU8.subarray(src, src + width / 2)
// tmp = new Uint8Array(tmp)
// data.set(tmp, pos)
// pos += tmp.length
// }
// for(let i=0; i< height / 2; i++) {
// let src = addr_v + i * stride_v
// let tmp = HEAPU8.subarray(src, src + width / 2)
// tmp = new Uint8Array(tmp)
// data.set(tmp, pos)
// pos += tmp.length
// }
// var obj = {
// data: data,
// width,
// height
// }
// var objData = {
// t: kVideoFrame,
// s: pts,
// d: obj
// };
// self.postMessage(objData, [objData.d.data.buffer]);
// const t2 = new Date().getTime()-decodet1;
// console.log("decode time:"+t2+" len:"+size);//+" data:"+typedArray.toString(16));
// // decodet1=new Date().getTime();
// // displayVideoFrame(obj);
// });
var ret = Module . _ openDecoder ( decoder_type , videoCallback , LOG_LEVEL_WASM )
if ( ret == 0 ) {
console . log ( "openDecoder success" ) ;
} else {
console . error ( "openDecoder failed with error" , ret ) ;
// return;
}
var objData = {
t : kOpenDecoderRsp ,
e : ret
} ;
self . postMessage ( objData ) ;
}
Decoder . prototype . sendFrame = function ( data , type ) {
// var typedArray = {
// pts: data.pts,
// size: data.size,
// d: new Uint8Array(data.packet)
// }
var typedArray = {
pts : data . pts ,
size : data . size ,
d : data . packet //new Uint8Array(data.packet)
}
// var typedArray = new Uint8Array(data.packet);
// if(H265Frame.length>MAX_FRAME_SIZE){
// H265Frame.shift();
// }
if ( type === "VIDEO" ) {
H265Frame . push ( typedArray )
} else if ( type === "AUDIO" ) {
AUDIOFrame . push ( typedArray )
}
// var size = typedArray.length
// var cacheBuffer = Module._malloc(size);
// Module.HEAPU8.set(typedArray, cacheBuffer);
// // totalSize += size
// // console.log("[" + (++readerIndex) + "] Read len = ", size + ", Total size = " + totalSize)
// Module._decodeData(cacheBuffer, size, pts++)
// if (cacheBuffer != null) {
// Module._free(cacheBuffer);
// cacheBuffer = null;
// }
// if(size < CHUNK_SIZE) {
// console.log('Flush frame data')
// Module._flushDecoder();
// Module._closeDecoder();
// }
}
Decoder . prototype . closeDecoder = function ( ) {
console . log ( "closeDecoder." ) ;
if ( this . decodeTimer ) {
clearInterval ( this . decodeTimer ) ;
this . decodeTimer = null ;
console . log ( "Decode timer stopped." ) ;
}
// var ret = Module._closeDecoder();
console . log ( "Close ffmpeg decoder return " + ret + "." ) ;
var objData = {
t : kCloseDecoderRsp ,
e : 0
} ;
self . postMessage ( objData ) ;
} ;
Decoder . prototype . processReq = function ( req ) {
// console.log("processReq " + req.t + ".");
switch ( req . t ) {
case kInitDecoderReq :
this . initDecoder ( ) ;
break ;
case kUninitDecoderReq :
this . uninitDecoder ( ) ;
break ;
case kOpenDecoderReq :
this . decode_seq ( ) ;
break ;
case kCloseDecoderReq :
this . closeDecoder ( ) ;
break ;
case kStartDecodingReq :
this . startDecoding ( req . i ) ;
break ;
case kPauseDecodingReq :
this . pauseDecoding ( ) ;
break ;
case kFeedDataReq :
this . sendFrame ( req . d , req . type ) ;
// if(req.type==="VIDEO"){
// this.sendVideoFrame(req.d);
// }else{
// this.sendAudioFrame(req.d);
// }
break ;
// case kSeekToReq:
// this.seekTo(req.ms);
// break;
default :
this . logger . logError ( "Unsupport messsage " + req . t ) ;
}
} ;
self . decoder = new Decoder ;
self . onmessage = function ( evt ) {
if ( ! self . decoder ) {
console . log ( "[ER] Decoder not initialized!" ) ;
return ;
}
var req = evt . data ;
if ( ! self . decoder . wasmLoaded ) {
self . decoder . cacheReq ( req ) ;
console . log ( "Temp cache req " + req . t + "." ) ;
return ;
}
self . decoder . processReq ( req ) ;
} ;
function onWasmLoaded ( ) {
if ( self . decoder ) {
self . decoder . onWasmLoaded ( ) ;
} else {
console . log ( "[ER] No decoder!" ) ;
}
}