I am trying to create a simple video player SWF using the open source media framework in Flex 4. I want to make it dynamically scale based on the dimensions of the video, input by the user. I am following the directions on the Adobe help site, but the video does not seem to scale properly. Depending on the size, sometimes videos play larger than the space allotted on the webpage, and sometimes smaller. The only way I have been able to get it to work properly is by including a SWF metadata tag hardcoding the width and height, but I can't use that if I want to make the player dynamically sized. My code is :
package {
import flash.display.Sprite;
import flash.events.Event;
import org.osmf.media.MediaElement;
import org.osmf.media.MediaPlayer;
import org.osmf.media.URLResource;
import org.osmf.containers.MediaContainer;
import org.osmf.elements.VideoElement;
import org.osmf.layout.LayoutMetadata;
public class GalleryVideoPlayer extends Sprite {
private var videoElement:VideoElement;
private var mediaPlayer:MediaPlayer;
private var mediaContainer:MediaContainer;
private var flashVars:Object;
public function GalleryVideoPlayer() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
flashVars = loaderInfo.parameters;
mediaPlayer = new MediaPlayer();
videoElement = new VideoElement(new URLResource(flashVars.file));
mediaContainer = new MediaContainer();
var layoutMetadata:LayoutMetadata = new LayoutMetadata();
layoutMetadata.width = Number(flashVars.width);
layoutMetadata.height = Number(flashVars.height);
videoElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata);
mediaPlayer.media = videoElement;
mediaContainer.addMediaElement(videoElement);
addChild(mediaContainer);
}
}}
I don't know much about flex but i've used an OSMF player called the StrobeMediaPlayback and embedded it onto a html page. There's a javascript bridge which you can call using the ExternalInterface.call() function in actionscript (within the player code).
So I wrote a javascript function to resize the swf (can be done easily using jquery) and called it from actionScript whenever the video had to scale.
See if this helps you.
Related
how can i create own frames animation and play in movieclip or any movieclip extends.. i have this code but is wrong - i'm flash builder beginner so i don't know how work it..i can do it in MovieClip
<?xml version="1.0" encoding="utf-8"?>
public var mc:MovieClip;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
var comp:UIComponent = new UIComponent();
this.addElement(comp);
mc = new MovieClip();
for (var i:int =0; i<100; i++)
{
var rect:Sprite = new Sprite();
rect.graphics.beginFill(0x330000);
rect.graphics.drawCircle(0, 0, 20);
rect.graphics.endFill();
rect.x=30 + (i%40)*5;
rect.y=100;
mc.addChild(rect);
}
comp.addChild(mc);
}
protected function button1_clickHandler(event:MouseEvent):void
{
mc.play();
}
]]>
</fx:Script>
<s:Button click="button1_clickHandler(event)"/>
thanks for help
Sadly there is no way to create MovieClip animations at runtime, they can only be created using Flash Authoring (or possibly other tools that can export to swf).
Your options are to either create a bunch of Sprite or possibly Shape and add/remove these from the display list as you progress throught the frames. Another option, if your graphics are simpler, you can generate them on the fly for each frame.
I think we'd need a bit more information about the type of animation you're hoping to create.
Depending on what it is, it could be very possible in theory. You'd be creating a separate class that extends MovieClip and instantiate that in your 'for loop'. That class could have all sorts of animation instructions and logic. Extending 'MovieClip' isn't the only option, but it does enable you to use Event.ENTER_FRAME where with a Sprite you'd need to set up an internal Timer or use a public 'update' or 'draw' method that can be called from your main code.
There are also 'Motion' classes that allow you to load XML animation instructions that you have a fair amount of control with. Look up fl.motion.Animator.
What are you trying to do? Welcome to ActionScript!
In Flex 3 I have a SWFLoader:
<mx:SWFLoader id="player" source="http://youtube.com/v/..." />
and after some time I invoke player.unloadAndStop(). And I always get this error:
ReferenceError: Error #1056: Cannot create property __tweenLite_mc on _swftest_mx_managers_SystemManager.
What does it mean and how to avoid this?
UPD: AIR 2 doesn't have this problem
Maybe try the Loader class? I'm not sure if it will help but I do all my loading via ActionScript. Generally speaking, I do "heavyWeight" programming/logic/cotrol stuff in ActionScript and leave Flex for more simplistic layout code. That is, flex puts things in place and actionscript controls it all. When loading clips in our Flex 3 project, I have control code along the lines of:
import flash.display.Loader;
private var loader:Loader;
public function init() {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loadFailed);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleted);
}
with calls to things like:
//here, pop returns a string like "/path/to/movie.swf"
loader.load(new URLRequest(clipsToPlay.pop()));
...
loader.unload();
contained in functions like:
private function loadNextClip():void {
if(clipsToPlay.length == 0) {
dispatchEvent(new PlayBackCompleteEvent(PlaybackCompleteEvent.ALL));
return;
}
loader.load(new URLRequest(clipsToPlay.pop()));
}
private function loadCompleted(event:Event):void {
currentClip = event.target.content as MovieClip;
loader.unload();
displayClip();
}
private function displayClip():void {
applyEffects();
currentClip.addEventListener(Event.ENTER_FRAME, monitorForCompletion);
addChild(currentClip);
}
I'm not sure if Loader can be used instead of SWFLoader but if so I hope that helps you or someone else, in some way...
EDIT:
I just looked it up and mx.controls.SWFLoader and flash.display.Loader have very similar functionality. I'd try using Loader, as prescribed above, and see if it fixes the problem. You could probably initialize the loader via MXML, too, but I wouldn't recommend it since it's not a visual component, I think it's better to let MXML handle visual things while ActionScript handles logical things.
Below is my code, and the question is explained after it.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:cal="cal.*"
layout="absolute"
applicationComplete="init()"
xmlns:geometry="com.degrafa.geometry.*"
xmlns:degrafa="com.degrafa.*"
xmlns:paint="com.degrafa.paint.*"
xmlns:containers="flexlib.containers.*"
xmlns:flexlib_controls="flexlib.controls.*"
xmlns:mdi_containers="flexlib.mdi.containers.*"
xmlns:auto="com.hillelcoren.components.*"
xmlns:local="*"
xmlns:components="CollapsibleAccordion.*"
modalTransparency="0.8"
modalTransparencyColor="0x000000"
backgroundSize="100%">
<mx:Script>
<![CDATA[
import c7.views.components.PhotoViewer.PhotoViewer;
import c7.config.ServerConfig;
import mx.core.Application;
import mx.containers.*;
import c7.models.GlobalModel;
private var pv_slideshow:PhotoViewer = null;
private function toggleFullScreen():void
{
if(stage.displayState == StageDisplayState.NORMAL)
{
this.pv_slideshow = new PhotoViewer;
Application.application.addChild(this.pv_slideshow); //added as top-most component to application itself
//set new sizes & go full-screen
this.pv_slideshow.x = 0;
this.pv_slideshow.y = 0;
this.pv_slideshow.width = stage.fullScreenWidth;
this.pv_slideshow.height = stage.fullScreenHeight;
try
{
stage.displayState = StageDisplayState.FULL_SCREEN;
}
catch(err:Error)
{
Alert.show(err.toString());
}
stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenEventHandler, false, 0, true); //intentionally weak referenced
//refresh the display sizes & display list
invalidateSize();
invalidateDisplayList();
}
/*else
stage.displayState = StageDisplayState.NORMAL;*/
}
private function fullScreenEventHandler(event:FullScreenEvent):void
{
if (event.fullScreen) //nothing to do in case when switching to full-screen
return;
//Alert.show(pv_slideshow.width.toString());
//application.removeChild(this.pv_slideshow);
Application.application.removeChild(pv_slideshow); //remove the full-screen container
this.pv_slideshow = null; //reset
//refresh the display sizes & display list
invalidateSize();
invalidateDisplayList();
}
The toggleFullScreen is fired on the click of a button... and it working absolutely fine. But the issue is in "exit" . When I click escape key fullScreenEventHandler is fired and it should remove the pv_slideshow.
This is where I get a null object reference error on the line:
Application.application.removeChild(pv_slideshow); //remove the full-screen container
I have tried using this.pv_slideshow and other such things.
Plz help me figure it out. what am i doing wrong and how should I make it work.
This is exact error message I get:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.core::Container/http://www.adobe.com/2006/flex/mx/internal::removingChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3315]
at mx.core::Container/removeChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2263]
at index_cloud/fullScreenEventHandler()[C:\development\flex_src\index_cloud.mxml:1661]
I wouldn't use Application.application either.
Please check first pv_slideshow really exists, you can get it's parent ( if has one ) and remove it later.
get the parent
pv_slideshow.parent
remove it from the parent_item
parent_item.removeChild( pv_slideshow )
Make sure also the version of Flex you are using, you may need to remove it with removeElement.
The intended architectural use of Application.application is not to use it as a uiComponent or displayObject, or whatever. If you're building a library project that is doing some calculations based on the application properties, or the application's systemManager, or you need access to the outter application from a loaded module, then you have good reason to use App.app.
You example is not one of those cases. Your best bet is to add your component to 'this' (as long as you're not going to use a "view" container), and do a this.removeChild. That should solve a good chunk of your issues.
Best of luck,
Jeremy
Is there a way I can programmatically determine the filename of the .swf my class is running in?
Thanks!
Stage has a loaderInfo property, which contains a url property that has the information you're looking for. You can get the stage property from any DisplayObject in Flex.
trace(stage.loaderInfo.url);
Just a helpful note: If you load one SWF into another, the loaded (inner) SWF will return an erroneous result if you use loaderInfo.url to try to get the filename. For instance, something like:
Path/To/Outer.swf/[[DYNAMIC]]/1
Instead of:
Path/To/Inner.swf
Beware!
That said, here is the code I use to get the current SWF name:
function SWFName(symbol:DisplayObject):String
{
var swfName:String;
swfName = symbol.loaderInfo.url;
swfName = swfName.slice(swfName.lastIndexOf("/") + 1); // Extract the filename from the url
swfName = swfName.slice(0, -4); // Remove the ".swf" file extension
swfName = new URLVariables("path=" + swfName).path; // this is a hack to decode URL-encoded values
return swfName;
}
Not from within flash, afaik. What do you need it for? There might be a better way to do it.
You can use loaderInfo.loaderURL to get the full path and name of you swf
Example of a class:
public class Main extends Sprite {
private function init():void {
removeEventListener(Event.COMPLETE, init);
var myUrl:String=loaderInfo.loaderURL;
var tmp:Array=myUrl.split("/");
var myName:String=tmp[tmp.length-1].split(".swf")[0];
}
public function Main() {
super();
if (stage)
init();
else
addEventListener(Event.COMPLETE, init, false, 0, true);
}
}
Things have changed a bit in more recent versions so I'll give an answer for Adobe Flash Builder 4.6 (geared towards Flash in browser, but you get the idea).
<s:Application ... applicationComplete="alertSwfUrl()">
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
private function alertSwfUrl():void {
var a:LoaderInfo = FlexGlobals.topLevelApplication.stage.loaderInfo;
ExternalInterface.call('alert', a.url);
}
]]>
</fx:Script>
</s:Application
Check out the LoaderInfo docs to figure out how to use the loaderInfo object associated with the stage.
I get a ActionScript class for loading the content:
public class LoaderContainer extends Sprite {
public function LoaderExample() {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
addChild(loader);
var request:URLRequest = new URLRequest("File://C:/1.swf");
loader.load(request);
}
private function completeHandler(event:Event):void {
Alert.show(this.x+"/"+this.y+"/"+this.width +"/"+ this.height);
}
}
And then add the LoaderContainer to a Panel control in main MXML.
What supprise me is that the LoaderContainer's width/height is changing all the way according to the contents that it loaded.
Is there any way that we can limit the content's size right obeying the container's size?
Thanks
Michael
Since you're using Flex, is there any reason why you wouldn't just load it directly into an mx:Image or mx:SWFLoader? Since you're loading it and using addChild it's not being wrangled into the Flex framework where you could control it...
<mx:Image source="File://C:/1.swf" width="100" height="100" />