1.c++层接口:Decoder.cpp
// Decoder.cpp : Defines the exported functions for the DLL application.
//编译命令:
//emcc -O3 --bind -o ParseLib.bc ParseLib.cpp
//emcc -O3 --bind -o GetH264FromPS.bc GetH264FromPS.cpp
//emcc -O3 --bind -o H264Decode.bc H264Decode.cpp
//emcc --bind ParseLib.bc GetH264FromPS.bc H264Decode.bc libavcodec.bc libavutil.bc -O3
// -s WASM=1 -s EXPORTED_FUNCTIONS=" //['_Init','_PsToYUV','_InputData','_GetOneFrame','_GetBuffer','_UnInit']" -s //TOTAL_MEMORY=128*1024*1024 -s ALLOW_MEMORY_GROWTH=0 -o decode.js
#include "GetH264FromPS.h"
#include <emscripten/bind.h>
#define BUFFER_SIZE 1280*720*2
#define FRAME_IS_NULL -1
using namespace emscripten;
struct FRAME_INFO
{
int dWidth;
int dHeight;
//int Linesize_Fir;
//int Linesize_Sec;
//int Linesize_Thi;
};
FRAME_INFO g_stFrameInfo = {0};
unsigned char* g_Buffer = NULL;
FRAME_INFO GetFrameInfo()
{
return g_stFrameInfo;
}
#ifdef __cplusplus
extern "C" {
#endif
GetH264FromPS* mGetH264;
int Init(int iBufferSize) {
mGetH264 = new GetH264FromPS();
g_Buffer = new unsigned char[BUFFER_SIZE];
return mGetH264->Init(iBufferSize);
};
int PsToYUV() {
return mGetH264->GetH246FromPs();
};
int InputData(unsigned char* pBuffe, int iLength) {
return mGetH264->InputData(pBuffe, iLength);
};
int GetOneFrame(){
AVFrame* frame = mGetH264->GetOneBuffer();
if(frame==NULL){
return FRAME_IS_NULL;
}
memset(g_Buffer,0,BUFFER_SIZE);
unsigned char **pBuf = frame->data;//指向像素保存的地址
int *pStride = frame->linesize;//位宽
unsigned char* tempBuffer = g_Buffer;
for (int color_idx = 0; color_idx < 3; color_idx++)
{
int nWidth = color_idx == 0 ? frame->width : frame->width / 2;
int nHeight = color_idx == 0 ? frame->height : frame->height / 2;
for (int idx = 0; idx < nHeight; idx++)
{
memcpy(tempBuffer,pBuf[color_idx],nWidth);
tempBuffer += nWidth;
pBuf[color_idx] += pStride[color_idx];
}
//fflush(pFout);
}
//g_Buffer = *(frame->data);
//g_FrameInfo.FrameType=frame->
g_stFrameInfo.dWidth =frame->width;
g_stFrameInfo.dHeight = frame->height;
//g_stFrameInfo.Linesize_Fir = frame->linesize[0];
//g_stFrameInfo.Linesize_Sec = frame->linesize[1];
//g_stFrameInfo.Linesize_Thi = frame->linesize[2];
return 0;
};
unsigned char* GetBuffer(){
return g_Buffer;
};
int UnInit(){
if(g_Buffer)
delete[] g_Buffer;
g_Buffer = NULL;
if(mGetH264)
delete mGetH264;
mGetH264 = NULL;
return 0;
};
#ifdef __cplusplus
}
#endif
EMSCRIPTEN_BINDINGS(my_object)
{
value_object<FRAME_INFO>("FRAME_INFO")
.field("width", &FRAME_INFO::dWidth)
.field("height", &FRAME_INFO::dHeight);
//.field("linesize_fir", &FRAME_INFO::Linesize_Fir)
//.field("linesize_sec", &FRAME_INFO::Linesize_Sec)
//.field("linesize_thi", &FRAME_INFO::Linesize_Thi)
//;
emscripten::function("_GetFrameInfo", &GetFrameInfo);
}
2.JS层的接口:worker.js
importScripts('decode.js');//它是以阻塞方法加载js的,只有所有文件加载完成之后,接下来的脚本才能继续执行
console.log('decode.js');
Module.preRun.push(function() {
console.log('postRun');
var iInit_re = Module._Init(1024*1024*2);
console.log("nihao"+iInit_re);
});
const FRAME_IS_NULL = -1;
const DECODE_FINISHED = 4;
//var iInit_re = Module._Init(1024*1024*2);
onmessage=function(event){
var data = event.data;
if(data.type === "decode_first")
{
var iRe = -1;
var iLen = data.len;
var pBuffer = Module._malloc(iLen)//分配堆内存
var Data = Module.HEAPU8.subarray(pBuffer, pBuffer + iLen);//绑定到视图对象
Data.set(new Uint8Array(data.buf));//数据写入到emscripten分配的内存中去
while(iRe){
iRe = Module._InputData(pBuffer,iLen);
console.log("input data result="+iRe);
var res = Module._PsToYUV();
console.log("_PsToYUV result="+res);
var result = Module._GetOneFrame();
console.log("getoneframe result="+result);
if(result === FRAME_IS_NULL){
continue;
}
else{
var sFramInfo = Module._GetFrameInfo();
var iWidth = sFramInfo.width;
var iHeight = sFramInfo.height;
//var iLine_Fir = sFramInfo.linesize_fir;
//var iLine_Sec = sFramInfo.linesize_sec;
//var iLine_Thi = sFramInfo.linesize_thi;
var iyuv_size = iWidth*iHeight*3/2;
var pYUV = Module._GetBuffer();
var buf = new ArrayBuffer(iyuv_size);//通过二进制对象分配一块连续内存
var ayuv_data = new Uint8Array(buf);//二进制对象绑定到视图,通过视图对内存进行读写操作
ayuv_data.set(Module.HEAPU8.subarray(pYUV,pYUV+iyuv_size));//c中的内存拷贝到刚分配的js内存中
postMessage({type:"video",buf:ayuv_data.buffer,len:ayuv_data.length,width:iWidth,height:iHeight},[ayuv_data.buffer]);
}
}
Module._free(pBuffer);
}
else if(data.type === "decode_second")
{
do{//解码缓存中剩余的数据
iRe = Module._PsToYUV();
var result = Module._GetOneFrame();
if(result === FRAME_IS_NULL){
continue;
}
else{
var sFramInfo = Module._GetFrameInfo();
var iWidth = sFramInfo.width;
var iHeight = sFramInfo.height;
//var iLine_Fir = sFramInfo.linesize_fir;
//var iLine_Sec = sFramInfo.linesize_sec;
//var iLine_Thi = sFramInfo.linesize_thi;
var iyuv_size = iWidth*iHeight*3/2;
var pYUV = Module._GetBuffer();
var buf = new ArrayBuffer(iyuv_size);
var ayuv_data = new Uint8Array(buf);
ayuv_data.set(Module.HEAPU8.subarray(pYUV,pYUV+iyuv_size));
postMessage({type:"video",buf:ayuv_data.buffer,len:ayuv_data.length,width:iWidth,height:iHeight},[ayuv_data.buffer]);
}
}while(iRe != DECODE_FINISHED)//4 表示解码结束的标志
}
else if(data.type === "stop"){
Module._UnInit();
}
}