From 9ae46145954c4ab39b0313d9627d4b57342b40fe Mon Sep 17 00:00:00 2001 From: Nathan Dinsmore Date: Tue, 24 Jun 2014 12:52:47 -0400 Subject: [PATCH] Fixed whitespace and formatting in util.SimpleFlvWriter --- src/util/SimpleFlvWriter.as | 549 ++++++++++++++++++------------------ 1 file changed, 267 insertions(+), 282 deletions(-) diff --git a/src/util/SimpleFlvWriter.as b/src/util/SimpleFlvWriter.as index eb77f62..4ca6604 100644 --- a/src/util/SimpleFlvWriter.as +++ b/src/util/SimpleFlvWriter.as @@ -23,295 +23,280 @@ 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.saveFrame(myBitmapData1); + myWriter.saveFrame(myBitmapData2); + myWriter.saveFrame(myBitmapData3); // etc. */ - + package util { - import flash.display.BitmapData; - import flash.net.*; - import flash.utils.ByteArray; + import flash.display.BitmapData; + import flash.net.*; + 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; + static private var _instance:SimpleFlvWriter; - private var fs:ByteArray = new ByteArray(); - private const blockWidth:int = 32; - private const blockHeight:int = 32; - private var previousTagSize:uint = 0; - private var iteration:int = 0; - private var bmp:BitmapData; - + private var frameWidth:int; + private var frameHeight:int; + private var frameRate:Number; + private var duration:Number; - public static function getInstance():SimpleFlvWriter - { - if(SimpleFlvWriter._instance == null) - SimpleFlvWriter._instance = new SimpleFlvWriter(new SingletonEnforcer()); - return SimpleFlvWriter._instance; + private var fs:ByteArray = new ByteArray(); + 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()); } - - public function SimpleFlvWriter(singletonEnforcer:SingletonEnforcer) - { - } - - public function createFile(bytes:ByteArray, 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; - - fs = bytes; - - // 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() ); - } - - 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); - } + return SimpleFlvWriter._instance; } -} + + public function SimpleFlvWriter(singletonEnforcer:SingletonEnforcer) {} + + public function createFile(bytes:ByteArray, 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; + + fs = bytes; + + // 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()); + } + + 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 {} @@ -332,20 +317,20 @@ class SingletonEnforcer {} previoustagsize flvtag ... - + FLV file format: - + header - + last tag size - + FLVTAG: tagtype datasize timestamp timestampextended - streamid + streamid data [VIDEODATA]: frametype codecid @@ -354,13 +339,13 @@ class SingletonEnforcer {} imagewidth ub[12] blockheight ub[4] imageheight ub[12] - imageblocks [IMAGEBLOCKS[]]: + imageblocks [IMAGEBLOCKS[]]: datasize ub[16] data.. - + last tag size - + FLVTAG - - etc. + + etc. */