shithub: h264bsd

Download patch

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");  
+    }
+  }
+}