mirror of
https://github.com/scratchfoundation/scratch-flash.git
synced 2024-12-04 21:21:06 -05:00
Fixed whitespace and formatting in util.SimpleFlvWriter
This commit is contained in:
parent
3ca6d42232
commit
9ae4614595
1 changed files with 267 additions and 282 deletions
|
@ -23,295 +23,280 @@
|
||||||
http://www.zeropointnine.com/blog
|
http://www.zeropointnine.com/blog
|
||||||
5-2007
|
5-2007
|
||||||
v0.8
|
v0.8
|
||||||
|
|
||||||
Singleton class to create uncompressed FLV files.
|
Singleton class to create uncompressed FLV files.
|
||||||
Does not handle audio. Feel free to extend.
|
Does not handle audio. Feel free to extend.
|
||||||
|
|
||||||
Source code licensed under a Creative Commons Attribution 3.0 License.
|
Source code licensed under a Creative Commons Attribution 3.0 License.
|
||||||
http://creativecommons.org/licenses/by/3.0/
|
http://creativecommons.org/licenses/by/3.0/
|
||||||
Some Rights Reserved.
|
Some Rights Reserved.
|
||||||
|
|
||||||
EXAMPLE USAGE:
|
EXAMPLE USAGE:
|
||||||
|
|
||||||
var myWriter:SimpleFlvWriter = SimpleFlvWriter.getInstance();
|
var myWriter:SimpleFlvWriter = SimpleFlvWriter.getInstance();
|
||||||
myWriter.createFile(myFile, 320,240, 30, 120);
|
myWriter.createFile(myFile, 320,240, 30, 120);
|
||||||
myWriter.saveFrame( myBitmapData1 );
|
myWriter.saveFrame(myBitmapData1);
|
||||||
myWriter.saveFrame( myBitmapData2 );
|
myWriter.saveFrame(myBitmapData2);
|
||||||
myWriter.saveFrame( myBitmapData3 ); // etc.
|
myWriter.saveFrame(myBitmapData3); // etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package util {
|
package util {
|
||||||
import flash.display.BitmapData;
|
import flash.display.BitmapData;
|
||||||
import flash.net.*;
|
import flash.net.*;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
|
|
||||||
public class SimpleFlvWriter {
|
public class SimpleFlvWriter {
|
||||||
static private var _instance: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:ByteArray = new ByteArray();
|
private var frameWidth:int;
|
||||||
private const blockWidth:int = 32;
|
private var frameHeight:int;
|
||||||
private const blockHeight:int = 32;
|
private var frameRate:Number;
|
||||||
private var previousTagSize:uint = 0;
|
private var duration:Number;
|
||||||
private var iteration:int = 0;
|
|
||||||
private var bmp:BitmapData;
|
|
||||||
|
|
||||||
|
|
||||||
public static function getInstance():SimpleFlvWriter
|
private var fs:ByteArray = new ByteArray();
|
||||||
{
|
private const blockWidth:int = 32;
|
||||||
if(SimpleFlvWriter._instance == null)
|
private const blockHeight:int = 32;
|
||||||
SimpleFlvWriter._instance = new SimpleFlvWriter(new SingletonEnforcer());
|
private var previousTagSize:uint = 0;
|
||||||
return SimpleFlvWriter._instance;
|
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(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
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 {}
|
class SingletonEnforcer {}
|
||||||
|
|
||||||
|
@ -332,20 +317,20 @@ class SingletonEnforcer {}
|
||||||
previoustagsize
|
previoustagsize
|
||||||
flvtag
|
flvtag
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
FLV file format:
|
FLV file format:
|
||||||
|
|
||||||
header
|
header
|
||||||
|
|
||||||
last tag size
|
last tag size
|
||||||
|
|
||||||
FLVTAG:
|
FLVTAG:
|
||||||
tagtype
|
tagtype
|
||||||
datasize
|
datasize
|
||||||
timestamp
|
timestamp
|
||||||
timestampextended
|
timestampextended
|
||||||
streamid
|
streamid
|
||||||
data [VIDEODATA]:
|
data [VIDEODATA]:
|
||||||
frametype
|
frametype
|
||||||
codecid
|
codecid
|
||||||
|
@ -354,13 +339,13 @@ class SingletonEnforcer {}
|
||||||
imagewidth ub[12]
|
imagewidth ub[12]
|
||||||
blockheight ub[4]
|
blockheight ub[4]
|
||||||
imageheight ub[12]
|
imageheight ub[12]
|
||||||
imageblocks [IMAGEBLOCKS[]]:
|
imageblocks [IMAGEBLOCKS[]]:
|
||||||
datasize ub[16] <same as 'ub16', i think>
|
datasize ub[16] <same as 'ub16', i think>
|
||||||
data..
|
data..
|
||||||
|
|
||||||
last tag size
|
last tag size
|
||||||
|
|
||||||
FLVTAG
|
FLVTAG
|
||||||
|
|
||||||
etc.
|
etc.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue