ref: 6b542d68181923c61c0fd184b5b40e199630cc89
parent: d54a2b10163d1c743f06ebde69fd4ae74c04fd28
author: Sam Leitch <sam.leitch@calgaryscientific.com>
date: Tue Mar 18 07:09:02 EDT 2014
Added h264 lib that wraps the Crossbridge bits.
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@
node_modules
js/h264bsd_asm.js.map
*.suo
+flex/.settings/
+flex/bin/
--- /dev/null
+++ b/flex/.actionScriptProperties
@@ -1,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<actionScriptProperties analytics="false" mainApplicationPath="h264bsd.as" projectUUID="42d635ed-f4ca-4d17-a420-c8d171b0c706" version="10">
+ <compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="false" fteInMXComponents="false" generateAccessible="false" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="false" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="bin" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="false" useDebugRSLSwfs="true" verifyDigests="true" warn="true">
+ <compilerSourcePath/>
+ <libraryPath defaultLinkType="0">
+ <libraryPathEntry kind="4" path="">
+ <excludedEntries>
+ <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flex.swc" useDefaultLinkType="false"/>
+ <libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/core.swc" useDefaultLinkType="false"/>
+ </excludedEntries>
+ </libraryPathEntry>
+ <libraryPathEntry kind="1" linkType="1" path="lib"/>
+ </libraryPath>
+ <sourceAttachmentPath/>
+ </compiler>
+ <applications>
+ <application path="h264bsd.as"/>
+ </applications>
+ <modules/>
+ <buildCSSFiles/>
+ <flashCatalyst validateFlashCatalystCompatibility="false"/>
+</actionScriptProperties>
--- /dev/null
+++ b/flex/.flexLibProperties
@@ -1,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<flexLibProperties includeAllClasses="true" useMultiPlatformConfig="false" version="3">
+ <includeClasses>
+ <classEntry path="h264bsd.Decoder"/>
+ </includeClasses>
+ <includeResources/>
+ <namespaceManifests/>
+</flexLibProperties>
--- /dev/null
+++ b/flex/.project
@@ -1,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>h264bsd</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.adobe.flexbuilder.project.flexbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.adobe.flexbuilder.project.flexlibnature</nature>
+ <nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
+ </natures>
+</projectDescription>
--- a/flex/Makefile
+++ b/flex/Makefile
@@ -14,8 +14,8 @@
fi
swc: check
- "$(FLASCC)/usr/bin/clang" $(BASE_CFLAGS) $(SOURCES) -emit-swc=h264bsd -o h264bsd.swc
- "$(FLEX)/bin/mxmlc" -static-link-runtime-shared-libraries -compiler.omit-trace-statements=false -library-path=h264bsd.swc -debug=true h264test.as -o h264test.swf
+ "$(FLASCC)/usr/bin/gcc" $(BASE_CFLAGS) $(SOURCES) -emit-swc=h264bsd_asm -o lib/h264bsd_asm.swc
+ "$(FLEX)/bin/mxmlc" -static-link-runtime-shared-libraries -compiler.omit-trace-statements=false -library-path=lib/h264bsd_asm.swc -debug=true test/h264test.as -o test/h264test.swf
clean:
--- a/flex/h264test.as
+++ /dev/null
@@ -1,43 +1,0 @@
-package
-{
- import flash.display.Sprite;
- import flash.text.TextField;
- import flash.events.Event;
- import h264bsd.CModule;
-
- public class h264test extends Sprite
- {
- public function h264test()
- {
- addEventListener(Event.ADDED_TO_STAGE, initCode);
- }
-
- public function initCode(e:Event):void
- {
- CModule.startAsync(this)
-
- var ret:int = 0;
- var tf:TextField = new TextField
- tf.multiline = true
- tf.width = stage.stageWidth
- tf.height = stage.stageHeight
- addChild(tf)
-
- trace("Logging Started...");
-
- var h264:int = 0;
- var args:Vector.<int> = new Vector.<int>;
- h264 = CModule.callI(CModule.getPublicSymbol("h264bsdAlloc"), args);
- tf.appendText("h264bsdAlloc ... " + ( h264 != 0 ? "Success" : "Failure") + "\n");
-
-
- args = new <int>[h264,0];
- ret = CModule.callI(CModule.getPublicSymbol("h264bsdInit"), args);
- tf.appendText("h264bsdInit ... " + ( ret == 0 ? "Success" : "Failure" + ret) + "\n");
-
- args = new <int>[h264];
- CModule.callI(CModule.getPublicSymbol("h264bsdShutdown"), args);
- tf.appendText("h264bsdShutdown ... Success\n");
- }
- }
-}
--- /dev/null
+++ b/flex/src/h264bsd/CroppingInfo.as
@@ -1,0 +1,52 @@
+package h264bsd
+{
+ public class CroppingInfo
+ {
+ private var _width:int = 0;
+ private var _height:int = 0;
+ private var _top:int = 0;
+ private var _left:int = 0;
+ private var _widthUncropped:int = 0;
+ private var _heightUncropped:int = 0;
+
+ public function CroppingInfo(widthUncropped:int, heightUncropped:int, widthCrop:int, heightCrop:int, top:int, left:int) {
+ _widthUncropped = widthUncropped;
+ _heightUncropped = heightUncropped;
+ _width = widthCrop;
+ _height = heightCrop;
+
+ if (_width == 0)
+ _width = _widthUncropped;
+
+ if (_height == 0)
+ _height = _heightUncropped;
+
+ _top = top;
+ _left = left;
+ }
+
+ public function get uncroppedWidth():int {
+ return _widthUncropped;
+ }
+
+ public function get uncroppedHeight():int {
+ return _heightUncropped;
+ }
+
+ public function get width():int {
+ return _width;
+ }
+
+ public function get height():int {
+ return _height;
+ }
+
+ public function get top():int {
+ return _top;
+ }
+
+ public function get left():int {
+ return _left;
+ }
+ }
+}
--- /dev/null
+++ b/flex/src/h264bsd/Decoder.as
@@ -1,0 +1,266 @@
+package h264bsd
+{
+ import flash.display.Bitmap;
+ import flash.display.BitmapData;
+ import flash.events.EventDispatcher;
+ import flash.geom.ColorTransform;
+ import flash.geom.Matrix;
+ import flash.geom.Rectangle;
+ import flash.utils.ByteArray;
+ import flash.utils.Endian;
+ import flash.utils.getQualifiedClassName;
+
+ import h264bsd_asm.CModule;
+
+ import mx.logging.ILogger;
+ import mx.logging.Log;
+
+ [Event(name = "pictureReady", type = "pureweb.client.ui.H264DecoderEvent")]
+ [Event(name = "headersReady", type = "pureweb.client.ui.H264DecoderEvent")]
+ public class Decoder extends EventDispatcher
+ {
+ public static const RDY:int = 0;
+ public static const PIC_RDY:int = 1;
+ public static const HDRS_RDY:int = 2;
+ public static const ERROR:int = 3;
+ public static const PARAM_SET_ERROR:int = 4;
+ public static const MEMALLOC_ERROR:int = 5;
+ public static const NO_INPUT:int = 1024;
+
+ private static var _logger:ILogger = null;
+
+ private var _storagePtr:int = 0;
+ private var _released:Boolean = false;
+ private var _ready:Boolean = false;
+
+ private var _h264bsdAlloc:int = 0;
+ private var _h264bsdInit:int = 0;
+ private var _h264bsdPicWidth:int = 0;
+ private var _h264bsdPicHeight:int = 0;
+ private var _h264bsdNextOutputPicture:int = 0;
+ private var _h264bsdNextOutputPictureBGRA:int = 0;
+ private var _h264bsdDecode:int = 0;
+ private var _h264bsdShutdown:int = 0;
+ private var _h264bsdFree:int = 0;
+ private var _h264bsdCroppingParams:int = 0;
+
+ private var _inputPtr:int = 0;
+ private var _inputOffset:int = 0;
+ private var _inputLength:int = 0;
+
+ public function Decoder() {
+
+ buildFunctionTable();
+ initStorage();
+ clearInputQueue();
+ _ready = false;
+
+ }
+
+ public function release():void {
+ if (_released) return;
+ clearInputQueue();
+ freeStorage();
+ _released = true;
+ }
+
+ public function queueInput(data:ByteArray):void {
+ if(data == null) return;
+
+ if(_inputPtr != 0) {
+ var combinedData:ByteArray = new ByteArray();
+ CModule.readBytes(_inputPtr + _inputOffset, _inputLength - _inputOffset, combinedData);
+
+ combinedData.writeBytes(data);
+ combinedData.position= 0;
+ data = combinedData;
+ }
+
+ _inputLength = data.bytesAvailable;
+ _inputPtr = CModule.malloc(_inputLength);
+ _inputOffset = 0;
+
+ CModule.writeBytes(_inputPtr, _inputLength, data);
+ }
+
+ public function decode():int {
+ if (_inputPtr == 0) return NO_INPUT;
+
+ var bytesReadPtr:int = CModule.malloc(4);
+ var dataPtr:int = _inputPtr + _inputOffset;
+ var length:int = _inputLength - _inputOffset;
+
+ var args:Vector.<int> = new <int>[_storagePtr, dataPtr, length, 0, bytesReadPtr];
+ var result:int = CModule.callI(_h264bsdDecode, args);
+
+ switch(result)
+ {
+ case Decoder.PIC_RDY:
+ dispatchEvent(new DecoderEvent(DecoderEvent.PICTURE_READY));
+ break;
+ case Decoder.HDRS_RDY:
+ dispatchEvent(new DecoderEvent(DecoderEvent.HEADERS_READY));
+ break;
+ }
+
+ var bytesRead:int = CModule.read32(bytesReadPtr);
+ _inputOffset += bytesRead;
+
+ if(_inputOffset >= _inputLength) clearInputQueue();
+
+ if (bytesReadPtr != 0) CModule.free(bytesReadPtr);
+
+ return result;
+ }
+
+ public function getNextOutputPictureBytesBGRA():ByteArray {
+ var picIdPtr:int = CModule.malloc(4);
+ var isIdrPicPtr:int = CModule.malloc(4);
+ var numErrMbsPtr:int = CModule.malloc(4);
+
+ var bytesPtr:int = 0;
+ var args:Vector.<int> = new <int>[_storagePtr, picIdPtr, isIdrPicPtr, numErrMbsPtr];
+ bytesPtr = CModule.callI(_h264bsdNextOutputPictureBGRA, args);
+
+ var bytes:ByteArray = new ByteArray();
+ bytes.endian = Endian.LITTLE_ENDIAN;
+ CModule.readBytes(bytesPtr, outputByteLengthRGBA, bytes);
+ bytes.position = 0;
+
+ if (picIdPtr != 0) CModule.free(picIdPtr);
+ if (isIdrPicPtr != 0) CModule.free(isIdrPicPtr);
+ if (numErrMbsPtr != 0) CModule.free(numErrMbsPtr);
+
+ return bytes;
+ }
+
+ public function getNextOutputPictureBytes():ByteArray {
+ var picIdPtr:int = CModule.malloc(4);
+ var isIdrPicPtr:int = CModule.malloc(4);
+ var numErrMbsPtr:int = CModule.malloc(4);
+
+ var bytesPtr:int = 0;
+ var args:Vector.<int> = new <int>[_storagePtr, picIdPtr, isIdrPicPtr, numErrMbsPtr];
+ bytesPtr = CModule.callI(_h264bsdNextOutputPicture, args);
+
+ var bytes:ByteArray = new ByteArray();
+ bytes.endian = Endian.LITTLE_ENDIAN;
+ CModule.readBytes(bytesPtr, outputByteLength, bytes);
+ bytes.position = 0;
+
+ if (picIdPtr != 0) CModule.free(picIdPtr);
+ if (isIdrPicPtr != 0) CModule.free(isIdrPicPtr);
+ if (numErrMbsPtr != 0) CModule.free(numErrMbsPtr);
+
+ return bytes;
+ }
+
+ public function drawNextOutputPicture(target:Bitmap, transform:Matrix = null):void
+ {
+ var rgbBytes:ByteArray = getNextOutputPictureBytesBGRA();
+
+ var cinfo:CroppingInfo = getCroppingInfo();
+ var outputPicture:BitmapData = new BitmapData(cinfo.uncroppedWidth, cinfo.uncroppedHeight);
+ outputPicture.setPixels(new Rectangle(0,0, cinfo.uncroppedWidth, cinfo.uncroppedHeight), rgbBytes);
+
+ target.bitmapData.lock();
+ target.bitmapData.draw(outputPicture, transform, null, null, new Rectangle(0,0, cinfo.width, cinfo.height), true);
+ target.bitmapData.unlock();
+ }
+
+ private function get outputByteLength():int {
+ return outputWidth * outputHeight * 3 / 2;
+ }
+
+ private function get outputByteLengthRGBA():int {
+ return outputWidth * outputHeight * 4;
+ }
+
+ private function get outputWidth():int {
+ var widthMB:int = CModule.callI(_h264bsdPicWidth, new <int>[_storagePtr]);
+ return widthMB * 16;
+ }
+
+ private function get outputHeight():int {
+ var heightMB:int = CModule.callI(_h264bsdPicHeight, new <int>[_storagePtr]);
+ return heightMB * 16;
+ }
+
+ public function getCroppingInfo():CroppingInfo {
+ var croppingFlagPtr:int = CModule.malloc(4);
+ var leftOffsetPtr:int = CModule.malloc(4);
+ var widthPtr:int = CModule.malloc(4);
+ var topOffsetPtr:int = CModule.malloc(4);
+ var heightPtr:int = CModule.malloc(4);
+
+ var args:Vector.<int> = new <int>[_storagePtr, croppingFlagPtr, leftOffsetPtr, widthPtr, topOffsetPtr, heightPtr];
+ CModule.callI(_h264bsdCroppingParams, args);
+
+ // XXX: Cropping info appears to be broken
+ var result:CroppingInfo = new CroppingInfo(outputWidth, outputHeight, CModule.read32(widthPtr), CModule.read32(heightPtr), CModule.read32(topOffsetPtr), CModule.read32(leftOffsetPtr));
+
+ CModule.free(croppingFlagPtr);
+ CModule.free(leftOffsetPtr);
+ CModule.free(widthPtr);
+ CModule.free(topOffsetPtr);
+ CModule.free(heightPtr);
+
+ return result;
+ }
+
+ private function buildFunctionTable():void {
+ _h264bsdAlloc = CModule.getPublicSymbol("h264bsdAlloc");
+ _h264bsdInit = CModule.getPublicSymbol("h264bsdInit");
+ _h264bsdPicWidth = CModule.getPublicSymbol("h264bsdPicWidth");
+ _h264bsdPicHeight = CModule.getPublicSymbol("h264bsdPicHeight");
+ _h264bsdNextOutputPicture = CModule.getPublicSymbol("h264bsdNextOutputPicture");
+ _h264bsdNextOutputPictureBGRA = CModule.getPublicSymbol("h264bsdNextOutputPictureBGRA");
+ _h264bsdDecode = CModule.getPublicSymbol("h264bsdDecode");
+ _h264bsdShutdown = CModule.getPublicSymbol("h264bsdShutdown");
+ _h264bsdFree = CModule.getPublicSymbol("h264bsdFree");
+ _h264bsdCroppingParams = CModule.getPublicSymbol("h264bsdCroppingParams");
+
+ if (_h264bsdAlloc == 0 ||
+ _h264bsdInit == 0 ||
+ _h264bsdPicWidth == 0 ||
+ _h264bsdPicHeight == 0 ||
+ _h264bsdNextOutputPicture == 0 ||
+ _h264bsdDecode == 0 ||
+ _h264bsdShutdown == 0 ||
+ _h264bsdFree == 0 ||
+ _h264bsdCroppingParams == 0 ||
+ _h264bsdNextOutputPictureBGRA == 0) {
+ throw new Error("One or more missing entries in h264bsd function table.");
+ }
+ }
+
+ private function initStorage():void {
+ if(_storagePtr != 0) return;
+ _storagePtr = CModule.callI(_h264bsdAlloc, new <int>[]);
+ CModule.callI(_h264bsdInit, new <int>[_storagePtr, 0]);
+ }
+
+ private function freeStorage():void {
+ if(_storagePtr != 0) return;
+
+ CModule.callI(_h264bsdShutdown, new <int>[this._storagePtr]);
+ CModule.callI(_h264bsdFree, new <int>[this._storagePtr]);
+ }
+
+ private function clearInputQueue():void {
+ if(_inputPtr == 0) return;
+ CModule.free(_inputPtr);
+ _inputPtr = 0;
+ _inputOffset = 0;
+ _inputLength = 0;
+ }
+
+ private function get logger():ILogger
+ {
+ if(_logger == null)
+ _logger = Log.getLogger(getQualifiedClassName(this).replace("::", "."));
+
+ return _logger;
+ }
+ }
+}
--- /dev/null
+++ b/flex/src/h264bsd/DecoderEvent.as
@@ -1,0 +1,15 @@
+package h264bsd
+{
+ import flash.events.Event;
+
+ public class DecoderEvent extends Event
+ {
+ public static const PICTURE_READY:String = "pictureReady";
+ public static const HEADERS_READY:String = "headersReady";
+
+ public function DecoderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
+ {
+ super(type, bubbles, cancelable);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+++ b/flex/test/h264test.as
@@ -1,0 +1,43 @@
+package
+{
+ import flash.display.Sprite;
+ import flash.text.TextField;
+ import flash.events.Event;
+ import h264bsd.CModule;
+
+ public class h264test extends Sprite
+ {
+ public function h264test()
+ {
+ addEventListener(Event.ADDED_TO_STAGE, initCode);
+ }
+
+ public function initCode(e:Event):void
+ {
+ CModule.startAsync(this)
+
+ var ret:int = 0;
+ var tf:TextField = new TextField
+ tf.multiline = true
+ tf.width = stage.stageWidth
+ tf.height = stage.stageHeight
+ addChild(tf)
+
+ trace("Logging Started...");
+
+ var h264:int = 0;
+ var args:Vector.<int> = new Vector.<int>;
+ h264 = CModule.callI(CModule.getPublicSymbol("h264bsdAlloc"), args);
+ tf.appendText("h264bsdAlloc ... " + ( h264 != 0 ? "Success" : "Failure") + "\n");
+
+
+ args = new <int>[h264,0];
+ ret = CModule.callI(CModule.getPublicSymbol("h264bsdInit"), args);
+ tf.appendText("h264bsdInit ... " + ( ret == 0 ? "Success" : "Failure" + ret) + "\n");
+
+ args = new <int>[h264];
+ CModule.callI(CModule.getPublicSymbol("h264bsdShutdown"), args);
+ tf.appendText("h264bsdShutdown ... Success\n");
+ }
+ }
+}