参考资料:
http://blog.csdn.net/sunnylion1982/article/details/38376453
http://blog.csdn.net/happydeer/article/details/8775
http://blog.csdn.net/zhujinghao_09/article/details/44458245
https://github.com/Sebmaster/avi.js
http://blog.csdn.net/yi7900/article/details/7481599
代码:
debugger;
var record=new Worker("/js/media/record.js")
record.onmessage=function (e) {
if(e.data.type=="blob"){
var blob=e.data.data
var a=document.createElement("a")
var url=URL.createObjectURL(blob)
a.href=url
document.documentElement.appendChild(a)
a.download="guxi.avi"
a.id="guxi"
a.click()
}
}
代码:
"use strict";
(function() {
/**
* @param {Uint8Array} buf
* @param {number} idx
* @param {Array.<number>} bytes
*/
function writeBytes(buf, idx, bytes) {
for (var i=0; i < bytes.length; ++i) {
buf[idx + i] = bytes[i];
}
}
/**
* @param {Uint8Array} buf
* @param {number} idx
* @param {number} num
*/
function writeShort(buf, idx, num) {
buf[idx] = num & 255;
buf[idx + 1] = (num >> 8) & 255;
}
/**
* @param {Uint8Array} buf
* @param {number} idx
* @param {number} num
*/
function writeInt(buf, idx, num) {
buf[idx] = num & 255;
buf[idx + 1] = (num >> 8) & 255;
buf[idx + 2] = (num >> 16) & 255;
buf[idx + 3] = (num >> 24) & 255;
}
/**
* @param {number} idx
* @param {string} str
*/
function writeString(buf, idx, str) {
for (var i=0; i < str.length; ++i) {
buf[idx + i] = str.charCodeAt(i) & 255;
}
}
///////////////////////////////////////////////////////avi数据结构
//12 "RIFF" SIZE(TYPE+DATA) "AVI "
//12 "LIST" SIZE(TYPE+DATA) "hdrl"
//64 AVIMAINHEADER数据结构--"avih" 56+8=64
//12 "LIST" SIZE "strl"
//"strh" AVISTREAMHEADER 数据结构 64=56+8
//"strf" BITMAPINFO数据结构 或 WAVEFORMATEX数据结构 48=40+8 或 38=30+8
//多个流 两个 视频+音频
//12 LIST size MOVI
///////////////////////////////////////////////////////////////////
/**
* @constructor
*/
function AVIJS(width,height,fps) {
this.settings = {
"width": width,
"height": height,
"fps":fps
};
/** @type {Array.<Object{"data","type"}>} */
this.frames = [];
};
AVIJS.prototype.getBuffer = function() {
var headerInfoNum=88+124;
var frames=this.frames.length//所有帧
var vframe=0;//视频帧
var aframe=0;//音频帧
var bytes=0;//所有帧的字节数
for(var i=0;i<this.frames.length;i++){
if(this.frames[i].type=="video"){
vframe++
}else{
aframe++
}
bytes+=this.frames[i].data.length+(this.frames[i].data.length%2==0?0:1)
}
var dataNum=frames*8+12+bytes;//数据及其头的字节数
var buffer = new Uint8Array(headerInfoNum + dataNum);
//前88位
writeString(buffer, 0, 'RIFF');
writeInt(buffer, 4, headerInfoNum + dataNum-8);
writeString(buffer, 8, 'AVI ');
writeString(buffer, 12, 'LIST');
writeInt(buffer, 16, headerInfoNum-20);//88+124+114
writeString(buffer, 20, 'hdrl');
//AVIMAINHEADER数据结构
writeString(buffer, 24, 'avih');
writeInt(buffer, 28, 56);
writeInt(buffer, 32, 1000000/this.settings.fps);
writeInt(buffer, 36, 0);
writeInt(buffer, 40, 0);
writeInt(buffer, 44, 0);
writeInt(buffer, 48, 0);
writeInt(buffer, 52, 0); //为交互格式指定初始帧数(非交互格式应该指定为0)
writeInt(buffer, 56, 2);
writeInt(buffer, 60, 0);
writeInt(buffer, 64, this.settings.width);
writeInt(buffer, 68, this.settings.height);
writeInt(buffer, 72, 0);
writeInt(buffer, 76, 0);
writeInt(buffer, 80, 0);
writeInt(buffer, 84, 0);
//视频头信息 124
var vbuf=new Uint8Array(124)
writeString(vbuf, 0, 'LIST');
writeInt(vbuf, 4, 116);
writeString(vbuf, 8, 'strl');
writeString(vbuf, 12, 'strh');
writeInt(vbuf, 16, 56);
writeString(vbuf, 20, 'vids'); //流的类型
writeString(vbuf, 24, 'H264'); //解码器
writeInt(vbuf, 28, 0); //标记:是否允许这个流输出?调色板是否变化?
writeShort(vbuf, 32, 0); // Priority
writeShort(vbuf, 34, 0); // Language
writeInt(vbuf, 36, 0); // Initial frames
writeInt(vbuf, 40, 1); // Scale
writeInt(vbuf, 44, this.settings.fps*1); // Rate:fps*scale
writeInt(vbuf, 48, 0); // Startdelay
writeInt(vbuf, 52, 500); // Length
writeInt(vbuf, 56, 0); // suggested buffer size
writeInt(vbuf, 60, 0); // quality
writeInt(vbuf, 64, 0); // sampleSize
writeShort(vbuf, 68, 0); // Rect left
writeShort(vbuf, 70, 0); // Rect top
writeShort(vbuf, 72, this.settings.width); // Rect width
writeShort(vbuf, 74, this.settings.height); // Rect height
writeString(vbuf, 76, 'strf');
writeInt(vbuf, 80, 40);
writeInt(vbuf, 84, 40); // struct size
writeInt(vbuf, 88, this.settings.width); // width
writeInt(vbuf, 92, this.settings.height); // height
writeShort(vbuf, 96, 1); // planes
writeShort(vbuf, 98, 16); // bits per pixel
writeString(vbuf, 100, "H264"); // compression
writeInt(vbuf, 104, 0); // image size 是否乘以3????
writeInt(vbuf, 108, 0); // x pixels per meter
writeInt(vbuf, 112, 0); // y pixels per meter
writeInt(vbuf, 116, 0); // colortable used
writeInt(vbuf, 120, 0); // colortable important
buffer.set(vbuf,88);
// //音频头信息 114
// var abuf=new Uint8Array(114);
// writeString(abuf, 0, 'LIST');
// writeInt(abuf, 4, 106);
// writeString(abuf, 8, 'strl');
// writeString(abuf, 12, 'strh');
// writeInt(abuf, 16, 56);
// writeString(abuf, 20, 'auds'); //流的类型
// writeString(abuf, 24, 'PCM '); //解码器 0x55
// writeInt(abuf, 28, 0); //标记
// writeShort(abuf, 32, 0); // Priority
// writeShort(abuf, 34, 0); // Language
// writeInt(abuf, 36, 0); // Initial frames
// writeInt(abuf, 40, 1); // Scale
// writeInt(abuf, 44, 30); // Rate 0x5dc0
// writeInt(abuf, 48, 0); // Startdelay
// writeInt(abuf, 52, frames-500); // Length 0x1d19c0
// writeInt(abuf, 56, 1024*1024); // suggested buffer size 0x240
// writeInt(abuf, 60, 0xffffffff); // quality
// writeInt(abuf, 64, 0);
// writeShort(abuf, 68, 0);
// writeShort(abuf, 70, 0);
// writeShort(abuf, 72, 0);
// writeShort(abuf, 74, 0);
// //WAVEFORMATEX数据结构
// writeString(abuf, 76, 'strf');
// writeInt(abuf, 80, 30);
// writeShort(abuf,84,1)//wFormatTag pcm
// writeShort(abuf,86,1)//nChannels 通道
// writeInt(abuf,88,8000)//nSamplesPerSec 采样率
// writeInt(abuf,92,16000)//nAvgBytesPerSec 平均数据传输率
// writeShort(abuf,96,2)//nBlockAlign 最小数据的原子大小
// writeShort(abuf,98,0)//wBitsPerSample
// writeShort(abuf,100,0)//cbSize
// writeShort(abuf,102,1)
// writeShort(abuf,104,2)
// writeShort(abuf,106,0)
// writeShort(abuf,108,32772)
// writeShort(abuf,110,1)
// writeShort(abuf,112,0)
// buffer.set(abuf,212);
writeString(buffer,headerInfoNum,"LIST")
writeInt(buffer,headerInfoNum+4,dataNum-8)
writeString(buffer,headerInfoNum+8,"movi")
var offset=headerInfoNum+12;
for(var i=0;i<this.frames.length;i++){
var tmpnum=this.frames[i].data.length+8+(this.frames[i].data.length%2==0?0:1)
var tmp=new Uint8Array(tmpnum)
if(this.frames[i].type=="video"){
writeString(tmp,0,"00dc")
}else{
writeString(tmp,0,"01wb")
}
writeInt(tmp,4,tmpnum-8)
writeBytes(tmp,8,this.frames[i].data)
buffer.set(tmp,offset)
offset+=tmpnum
}
var blob;
try {
blob = new Blob([buffer.buffer], { 'type' : 'video/msvideo' });
} catch (e) {
var builder = new (typeof BlobBuilder !== 'undefined' ? BlobBuilder : WebKitBlobBuilder)();
builder.append(buffer.buffer);
blob = builder.getBlob('video/msvideo');
}
return blob;
};
var scope = new Function('return this')();
scope['AVIJS'] = AVIJS;
})();