SimpleFlvWriter 一个动态生成flv的类
2011-10-07 21:48
120 查看
/* SimpleFlvWriter.as Lee Felarca http://www.zeropointnine.com/blog 5-2007 v0.8 Singleton class to create uncompressed FLV files. Does not handle audio. Feel free to extend. Source code licensed under a Creative Commons Attribution 3.0 License. http://creativecommons.org/licenses/by/3.0/ Some Rights Reserved. EXAMPLE USAGE: var myWriter:SimpleFlvWriter = SimpleFlvWriter.getInstance(); myWriter.createFile(myFile, 320,240, 30, 120); myWriter.saveFrame( myBitmapData1 ); myWriter.saveFrame( myBitmapData2 ); myWriter.saveFrame( myBitmapData3 ); // etc. myWriter.closeFile(); */ package { import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; import flash.display.BitmapData; import flash.utils.ByteArray; public class SimpleFlvWriter { static private var _instance:SimpleFlvWriter; private var frameWidth:int; private var frameHeight:int; private var frameRate:Number; private var duration:Number; private var fs:FileStream = new FileStream(); private var f:File; private const blockWidth:int = 32; private const blockHeight:int = 32; private var previousTagSize:uint = 0; private var iteration:int = 0; private var bmp:BitmapData; public static function getInstance():SimpleFlvWriter { if(SimpleFlvWriter._instance == null) SimpleFlvWriter._instance = new SimpleFlvWriter(new SingletonEnforcer()); return SimpleFlvWriter._instance; } public function SimpleFlvWriter(singletonEnforcer:SingletonEnforcer) { } public function createFile(pFile:File, pWidth:int, pHeight:int, pFramesPerSecond:Number, pDurationInSeconds:Number=0):void { /* Parameters: pFile: The file which will be created and written to pWidth: Video height pWidth: Video width pFramesPerSecond: Determines framerate of created video pDurationInSeconds: Duration of video file to be created. Used for metadata only. Optional. */ frameWidth = pWidth; frameHeight = pHeight; frameRate = pFramesPerSecond; duration = pDurationInSeconds; f = pFile; fs.openAsync(f, FileMode.WRITE); // create header fs.writeBytes( header() ); // create metadata tag fs.writeUnsignedInt( previousTagSize ); fs.writeBytes( flvTagOnMetaData() ); } public function saveFrame(pBitmapData:BitmapData):void { // bitmap dimensions should of course match parameters passed to createFile() bmp = pBitmapData; fs.writeUnsignedInt( previousTagSize ); fs.writeBytes( flvTagVideo() ); } public function closeFile():void { fs.close(); } private function header():ByteArray { var ba:ByteArray = new ByteArray(); ba.writeByte(0x46) // 'F' ba.writeByte(0x4C) // 'L' ba.writeByte(0x56) // 'V' ba.writeByte(0x01) // Version 1 ba.writeByte(0x01) // misc flags - video stream only ba.writeUnsignedInt(0x09) // header length return ba; } private function flvTagVideo():ByteArray { var tag:ByteArray = new ByteArray(); var dat:ByteArray = videoData(); var timeStamp:uint = uint(1000/frameRate * iteration++); // tag 'header' tag.writeByte( 0x09 ); // tagType = video writeUI24(tag, dat.length); // data size writeUI24(tag, timeStamp); // timestamp in ms tag.writeByte(0); // timestamp extended, not using *** writeUI24(tag, 0); // streamID always 0 // videodata tag.writeBytes( dat ); previousTagSize = tag.length; return tag; } private function videoData():ByteArray { var v:ByteArray = new ByteArray; // VIDEODATA 'header' v.writeByte(0x13); // frametype (1) + codecid (3) // SCREENVIDEOPACKET 'header' // blockwidth/16-1 (4bits) + imagewidth (12bits) writeUI4_12(v, int(blockWidth/16) - 1, frameWidth); // blockheight/16-1 (4bits) + imageheight (12bits) writeUI4_12(v, int(blockHeight/16) - 1, frameHeight); // VIDEODATA > SCREENVIDEOPACKET > IMAGEBLOCKS: var yMax:int = int(frameHeight/blockHeight); var yRemainder:int = frameHeight % blockHeight; if (yRemainder > 0) yMax += 1; var xMax:int = int(frameWidth/blockWidth); var xRemainder:int = frameWidth % blockWidth; if (xRemainder > 0) xMax += 1; for (var y1:int = 0; y1 < yMax; y1++) { for (var x1:int = 0; x1 < xMax; x1++) { // create block var block:ByteArray = new ByteArray(); var yLimit:int = blockHeight; if (yRemainder > 0 && y1 + 1 == yMax) yLimit = yRemainder; for (var y2:int = 0; y2 < yLimit; y2++) { var xLimit:int = blockWidth; if (xRemainder > 0 && x1 + 1 == xMax) xLimit = xRemainder; for (var x2:int = 0; x2 < xLimit; x2++) { var px:int = (x1 * blockWidth) + x2; var py:int = frameHeight - ((y1 * blockHeight) + y2); // (flv's save from bottom to top) var p:uint = bmp.getPixel(px, py); block.writeByte( p & 0xff ); // blue block.writeByte( p >> 8 & 0xff ); // green block.writeByte( p >> 16 ); // red } } block.compress(); writeUI16(v, block.length); // write block length (UI16) v.writeBytes( block ); // write block } } return v; } private function flvTagOnMetaData():ByteArray { var tag:ByteArray = new ByteArray(); var dat:ByteArray = metaData(); // tag 'header' tag.writeByte( 18 ); // tagType = script data writeUI24(tag, dat.length); // data size writeUI24(tag, 0); // timestamp should be 0 for onMetaData tag tag.writeByte(0); // timestamp extended writeUI24(tag, 0); // streamID always 0 // data tag tag.writeBytes( dat ); previousTagSize = tag.length; return tag; } private function metaData():ByteArray { // onMetaData info goes in a ScriptDataObject of data type 'ECMA Array' var b:ByteArray = new ByteArray(); // ObjectNameType (always 2) b.writeByte(2); // ObjectName (type SCRIPTDATASTRING): writeUI16(b, "onMetaData".length); // StringLength b.writeUTFBytes( "onMetaData" ); // StringData // ObjectData (type SCRIPTDATAVALUE): b.writeByte(8); // Type (ECMA array = 8) b.writeUnsignedInt(7) // // Elements in array // SCRIPTDATAVARIABLES... if (duration > 0) { writeUI16(b, "duration".length); b.writeUTFBytes("duration"); b.writeByte(0); b.writeDouble(duration); } writeUI16(b, "width".length); b.writeUTFBytes("width"); b.writeByte(0); b.writeDouble(frameWidth); writeUI16(b, "height".length); b.writeUTFBytes("height"); b.writeByte(0); b.writeDouble(frameHeight); writeUI16(b, "framerate".length); b.writeUTFBytes("framerate"); b.writeByte(0); b.writeDouble(frameRate); writeUI16(b, "videocodecid".length); b.writeUTFBytes("videocodecid"); b.writeByte(0); b.writeDouble(3); // 'Screen Video' = 3 writeUI16(b, "canSeekToEnd".length); b.writeUTFBytes("canSeekToEnd"); b.writeByte(1); b.writeByte(int(true)); var mdc:String = "SimpleFLVWriter.as v0.8 zeropointnine.com"; writeUI16(b, "metadatacreator".length); b.writeUTFBytes("metadatacreator"); b.writeByte(2); writeUI16(b, mdc.length); b.writeUTFBytes(mdc); // VariableEndMarker1 (type UI24 - always 9) writeUI24(b, 9); return b; } private function writeUI24(stream:*, p:uint):void { var byte1:int = p >> 16; var byte2:int = p >> 8 & 0xff; var byte3:int = p & 0xff; stream.writeByte(byte1); stream.writeByte(byte2); stream.writeByte(byte3); } private function writeUI16(stream:*, p:uint):void { stream.writeByte( p >> 8 ) stream.writeByte( p & 0xff ); } private function writeUI4_12(stream:*, p1:uint, p2:uint):void { // writes a 4-bit value followed by a 12-bit value in two sequential bytes var byte1a:int = p1 << 4; var byte1b:int = p2 >> 8; var byte1:int = byte1a + byte1b; var byte2:int = p2 & 0xff; stream.writeByte(byte1); stream.writeByte(byte2); } } } class SingletonEnforcer {} /* FLV structure summary: header previoustagsize flvtag [info] videodata [info] screenvideopacket [info] imageblocks imageblocks ... previoustagsize flvtag ... FLV file format: header last tag size FLVTAG: tagtype datasize timestamp timestampextended streamid data [VIDEODATA]: frametype codecid videodata [SCREENVIDEOPACKET]: blockwidth ub[4] imagewidth ub[12] blockheight ub[4] imageheight ub[12] imageblocks [IMAGEBLOCKS[]]: datasize ub[16] <same as 'ub16', i think> data.. last tag size FLVTAG etc. */
相关文章推荐
- 讨论一下hibernate如何动态注册一个动态生成的实体类
- 在JSP中动态生成随机验证码,登录时后台校验验证码,以及如何避免同一个验证码被重复提交爆破密码
- java中如何使用asm动态的生成或修改一个class文件以及asm的架构思想
- 一个动态生成脚本的例子
- 动态生成GRIDVIEW,将两个表数据绑定到一个GRIDVIEW中.
- php动态生成一个xml文件供swf调用
- ASP.NET中动态的生成一个图片
- 动态生成数组保存:已知一个数组20个元素(随机 1~100之间包含1和100),求大于平均数的元素个数,并动态生成一个新数组保存
- DWR动态在javascript里生成一个AjaxService类
- 控制一个动态生成view 的位置
- 写一个程序,能够动态生成多条插入语句如:insert into MyStudents values(“人名1”,年龄,‘男’,分数1,分数2)。将生成的插入语句输出到记事本文件 SQLStr.txt中
- R语言-networkd3.生成一个基于html的插件,可以动态交互,
- 一个用于动态生成静态页面的类——TextTemplate
- C#写的一个用于动态生成静态页面的类
- 提供一个动态生成word的方案
- 发布一个类似Subsonic语法的动态生成SQL语句,并可以返回相应实体类的一个组件
- 输入一个数组长度,动态创建数组,所有元素随机生成,输出元素中的最大值
- 动态生成一个textview,设置padding不起作用的解决办法。
- mybatis if 动态生成SQL的一个注意点 parameterType="map"
- 通过freemarker生成一个word,解决生成的word用wps打开有问题的问题,解决出word时中文文件名乱码问题,解决打开出word时打开的word出现问题的问题,出图片,解决动态列表