Skip to content

Instantly share code, notes, and snippets.

@jcward
Created October 25, 2013 19:04
Show Gist options
  • Save jcward/7160092 to your computer and use it in GitHub Desktop.
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)
/**
* 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
Copy link

Will this work on mobile also. Air ios or Android.. ?

@jcward
Copy link
Author

jcward commented Oct 28, 2013

@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.

@jcward
Copy link
Author

jcward commented Oct 28, 2013

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