Created
October 25, 2013 19:04
-
-
Save jcward/7160092 to your computer and use it in GitHub Desktop.
A simple example of playing a video stream in Flash (and vlc commands for serving the stream)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Streaming Video Test | |
* | |
* References: | |
* ----------- | |
* http://serverfault.com/questions/288137/how-to-stream-live-video-from-a-linux-server | |
* https://wiki.videolan.org/Stream_VLC_to_Website_with_asf_and_Flash#Method_2_H264_and_Flash_.flv | |
* http://blog.morscad.com/code-snippets/creating-a-video-player-in-as3-using-netstream/ | |
* | |
* Sample videos: | |
* -------------- | |
* http://www.divx.com/en/devices/profiles/video | |
* | |
* The following commands use VLC to stream from the network (server) to | |
* the client (AIR app): | |
* | |
* FLV format in FLV container: | |
* > vlc BigBuckBunny_DivX_HD720p_ASP.divx --sout '#transcode{vcodec=FLV1,vb=4096,acodec=mpga,ab=128,samplerate=44100}:std{access=http{mime=video/x-flv},mux=ffmpeg{mux=flv},dst=0.0.0.0:8081/stream.flv}' | |
* | |
* h264 format in FLV container: | |
* > vlc BigBuckBunny_DivX_HD720p_ASP.divx --sout '#transcode{vcodec=h264,vb=4096,acodec=mp3,ab=128,samplerate=44100}:std{access=http{mime=video/x-flv},mux=ffmpeg{mux=flv},dst=0.0.0.0:8081/stream.flv | |
*/ | |
package | |
{ | |
import flash.media.SoundTransform; | |
import flash.media.Video; | |
import flash.net.NetConnection; | |
import flash.net.NetStream; | |
import flash.display.Sprite; | |
[SWF( width="1920", height="1080", backgroundColor="#232323", frameRate="30" )] | |
public class StreamVideo extends Sprite | |
{ | |
// Enter the IP address of the computer running the above VLC commands: | |
private static const SERVER_IP:String = "10.0.1.3"; | |
public function StreamVideo():void | |
{ | |
stage.frameRate = 30; | |
stage.align = 'topLeft'; | |
var customClient = new Object(); | |
customClient.onMetaData = metaDataHandler; | |
var nc = new NetConnection(); | |
nc.connect(null); | |
var ns = new NetStream(nc); | |
ns.client = customClient; | |
var vid:Video = new StageVideoProxy(1280, 720); | |
vid.attachNetStream(ns); | |
this.addChild(vid); | |
ns.play("http://"+SERVER_IP+":8081/stream.flv"); | |
} | |
public function metaDataHandler(infoObject:Object):void { | |
for (var prop in infoObject){ | |
trace(prop+" : "+infoObject[prop]); | |
// TODO: set stage framerate? | |
} | |
} | |
} | |
} | |
// The below proxy class is a 3rd party class that plays video via | |
// StageVideo or Video, whichever is supported | |
/** | |
* Copyright (c) 2010 Dreamsocket Incorporated. | |
* All rights reserved. | |
* | |
* Permission is hereby granted, free of charge, to any person | |
* obtaining a copy of this software and associated documentation | |
* files (the "Software"), to deal in the Software without | |
* restriction, including without limitation the rights to use, | |
* copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the | |
* Software is furnished to do so, subject to the following | |
* conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
* OTHER DEALINGS IN THE SOFTWARE. | |
**/ | |
import flash.events.Event; | |
import flash.events.StageVideoEvent; | |
import flash.events.StageVideoAvailabilityEvent; | |
import flash.events.VideoEvent; | |
import flash.geom.Rectangle; | |
import flash.media.StageVideo; | |
import flash.media.StageVideoAvailability; | |
import flash.media.Video; | |
import flash.net.NetStream; | |
public class StageVideoProxy extends Video | |
{ | |
protected var m_netStream:NetStream; | |
protected var m_stageVideo:Object; | |
public function StageVideoProxy (p_width:int = 320, p_height:int = 240) | |
{ | |
super(p_width, p_height); | |
this.addEventListener(Event.ADDED_TO_STAGE, this.onAddedToStage); | |
this.addEventListener(Event.REMOVED_FROM_STAGE, this.onRemovedFromStage); | |
} | |
override public function set height(p_value:Number):void | |
{ | |
if(p_value != this.height) | |
{ | |
super.height = p_value; | |
this.layoutView(); | |
} | |
} | |
override public function get videoHeight():int | |
{ | |
return this.m_stageVideo ? this.m_stageVideo.videoHeight : super.videoHeight; | |
} | |
override public function get videoWidth():int | |
{ | |
return this.m_stageVideo ? this.m_stageVideo.videoWidth : super.videoWidth; | |
} | |
override public function set width(p_value:Number):void | |
{ | |
if(p_value != this.width) | |
{ | |
super.width = p_value; | |
this.layoutView(); | |
} | |
} | |
override public function set x(p_value:Number):void | |
{ | |
if(p_value != this.x) | |
{ | |
super.x = p_value; | |
this.layoutView(); | |
} | |
} | |
override public function set y(p_value:Number):void | |
{ | |
if(p_value != this.y) | |
{ | |
super.y = p_value; | |
this.layoutView(); | |
} | |
} | |
override public function attachNetStream(p_stream:NetStream):void | |
{ | |
if(p_stream != this.m_netStream) | |
{ | |
this.m_netStream = p_stream; | |
this.teardownStream(); | |
this.setupStageVideo(); | |
} | |
} | |
protected function setupSpriteVideo():void | |
{ | |
this.m_stageVideo = null; | |
super.attachNetStream(this.m_netStream); | |
} | |
protected function setupStageVideo():void | |
{ // only setup the view when video is on stage and there is a netstream attached | |
// this helps prevent as much as possible the time when a StageVideo is initialized | |
if(!this.stage || !this.m_netStream) return; | |
try | |
{ | |
if(!this.m_stageVideo && this.stage.stageVideos.length >= 1) | |
{ | |
this.m_stageVideo = this.stage.stageVideos[0]; | |
this.m_stageVideo.addEventListener(StageVideoEvent.RENDER_STATE, this.onRenderStateChanged); | |
this.layoutView(); | |
} | |
if(this.m_stageVideo) | |
{ | |
this.m_stageVideo.attachNetStream(this.m_netStream); | |
} | |
else | |
{ | |
this.setupSpriteVideo(); | |
} | |
} | |
catch(error:Error) | |
{ | |
this.setupSpriteVideo(); | |
} | |
} | |
protected function teardownStream():void | |
{ | |
try | |
{ | |
if(this.m_stageVideo) | |
{ | |
this.m_stageVideo.viewPort = new Rectangle(this.x, this.y, 0, 0); | |
this.m_stageVideo.attachNetStream(null); | |
} | |
else if(this.m_netStream) | |
{ | |
super.attachNetStream(null); | |
this.clear(); | |
} | |
} | |
catch(error:Error){} | |
} | |
protected function layoutView():void | |
{ | |
if(this.m_stageVideo) | |
this.m_stageVideo.viewPort = new Rectangle(this.x, this.y, this.width, this.height); | |
} | |
protected function onAddedToStage(p_event:Event):void | |
{ | |
//this.stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, this.onStageVideoAvailabilityChanged); | |
this.setupStageVideo(); | |
this.layoutView(); | |
} | |
protected function onRemovedFromStage(p_event:Event):void | |
{ | |
//this.stage.removeEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, this.onStageVideoAvailabilityChanged); | |
this.teardownStream(); | |
} | |
protected function onRenderStateChanged(p_event:Event):void | |
{ | |
switch(StageVideoEvent(p_event).status) | |
{ | |
case VideoEvent.RENDER_STATUS_UNAVAILABLE: | |
this.teardownStream(); | |
this.setupStageVideo(); | |
break; | |
} | |
} | |
protected function onStageVideoAvailabilityChanged(p_event:Event):void | |
{ | |
this.teardownStream(); | |
this.setupStageVideo(); | |
} | |
} |
@sthulesen - yes it works on mobile. I was streaming from vlc on Linux to Android (and maybe iOS, I forget exactly.) I was looking into StageVideo and various encoding parameters for hardware accelerated decoding (for reduced CPU usage == better battery life) when I last was working on the project a couple months ago.
BTW, for info on my Adobe AIR development setup in Linux, check out my blog: http://jcward.com/Adobe+AIR+Mobile+Development+On+Linux
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Will this work on mobile also. Air ios or Android.. ?