You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
12 KiB

2 years ago
self.Module = {
onRuntimeInitialized: function () {
onWasmLoaded();
},
};
self.importScripts("common.js");
self.importScripts("videodec_simd_noems6_h265.js")
var pts=0;
H265Frame =[];
AUDIOFrame =[];
function Decoder(){
// this.timer=null;
this.decodeTimer = null;
this.wasmLoaded = false;
this.vtype = 'hevc'
this.format = 'annexb'
this.extraData = ""
this.tmpReqQue = [];
this.decodestatus=false;
this.lastpts = 0;
}
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=0;
//void VideoDecoder::setCodec(string vtype, string format, string extra)
Module._codecInit()
console.log("initDecoder return " + ret + ".");
var objData = {
t: kInitDecoderRsp,
e: ret
};
self.postMessage(objData);
};
Decoder.prototype.uninitDecoder = function () {
var ret = 0;//Module._uninitDecoder();
Module._clear();
console.log("Uninit ffmpeg decoder return " + ret + ".");
};
// var data={
// pts: pts,
// size: size,
// iskeyframe: isKeyFrame,
// packet: h265data
// };
// var req = {
// t: ksendPlayerVideoFrameReq,
// l: h265datalen,
// d: data
// };
const MIN_H265FRAME_FOR_DECODE=0
var decodet1=new Date().getTime();
Decoder.prototype.decode=function(){
if(H265Frame.length>MIN_H265FRAME_FOR_DECODE){
// this.decodestatus=true;
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);
//void VideoDecoder::decode(string input, unsigned int isKeyFrame, unsigned int timestamp)
Module._decode(cacheBuffer,size,typedArray.iskeyframe,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("end 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() {
//void(*VideoCallback)(unsigned char* data,int width, int height, long pts);
var videoCallback = Module.addFunction(function (yuvArray, width, height, pts) {
let size = width*height;
let halfSize = size>>2;
let yPtr = HEAPU32[(yuvArray>>2)];
let uPtr = HEAPU32[(yuvArray>>2) + 1];
let vPtr = HEAPU32[(yuvArray>>2) + 2];
let yBuf = HEAPU8.subarray(yPtr, yPtr + size);
let uBuf = HEAPU8.subarray(uPtr, uPtr + halfSize);
let vBuf = HEAPU8.subarray(vPtr, vPtr + halfSize);
// let datas = [Uint8Array.from(yBuf), Uint8Array.from(uBuf), Uint8Array.from(vBuf)];
let datas = new Uint8Array(yBuf.length + uBuf.length + vBuf.length)
// 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)
datas.set(yBuf, 0)
datas.set(uBuf, yBuf.length)
datas.set(vBuf, yBuf.length + uBuf.length)
var obj = {
s: pts,
data: datas,
width,
height,
}
var objData = {
t: kVideoFrame,
d: obj
};
self.postMessage(objData, [objData.d.data.buffer]);
const t2 = new Date().getTime()-decodet1;
console.log("end decode simd time:"+t2,"pts",pts);//+" data:"+typedArray.toString(16));
},'viiii')
this.vtype="hevc";
this.format="annexb";
this.extraData="";
Module._setCodec(this.vtype,this.format,this.extraData,videoCallback);
// 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: 0
};
self.postMessage(objData);
}
// Decoder.prototype.onVideoInfo=function(width,height){
// this.width=width;
// this.height=height;
// var objData={
// t: kVideoInfo,
// width: width,
// height: height
// };
// self.postMessage(objData);
// }
// Decoder.prototype.onYUVData = function (yuvArray,pts){
// let size = this.width*this.height;
// let halfSize = size>>2;
// let yPtr = HEAPU32[(yuvArray>>2)];
// let uPtr = HEAPU32[(yuvArray>>2) + 1];
// let vPtr = HEAPU32[(yuvArray>>2) + 2];
// let yBuf = HEAPU8.subarray(yPtr, yPtr + size);
// let uBuf = HEAPU8.subarray(uPtr, uPtr + halfSize);
// let vBuf = HEAPU8.subarray(vPtr, vPtr + halfSize);
// let datas = [Uint8Array.from(yBuf), Uint8Array.from(uBuf), Uint8Array.from(vBuf)];
// // let vFrame = {
// // pixelType:'I420',
// // datas: datas,
// // width: this.width,
// // height: this.height,
// // pts: pts
// // };
// // 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 = {
// data: datas,
// 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);//+" data:"+typedArray.toString(16));
// }
function findMinFrame(H265Frame){
var min=50000;
var index=0;
for(var i=0;i<H265Frame.length;i++){
if((H265Frame[i].iskeyframe!==true)){
if(H265Frame[i].size<min){
min=H265Frame[i].size
index=i
}
}
}
return index
}
Decoder.prototype.sendFrame = function(data,type){
// if(data.pts<=this.lastpts){
// return;
// }
this.lastpts=data.pts;
var typedArray = {
pts: data.pts,
iskeyframe: data.iskeyframe,
size: data.size,
// d: data.packet//
d: data.packet//new Uint8Array(data.packet)
}
console.log("sendFrame pts:",typedArray.pts)
// if(H265Frame.length>MAX_FRAME_SIZE){
// H265Frame.shift();
// }
if(type==="VIDEO"){
if(H265Frame.length>MAX_FRAME_SIZE){
var index=findMinFrame(H265Frame)
H265Frame = H265Frame.splice(index, 1)
// for(var i=0;i<H265Frame.length;i++)
// if((H265Frame[i].iskeyframe!==true)){
// // &&(H265Frame[i].size<MAX_DELETE_FRAME_SIZE)
// H265Frame = H265Frame.splice(i, 1)
// break
// //break;
// // H265Frame.shift();
// }
}
H265Frame.push(typedArray)
}else if(type==="AUDIO"){
AUDIOFrame.push(typedArray)
}
}
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);
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!");
}
}
function onVideoInfo(width,height){
if (self.decoder) {
self.decoder.onVideoInfo(width,height);
} else {
console.log("[ER] No decoder!");
}
}
function onYUVData (yuvArray,pts){
if (self.decoder) {
self.decoder.onYUVData(yuvArray,pts);
} else {
console.log("[ER] No decoder!");
}
}