Hello everyone!
I'm trying out new StageVideo class and if I add it pure AS3 project everything works perfect.
But if I try to use the same code in Flex project I get no video output, but looks like the video itself is playing ('cos I can hear the sound track).
I've tried to remove everything from mxml file to make sure nothing covers video, tried to remove all background changes and etc. (put here any other stuff that might overlay stage), but nothing helped.
Is it possible to use StageVideo from Flex app at all? May be there's some trick to it?
Can someone help? Thanks in advance!
Try an application skin with just a contentGroup as in:
<?xml version="1.0" encoding="utf-8"?>
<s:Skin
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
>
<fx:Metadata>
[HostComponent("spark.components.Application")]
</fx:Metadata>
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
</s:states>
<s:Group id="contentGroup" width="100%" height="100%" x="0"
y="0"></s:Group>
</s:Skin
archemedia, yep, it's possible. with some limitations though
thx yamalight for your reaction. I've been browsing and browsing for some topics on this but wasn't able to find something usefull. I can access the CameraRoll on iPad but unlike other applications, it contains no video's. I can't find anything in the API for this. The same goes for iTunes music access. Any ideas?
thx,
Dany
Ged_mc wrote:
Hi Yamalight,
Please can you share some code for the solution - we're having the same issue but I'm not sure how giving the Application a skin helps.
Thanks
Ged
Take a look at Flex harUI message - that's the recipe. Just create new flex skin, make content-only and problem solved
Hi Keith,
We got stage video working on ios using Vimeo pro to deliver the video.
You haveto think of it as playing underneath your project. So hide all display list above it and build UI around it.
We didn't use ViewNavigatorApplication so I don't know.
However ViewNavigatorApplication will just be a visual layer over the stage video.
Find a way to hide it then rebuild your UI around the stage video to make it appear to be in your app..
Hello,
I guess there is no way to attach files to this post. I made the main app an Application instead of a ViewNavigatorApplication for simplicity sake. It's a basic mobile application project for an ipad, so in Flash Builder just create a basic project using that profile and drop these in. I appreciate you taking a look at it.
thx
Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
private var mediaPlayer:CatVideoPlayer;
private function init():void
{
var videoFile:File = File.applicationDirectory.resolvePath("preview.mp4");
var videoPath:String = new File(new File(videoFile.url).nativePath).url;
mediaPlayer = new CatVideoPlayer();
mediaPlayer.width = 640;
mediaPlayer.height = 360;
addElement(mediaPlayer);
mediaPlayer.source = videoPath;
}
]]>
</fx:Script>
</s:Application>
Custom UI Component:
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.StageVideoAvailabilityEvent;
import flash.events.StageVideoEvent;
import flash.geom.Rectangle;
import flash.media.StageVideo;
import flash.media.StageVideoAvailability;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import mx.core.FlexGlobals;
import mx.core.UIComponent;
public class CatVideoPlayer extends UIComponent
{
private var _defaultHeight:Number = 360;
private var _defaultWidth:Number = 640;
private var _ns:NetStream;
private var _obj:Object;
private var _source:String;
private var _sourceChanged:Boolean;
private var _stageBitmap:Bitmap;
private var _stageVideoAv:Boolean = false;
private var _sv:StageVideo;
private var _vd:Video;
private var _vidMask:Sprite;
//private var _videoStage:Sprite;
public function CatVideoPlayer()
{
super();
mouseEnabled = false;
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
public function onCuePoint(info:Object):void
{
trace("CatVideoPlayer.onCuePoint: time=" + info.time + " name=" + info.name + " type=" + info.type);
}
public function onMetaData(info:Object):void
{
//trace("metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate);
//this.width = info.width;
//this.height = info.height;
}
public function onPlayStatus(info:Object):void
{
trace("CatVideoPlayer.onPlayStatus: " + info.data);
}
public function onXMPData(info:Object):void
{
trace("CatVideoPlayer.onXMPData: " + info.data);
}
public function set source(value:String):void
{
_source = value;
_sourceChanged = true;
invalidateProperties();
}
override protected function commitProperties():void
{
super.commitProperties();
if (_sourceChanged)
{
setState("showVideoPlayer");
_sourceChanged = false;
}
}
override protected function createChildren():void
{
super.createChildren();
trace("createChildren fired in CatVideoPlayer");
//_videoStage = new Sprite();
//addChild(_videoStage);
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
/**
* Convert the current screen to a bitmap and mask it to show stageVideo.
*
*/
private function convertStageToBitmap():void
{
var bitmapData:BitmapData = new BitmapData(FlexGlobals.topLevelApplication.width, FlexGlobals.topLevelApplication.height);
_stageBitmap = new Bitmap();
_vidMask = new Sprite();
_vidMask.graphics.beginFill(0x000000);
_vidMask.graphics.moveTo(0, 0);
_vidMask.graphics.drawRect(0, 0, _defaultWidth, _defaultHeight);
_vidMask.graphics.endFill();
//bitmapData.draw(this);
bitmapData.draw(FlexGlobals.topLevelApplication.document);
_stageBitmap.bitmapData = bitmapData;
_stageBitmap.cacheAsBitmap = true;
_vidMask.cacheAsBitmap = true;
//addChild(_vidMask);
_stageBitmap.mask = _vidMask;
//addChild(_stageBitmap);
//backgroundImg_mc.visible = false;
//playerWindow_mc.visible = false;
//initVideo();
}
/**
* Handles the mouse clicks that occur on UI components.
* @param e
*
*/
private function handleInterfaceClick(e:Event):void
{
e.preventDefault();
switch (e.target.name)
{
case "playBtn_mc":
{
setState("showVideoPlayer");
break;
}
case "closeVideo_mc":
{
setState("closePlayer");
break;
}
default:
{
//do default
}
}
}
/**
* Plays the video using StageVideo if supported.
*
*/
private function initVideo():void
{
var nc:NetConnection = new NetConnection();
nc.connect(null);
_ns = new NetStream(nc);
_obj = new Object();
_ns.client = _obj;
_ns.bufferTime = 2;
_ns.client = _obj;
//_obj.onMetaData = MetaData;
//_obj.onCuePoint = CuePoint;
if (_stageVideoAv)
{
//use stageVideo
trace("using stage video in CatVideoPlayer.initVideo()");
_sv = stage.stageVideos[0];
_sv.addEventListener(StageVideoEvent.RENDER_STATE, onRender);
_sv.attachNetStream(_ns);
}
else
{
//fallback to video class
trace("using normal video in CatVideoPlayer.initVideo()");
_vd = new Video(_defaultWidth, _defaultHeight);
//_vd.x = 152;
//_vd.y = 143;
addChild(_vd);
_vd.attachNetStream(_ns);
}
//addChild(videoUI_mc);
_ns.play(_source);
}
private function onAddedToStage(event:Event):void
{
trace("onAddedToStage fired in CatVideoPlayer");
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILA BILITY, onStageVideoAvailability);
}
private function onRender(e:StageVideoEvent):void
{
// if (!videoUI_mc.fsMode)
// {
// _sv.viewPort = new Rectangle(152, 143, 720, 480);
// }
// else
// {
_sv.viewPort = new Rectangle(0, 0, 640, 360);
//}
}
private function onStageVideoAvailability(e:StageVideoAvailabilityEvent):void
{
_stageVideoAv = (e.availability == StageVideoAvailability.AVAILABLE);
initVideo();
}
/**
* Animate the video player's UI states.
* @param currentState The different states the player is in.
*
*/
private function setState(currentState:String):void
{
trace("setState fired in CatVideoPlayer");
switch (currentState)
{
case "showVideoPlayer":
{
//playBtn_mc.visible = false;
//addChild(playerWindow_mc);
//addChild(closeVideo_mc);
//playerWindow_mc.visible = true;
//closeVideo_mc.visible = true;
//TweenLite.from(playerWindow_mc, 1, { alpha:0, onComplete:function(){ convertStageToBitmap(); } });
//TweenLite.from(closeVideo_mc, 1, { alpha:0 });
convertStageToBitmap();
break;
}
case "closePlayer":
{
//removeVideoPlayer();
//playerWindow_mc.visible = false;
//playBtn_mc.visible = true;
break;
}
default:
{
//do default
}
}
}
}
}
You have to create a custom skin. Setting BG alpha to 0 doesn't work (or at least it didn't worked for me).
See example at top of this thread: http://forums.adobe.com/message/3459444#3459444
You just need a new skin with only content group and no BG at all. Then it works fine.
Also, you can take a look at my custom player here, it works on desktop, web and mobile with StageVideo support: https://github.com/yamalight/libcodezen/tree/master/src/com/codezen/co mponent/videoplayer
I still can't seem to get it right. Here is my app skin:
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<!-- host component -->
<fx:Metadata>
[HostComponent("spark.components.ViewNavigatorApplication")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="landscapeAndOverlay" />
<s:State name="portraitAndOverlay" />
<s:State name="landscape" />
<s:State name="portrait" />
<s:State name="disabled" />
<s:State name="normal" />
</s:states>
<!-- SkinParts
name=contentGroup, type=spark.components.Group, required=false
name=actionBar, type=spark.components.ActionBar, required=false
-->
<s:Group id="contentGroup" width="100%" height="100%" x="0" y="0"/>
<s:ViewNavigator id="navigator" width="100%" height="100%"/>
</s:Skin>
And here is the main app mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
firstView="views.MainHomeView"
skinClass="appSkin">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:ViewNavigatorApplication>
The video is playing obviously because I can hear it.
i have used CatVideoPlayer stage video with web Flex project it work fine but without a skin (button and stop button),
but when i try work with a Flex mobile project it's not worky
unfortunaltely even i don't hear the video even like Keith Lee.
i wondered if that is related with ViewNavigatorApplication hasn't background alpha attribute???
Our stageVideo experience was as follows:
We used video display in the Web app and Android mobile project
On android devices we found it unreliable across different android versions / devices. For the web we judged it too flaky given the hardware depedence.
StageVideo worked well on iOS ( iPad2 and 3 )
Our iPad project didn't use the ViewNavigatorApplication
We constructed it using traditional flex groups and states.
The stage video source is HTTP Live streaming ( via Vimeo pro - Excellent service ) - which is App Store OK.
When the stage video plays we set the app backgroundAlpha to zero and reconstructed the UI around the video ( never on top of it ).
The android situation was disappointing. I think Adobe has to get this to work reliably.
I am beginning to think that the skin used in a mobile project is somehow blocking the video. Many have said they have gotten StageVideo to work on an iPad, but I don't think I have run across anyone yet who has done it in a Flex mobile project. It should work in theory though ![]()
Well, I finally got all of this working. The culprit all along was the application skin; I had to assign a mask to it in order for the stage video to show through.
Now though i have another problem. Because the TabbedNavigatorApplication has a skin that defines a graphic for the application background, I have to assign the video mask to the skin, so anything in the display list is now a child of that mask. This is a problem because on my video player, I want to capture mouse down or touch events so that I can show/hide the video controls. Since it is masked, no matter what I try I can't seem to capture any of those events within the unmasked area which allows the stage video to show thru. Anyone know of any suggestions?
Yes, that too, but because the application skin is using an embedded image for the application background, I had to mask it in order for stage video to appear. Anyway I was trying to add the event listener to the mask, which did not work, so I added it to the stage object, and that so far has allowed me to capture mouse clicks positions and determine if the video is being clicked on or not.
Now the final problem is that I cannot display the video's ui controls over the top of the video, because the mask in the application skin is masking every child object of the application. I am now considering as a solution to simply cut a hole in the application background image instead of using a mask, but I wondering if it is possible to swap application backgrounds on the fly without seeing a display hiccup?
Theoretically, the contentGroup, which parents all the child controls in the skin should have no background at all, and some other control outside (and behind) the contentGroup is showing the backgroundImage. Then you can cut holes in the backgroundImage by applying your mask only to the backgroundImage and it should not be affecting anything else.
Hmm... I am using an Actionscript only skin, not an mxml skin. So correct me if I'm wrong, but you are saying that if I were using an mxml skin that I could make the background alpha of the contentGroup 0, add the background image to the skin outside of the contentGroup container, and then only apply the mask to the image? If so I will try that.
thx
I was able to solve the problem by applying the mask to the background image in the ActionScript skin, vs. applying it to the skin. That prevented the mask from affecting all child objects of the application. MXML skins are confusing
. Flex is really is cool once you grasp it; i can't see why the industry is moving away from it.
thx
North America
Europe, Middle East and Africa
Asia Pacific