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.
387 lines
12 KiB
387 lines
12 KiB
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!");
|
|
}
|
|
}
|
|
|