{"id":1690,"date":"2009-12-02T11:19:41","date_gmt":"2009-12-02T16:19:41","guid":{"rendered":"http:\/\/www.walking-productions.com\/notslop\/?p=1690"},"modified":"2009-12-02T11:23:25","modified_gmt":"2009-12-02T16:23:25","slug":"flash-media-server-sending-images","status":"publish","type":"post","link":"http:\/\/www.walking-productions.com\/notslop\/2009\/12\/02\/flash-media-server-sending-images\/","title":{"rendered":"Flash Media Server Sending Images"},"content":{"rendered":"<p>One of my students in my <a href=\"http:\/\/itp.nyu.edu\/~sve204\/liveweb_fall2009\">live web class<\/a> is developing an interesting application that sends screenshots to other people.  I put together some sample code to help him along and thought this would be of general interest.<\/p>\n<p>Using the Flash Media Server with Remote Shared Objects this can be built.  Here is a walk through of the code:<\/p>\n<p>First of all, this uses the JPGEncoder class from the <a href=\"http:\/\/code.google.com\/p\/as3corelib\/\">AS3CoreLib<\/a> so you probably want to grab that and import it.<\/p>\n<pre>\r\n\timport com.adobe.images.JPGEncoder;\r\n<\/pre>\n<p>This example uses a SharedObject, a NetConnection and NetStreams for sending the video as well as the screen shots.  Once the NetConnection is established, the SharedObject can be setup:<\/p>\n<pre>\r\n        \/\/ Listener for connection\r\n        private function connectionHandler (e:NetStatusEvent):void \r\n        { \r\n        \t\/\/ If we are connected\r\n             if (e.info.code == \"NetConnection.Connect.Success\") \r\n             {\r\n\t\t\t\t\/\/ Set up the shared object\r\n\t\t\t\t\/\/ We'll call it SimpleSO, pass in the app url and not make it persistent\r\n\t\t\t\tsharedObject = SharedObject.getRemote(\"SimpleSO\",nc.uri,false);\r\n\t\t\t\t\r\n\t\t\t\t\/\/ Tell the shared object to call methods in this class if requested\r\n\t\t\t\tsharedObject.client = this;\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\/\/ Add a listener for when shared object is changed\r\n\t\t\t   \tsharedObject.addEventListener (SyncEvent.SYNC,syncEventCallBack); \r\n\r\n\t\t\t\t\/\/ Connect the shared object to our netConnection\r\n\t\t\t\tsharedObject.connect(nc);\r\n\t\t\t\t\r\n\t\t\t\t\/\/ All of the video streaming setup\r\n\t\t\t\tdoEverything();\r\n\t\t\t\t\r\n\t\t\t\t\/\/ Register mouseclicks, how we'll determine when to send a frame\r\n\t\t\t\tstage.addEventListener(MouseEvent.MOUSE_DOWN, saveFrame);\r\n             } \r\n        }\r\n<\/pre>\n<p>Here is the method that is called when the mouse is clicked.  It creates a bitmapdata object, encodes as a JPEG and sends that as a bytearray through the shared object:<\/p>\n<pre>\r\n        private function saveFrame(e:MouseEvent):void\r\n        {        \r\n        \t\/\/ Save the frame to the bitmapdata object\r\n        \tvar bmpd:BitmapData = new BitmapData(320,240);\r\n        \tbmpd.draw(videoIn1);\r\n                \t\r\n        \t\/\/ First encode as JPEG so it is smaller\r\n\t\t\tvar jpgEncoder:JPGEncoder = new JPGEncoder(100);\r\n\t\t\tvar jpgByteArray:ByteArray = jpgEncoder.encode(bmpd);\r\n\t\t\t\r\n\t\t\t\/\/ Send it via the shared object\r\n\t\t\tsharedObject.send(\"newBitmap\",jpgByteArray);\r\n        }\r\n<\/pre>\n<p>The SharedObject.send method calls the function &#8220;newBitmap&#8221; on everyone who is connected and passes in the jpgByteArray.  The newBitmap function uses the Loader to uncompress the JPG and when it is done calls &#8220;gotBitmapData&#8221;:<\/p>\n<pre>\r\n\t\tpublic function newBitmap(jpgByteArray:ByteArray):void\r\n\t\t{\r\n\t\t\tvar loader:Loader = new Loader();\r\n\t\t\tloader.contentLoaderInfo.addEventListener(Event.COMPLETE, gotBitmapData)\r\n\t\t\tloader.loadBytes(jpgByteArray);\r\n\t\t}\r\n<\/pre>\n<p>gotBitmap data just creates a regular Bitmap and displays it:<\/p>\n<pre>\r\n\tprivate function gotBitmapData(e:Event):void\r\n\t{\r\n\t\tvar decodedBitmapData:BitmapData = Bitmap(e.target.content).bitmapData\r\n\r\n        \t\/\/ Create the bitmap image\r\n        \tvar bmp:Bitmap = new Bitmap(decodedBitmapData);\r\n        \t\r\n        \t\/\/ Add it to the stage\r\n        \tbmp.x = 0;\r\n        \tbmp.y = 240;\r\n        \taddChild(bmp);\t\t\t\r\n\t}\r\n<\/pre>\n<p>Here is the full AS3 class (it could be improved but it works):<\/p>\n<pre>\r\npackage\r\n{\r\n\t\/\/ Import JPEGEncoder Class from: http:\/\/code.google.com\/p\/as3corelib\/\r\n\timport com.adobe.images.JPGEncoder;\r\n\r\n\timport flash.display.Sprite; \r\n\timport flash.display.MovieClip; \r\n\timport flash.events.NetStatusEvent; \r\n\timport flash.net.NetConnection; \r\n\timport flash.net.NetStream; \r\n\timport flash.media.Camera; \r\n\timport flash.media.Microphone; \r\n\timport flash.media.Video; \r\n\timport flash.display.Bitmap;\r\n\timport flash.display.BitmapData;\r\n\timport flash.events.MouseEvent;\r\n\timport flash.utils.ByteArray;\r\n\timport flash.net.SharedObject; \r\n  \timport flash.events.SyncEvent; \r\n  \timport flash.events.Event;\r\n\timport flash.display.Loader;\r\n\r\n\tpublic class VideoCapture extends Sprite\r\n\t{\r\n\t\t\/\/ Shared Object for communication\r\n   \t\tprivate var sharedObject:SharedObject;\r\n\r\n \t\t\/\/ Overall NetConnection for communicating with FMS\r\n        private var nc:NetConnection; \r\n        \r\n        \/\/ RTMP URL, same as directory on FMS\r\n        private var rtmpURL:String = \"rtmp:\/\/xxxx\/webcam\";\r\n         \r\n        \/\/ NetStreams for each stream \r\n        private var netStreamOut:NetStream; \r\n        private var netStreamIn1:NetStream; \r\n        \r\n        \/\/ Camera\r\n        private var camera:Camera; \r\n        \/\/ Microphone\r\n        private var microphone:Microphone; \r\n                \r\n        \/\/ My Video\r\n        private var videoOut:Video; \r\n        \r\n        \/\/ Video Components\r\n        private var videoIn1:Video; \r\n        \r\n        \/\/ Stream Names\r\n        private var outStream:String; \r\n        private var inStream1:String; \r\n\r\n        public function VideoCapture() \r\n        { \r\n        \t\/\/ Construct NetConnection and connect to server\r\n             nc = new NetConnection(); \r\n             nc.connect(rtmpURL); \r\n             \r\n             \/\/ Add a listener for connection\r\n             nc.addEventListener (NetStatusEvent.NET_STATUS,connectionHandler); \r\n        } \r\n        \r\n        \r\n        \/\/ Listener for connection\r\n        private function connectionHandler (e:NetStatusEvent):void \r\n        { \r\n        \t\/\/ If we are connected\r\n             if (e.info.code == \"NetConnection.Connect.Success\") \r\n             {\r\n\r\n\t\t\t\t\/\/ Set up the shared object\r\n\t\t\t\t\/\/ We'll call it SimpleSO, pass in the app url and not make it persistent\r\n\t\t\t\tsharedObject = SharedObject.getRemote(\"SimpleSO\",nc.uri,false);\r\n\t\t\t\t\r\n\t\t\t\t\/\/ Tell the shared object to call methods in this class if requested\r\n\t\t\t\tsharedObject.client = this;\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\/\/ Connect the shared object to our netConnection\r\n\t\t\t\tsharedObject.connect(nc);\r\n\t\t\t\t\r\n\t\t\t\t\/\/ All of the video streaming\r\n\t\t\t\tdoEverything();\r\n\t\t\t\t\r\n\t\t\t\t\/\/ Register mouseclicks, how we'll determine when to send a frame\r\n\t\t\t\tstage.addEventListener(MouseEvent.MOUSE_DOWN, saveFrame);\r\n             } \r\n        }\r\n        \r\n        \/\/ Gets the results from the server\r\n        private function doEverything():void \r\n        { \r\n        \t\/\/ Name of streams\r\n\t\t\toutStream=\"one\"; \r\n\t\t\tinStream1=\"one\"; \r\n        \r\n\t\t\t\/\/ Setup the camera        \r\n\t\t\tcamera = Camera.getCamera(); \r\n\r\n\t\t\t\/\/ setup the microphone             \r\n\t\t\tmicrophone = Microphone.getMicrophone(); \r\n\r\n\t\t\t\/\/ Video components\r\n\t\t\tvideoOut = new Video(); \r\n    \t\tvideoIn1 = new Video();\r\n\r\n\t\t\t\/\/ Set positions \r\n\t\t\tvideoOut.x = 0;\r\n\t\t\tvideoOut.y = 0;\r\n\t\t\tvideoIn1.x = 320;\r\n\t\t\tvideoIn1.y = 0;\r\n\r\n\t\t\t\/\/ Add them to the screen\r\n\t\t\taddChild(videoOut);\r\n\t\t\taddChild(videoIn1);\r\n\r\n            \/\/ Publish our stream\r\n            netStreamOut = new NetStream(nc); \r\n            netStreamOut.attachAudio(microphone); \r\n            netStreamOut.attachCamera(camera); \r\n            netStreamOut.publish(outStream, \"live\"); \r\n             \r\n            \/\/ Attach camera to our video \r\n            videoOut.attachCamera(camera); \r\n             \r\n            \/\/Play incoming streamed video \r\n            netStreamIn1 = new NetStream(nc); \r\n\r\n\t\t\tvideoIn1.attachNetStream(netStreamIn1);\r\n\r\n\t\t\tnetStreamIn1.play(inStream1);\r\n        }\r\n        \r\n        private function saveFrame(e:MouseEvent):void\r\n        {        \r\n        \t\/\/ Save the frame to the bitmapdata object\r\n        \tvar bmpd:BitmapData = new BitmapData(320,240);\r\n        \tbmpd.draw(videoIn1);\r\n                \t\r\n        \t\/\/ First encode as JPEG so it is smaller\r\n\t\t\tvar jpgEncoder:JPGEncoder = new JPGEncoder(100);\r\n\t\t\tvar jpgByteArray:ByteArray = jpgEncoder.encode(bmpd);\r\n\t\t\t\r\n\t\t\t\/\/ Send it via the shared object\r\n\t\t\tsharedObject.send(\"newBitmap\",jpgByteArray);\r\n        }\r\n        \r\n\t\t\r\n\t\tpublic function newBitmap(jpgByteArray:ByteArray):void\r\n\t\t{\r\n\t\t\tvar loader:Loader = new Loader();\r\n\t\t\tloader.contentLoaderInfo.addEventListener(Event.COMPLETE, gotBitmapData)\r\n\t\t\tloader.loadBytes(jpgByteArray);\r\n\t\t}\r\n\t\t\r\n\t\tprivate function gotBitmapData(e:Event):void\r\n\t\t{\r\n\t\t\tvar decodedBitmapData:BitmapData = Bitmap(e.target.content).bitmapData\r\n\r\n        \t\/\/ Create the bitmap image\r\n        \tvar bmp:Bitmap = new Bitmap(decodedBitmapData);\r\n        \t\r\n        \t\/\/ Add it to the stage\r\n        \tbmp.x = 0;\r\n        \tbmp.y = 240;\r\n        \taddChild(bmp);\t\t\t\r\n\t\t}\r\n\t} \r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>One of my students in my live web class is developing an interesting application that sends screenshots to other people. I put together some sample code to help him along and thought this would be of general interest. Using the Flash Media Server with Remote Shared Objects this can be built. Here is a walk &hellip; <a href=\"http:\/\/www.walking-productions.com\/notslop\/2009\/12\/02\/flash-media-server-sending-images\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Flash Media Server Sending Images<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,76,41,22,13,42],"tags":[78,77,79,129,80,81,84,85,86,83,82,126],"class_list":["post-1690","post","type-post","status-publish","format-standard","hentry","category-development","category-flash","category-itp","category-open-source","category-streaming-and-multi-media","category-video","tag-actionscript","tag-as3","tag-bitmapdata","tag-flash","tag-flashmediaserver","tag-fms","tag-frame","tag-send","tag-sharedobject","tag-snapshot","tag-streaming","tag-video"],"_links":{"self":[{"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/posts\/1690","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/comments?post=1690"}],"version-history":[{"count":3,"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/posts\/1690\/revisions"}],"predecessor-version":[{"id":1692,"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/posts\/1690\/revisions\/1692"}],"wp:attachment":[{"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/media?parent=1690"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/categories?post=1690"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.walking-productions.com\/notslop\/wp-json\/wp\/v2\/tags?post=1690"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}