I'm working with spark video components, however the spark videoObject is null, when using a dynamic video source object it still null. Cameras are being detected properly, however when using a variable it's null, when using the Camera object directly usb camera is detected and videoobject still null... any ideas???
Now when using Camera.names all "cameras" are null, when playing a video from apache virtualhosts it plays well, this is so so weird...!
As requested, updated code:
import mx.controls.Alert;
import mx.events.FlexEvent;
import spark.components.VideoPlayer;
private var vidPlyr:VideoPlayer = null;
protected function winAppCreated(event:FlexEvent):void {
// Video Player
vidPlyr = new VideoPlayer();
vidPlyr.width = 320;
vidPlyr.height = 240;
// Video from apache virtualhost:
vidPlyr.source = "http://flex.test.capimg/JormaKaukonenCracksInTheFinish.flv";
addElement(vidPlyr);
var cameraTV:Camera = Camera.getCamera(Camera.names[0]);
var cameraUSB:Camera = Camera.getCamera(Camera.names[1]);
if (cameraTV) {
vidPlyr.videoDisplay.videoObject.attachCamera(cameraTV);
} else {
Alert.show("no TV card - " + Camera.names[0]);
// Alert shows: "no TV card - SAA7130 Analog TV Card"
}
if (cameraUSB) {
vidPlyr.videoDisplay.videoObject.attachCamera(cameraUSB);
} else {
Alert.show("no USB camera - " + Camera.names[1]);
// Alert shows: "no USB camera - USB2.0 Grabber"
}
}
This is a screenshot of running app.
I took a look at the VideoPlayer code, a lot of this class' properties have setters that look like this:
public function set source(value:Object):void
{
if (videoDisplay)
{
// do the real work
}
else
{
// store the value so we can use it later
}
}
VideoDisplay is the a skin part of the video player class. When you set the source, the skin must not have initialized the videoObject property. I would set the source, and then wait before trying to attach the camera.
Flex has a callLater() method that may solve this problem. callLater() will execute a function you specify on the next Flex update cycle:
// after setting the source
callLater(attachCamera);
// define a new function 'attachCamera' to call later
private function attachCamera():void
{
// if the videoObject property is not null
if (vidPlyr.videoDisplay.videoOjbect != null)
{
// attach the camera here
}
else
{
trace("cannot attach the camera, videoObject is still null");
}
}
[Edit]
The API to get a camera is strange, the signature is:
public static function getCamera(name:String = null):Camera
But that name argument is not the actual name of the camera. It supposed to be a String representation of the camera's index in the Camera.names array. Quoting the docs:
name:String (default = null) — Specifies which camera to get, as determined from the array returned by the names property. For most applications, get the default camera by omitting this parameter. To specify a value for this parameter, use the string representation of the zero-based index position within the Camera.names array. For example, to specify the third camera in the array, use Camera.getCamera("2").
Try doing something more generic like this when you attach the camera with callLater(attachCamera):
private function attachCamera():void
{
var cameras:Array = Camera.names;
var length:int = cameras.length;
var cameraObjects:Array = [];
for (var i:int = 0; i < length; i++)
{
cameraObjects.push( Camera.getCamera( i.toString() );
}
// use your own logic to select a camera, if there's more than one
if (cameraObjects.length > 0 && vidPlyr.videoDisplay.videoOjbect != null)
{
vidPlyr.videoDisplay.videoOjbect.attachCamera( cameraObjects[0] );
}
}
Related
I have a MovieClip in Library , which I am loading dynamically through addChild method.
The problem I am facing is :--
I have a Main Class which runs with several other classes and several FLA's.
Main Class calls a sub class function which in return calls the code in a frame of a FLA which loads this object from Library.
This object is not present in all FLA's, thats where I am getting stuck, getting Compile time error.
Tried checking through this but failed :(
var classExist:Boolean = isClassExists("CTRL_ALARM");
function isClassExists(className:String, domain:ApplicationDomain = null):Boolean
{
var res:Boolean;
if(domain)
{
res = domain.hasDefinition(className);
}
else
{
// res = getDefinitionByName(className);
//or the same
res = ApplicationDomain.currentDomain.hasDefinition(className);
}
trace(res);
return res;
}
Is there any way I can duplicate objects on Stage in as3, or how can I restrict an object from being compiled if it is not present in Library?
Try the following. If all of your SWFs are in the same sandbox, it might just work:
import flash.utils.getDefinitionByName;
var AlarmClass:Class = getDefinitionByName("CTRL_ALARM");
var anAlarm:DisplayObject = new AlarmClass;
Then, to make it work even with sandbox restrictions, you may seek for the definition you want through the loaded SWFs:
// This should contain Loader objects with your loaded SWFs.
var aList:Array;
for each (aLoader:Loader in aList)
{
// Get reference to loaded app domain.
var aDomain:ApplicationDomain = aLoader.contentLoaderInfo.applicationDomain;
// Check if such a class is in that SWF.
if (aDomain.hasDefinition("CTRL_ALARM"))
{
var AlarmClass:Class = aDomain.getDefinition("CTRL_ALARM");
var anAlarm:DisplayObject = new AlarmClass;
break;
}
}
Okay, so I'm trying to create a mobile flash game (I'm mostly an animator, a storyteller) and I'm having trouble with the input text for the player name. I've often read helpful tips on this site so I signed up to get some help. The code I use to load and save data is saveDataObject, But as far as I know input text has to be used with package code. I tried to convert it to function var, but then these errors occur. I am unsure how to use the Package class code, and everything I've read on it has been confusing. I am pretty much self taught for everything I know about code though tutorials and forums, so if it isn't explained in a way I can understand I wont be able to do it...
Here's the section of code if I wasn't clear(error lines separate):
var playerName:int;
init(); // this line goes directly beneath the variables
function f_1(init):void
{ // call once to set everything up
saveDataObject = SharedObject.getLocal("DataBattle/character/name"); // give the save data a location
-
playerName = txtPlayer;
-
function addName(e:TouchEvent):void
{
var myTextBox1:TextField = new TextField();
var txtPlayer:TextField = new TextField();
var myText:String = "Cyan";
function CaptureUserInput()
{
captureText();
}
function captureText():void
{
myTextBox1.type = TextFieldType.INPUT;
myTextBox1.background = true;
addChild(myTextBox1);
myTextBox1.text = myText;
myTextBox1.addEventListener(TextEvent.TEXT_INPUT, textInputCapture);
}
function textInputCapture(event:TextEvent):void
{
var str:String = myTextBox1.text;
createOutputBox(str);
}
function createOutputBox(str:String):void
{
txtPlayer.background = false;
txtPlayer.x = 200;
addChild(txtPlayer);
txtPlayer.text = str;
}
-
if(saveDataObject.data.characterName = playerName == null)
-
{ // checks if there is save data
trace("No Player data yet."); // if there isn't any data on the computer...
saveDataObject.data.characterName = playerName; // ...set the savedScore to 0
}
else
{
trace("Player data found."); // if we did find data...
loadData1(); // ...load the data
}
function loadData1():void
{
playerName = saveDataObject.data.characterName; // set the current score to the saved score
trace("Data Loaded!");
}
}
}
function saveData(e:TouchEvent):void
{
saveDataObject.data.characterName = playerName; // set the saved score to the current score
trace("Data Saved!");
saveDataObject.flush(); // immediately save to the local drive
trace(saveDataObject.size); // this will show the size of the save file, in bytes
}
Would be nice to have some more details about this error. Like which line is actually throwing this error.
However even without it there are few things that looks weird right away.
var playerName:int;
// And few lines below
playerName = txtPlayer;
// Few more lines below
var txtPlayer:TextField = new TextField();
Looks like you're declaring playerName as int so you want to store numeric values, but then txtPlayer is a TextField. So by playerName = txtPlayer; you're trying to store TextField as Int value, which is not gonna work.
I can also see
if(saveDataObject.data.characterName = playerName == null)
and it's like :O
I'm not even sure how this part is being compiled. You want to do playerName == null check (which would return true/false) and then assign it to saveDataObject.data.characterName ?
I got a .fla file, where inside I have some movieclip instances placed in the scene. I need to iterate through them and gather some data, like position, name, and custom properties.
These custom properties, I don't know how to pass them, I know one way that works so far is to use the accessibility properties panel (Flash Pro CC), and then in the code I can just read them. However there should be a better way I assume.
If I have understood correctly your question and what you have said in your comments about the answer of #Aaron, you have an swf file, which you load dynamically, and you want to get/set some of its MovieClips properties, if it's the case, take this example :
MyMC.as :
public class MyMC extends MovieClip
{
private var timer:Timer;
private var rotation_speed:int = 1;
public function MyMC() {
}
public function set_Rotation_Speed(_rotation_speed:int): void {
this.rotation_speed = _rotation_speed;
}
public function get_Rotation_Speed(): int {
return this.rotation_speed;
}
public function start_Rotation(): void {
this.timer = new Timer(500, 10);
this.timer.addEventListener(TimerEvent.TIMER, on_Timer);
this.timer.start();
}
private function on_Timer(e:TimerEvent): void {
this.rotation += this.rotation_speed;
}
}
Then, in my swf.swf I have an instance of that MovieClip.
I loaded the swf.swf using this code :
var loader:Loader = new Loader()
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, on_SWFLoad);
loader.load(new URLRequest('swf.swf'));
And to set/get some of my MovieClip properties, I did :
function on_SWFLoad(e:Event): void
{
var swf:DisplayObjectContainer = DisplayObjectContainer(loader.content);
var num_children:int = swf.numChildren;
for(var i:int = 0; i < num_children; i++)
{
var child:MovieClip = MovieClip(swf.getChildAt(i));
// get the name
trace('name : ' + child.name);
// set the position
child.x = child.y = 100;
// get the class name, in my case it's MyMC
var class_name:String = getQualifiedClassName(child);
// get all the details of the child
trace(describeType(child));
child.set_Rotation_Speed(45);
child.start_Rotation();
trace(child.get_Rotation_Speed()); // gives : 45
}
addChild(loader);
}
You can use the describeType() function To get all the properties of your instance.
Hope that can help.
First of all, you can set properties on timeline instances from code. There's nothing special about this. For example:
Place an instance of a library symbol on a keyframe
Give it an instance name in the Properties panel, for example "myInstance"
On the same keyframe put some code that refers to it, such as myInstance.color = "red"
You can also create and assign custom properties by making the symbol a component:
Right-click on the symbol in the library and choose "Component Definition"
Add custom properties in the Parameters table. It's now a component symbol.
On the timeline, place an instance of the symbol and use the Properties panel to set its parameters.
You can do a lot more with components if you want, such as live preview and compiled components. More info can be found here here: http://www.adobe.com/devnet/flash/learning_guide/components/part03.html
I'm really not familiar with Action Script 3 at all but I am with other languages.
I'm hoping someone could help me.
I'm attempting to make a modification to JWplayer so that an rtmp stream is retrieved via a PHP script rather than it being supplied in the HTML.
The code I currently have is below:
function useData(event:Event):void {
var data:String = event.target.data.toString();
}
/** Load content. **/
override public function load(itm:PlaylistItem):void {
_item = itm;
_position = 0;
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, useData);
loader.load(new URLRequest("http://192.168.0.12/phpauth/play1.php"));
// Set Video or StageVideo
if(!_video) {
_video = new Video(320, 240);
_video.smoothing = true;
_video.addEventListener('renderState', renderHandler);
// Use stageVideo when available
if (_stageEnabled && RootReference.stage['stageVideos'].length > 0) {
_stage = RootReference.stage['stageVideos'][0];
_stage.viewPort = new Rectangle(0,0,320,240);
_stage.addEventListener('renderState', renderHandler);
}
attachNetStream(_stream);
}
// Load either file, streamer or manifest
if (_item.file.substr(0,4) == 'rtmp') {
// Split application and stream
var definst:Number = _item.file.indexOf('_definst_');
In the load function the file name to play is held in _item.file. I'm trying to make a call to a php script which then overwrites the value in _item.file. I've confirmed that the php is being called but I don't know how to get the data from the data string in the useData function into the _item.file string.
Any help would be really appreciated - I suspect this is a simple one but my lack of AS3 knowledge is making it really difficult.
Thanks,
Your problem basically about how to access a local variable in an event handler. A quick and dirty way can be to have an anonymous function used as a handler like:
loader.addEventListener(Event.COMPLETE, function(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
});
This approach would work, because this anonymous function has access to the local variables inside load function as is. But, you need to be cautious that the anonymous function uses the variable exactly as the calling function is using. So, let's say there is a loop in load function and _item changes in every iteration of the loop. For that scenario, when load handler gets called, its _item would also have changed to the object which was last assigned to _item.
A far cleaner and OO approach can be to have a handler class like:
package {
public class LoadHandler {
private var _item:PlaylistItem;
public function LoadHandler(item:PlaylistItem) {
_item = item;
}
public function loadHandler(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
}
}
and then have loader.addEventListener(Event.COMPLETE, (new LoadHandler(_item)).loadHandler). Hope that helps. BTW, LoadHandler could be made more generic to take and array of objects to be used and a callback function. loadHandler function, then could just call callback function with that array of objects.
If you are returning a simple string from PHP you should be able to use
event.target.data;
e.g. from PHP... echo "hello";
var data:String = event.target.data
You could try tracing the response to ensure you are getting something back from PHP.
You can either test this from within the IDE or install the Debug version of the Flash Player browser plugin.
trace("Response from PHP: "+event.target.data);
_item.file = event.target.data;
trace("_item.file: "+_item.file);
We are making a system that has a main swf for the application, and loads separate tools from separate swfs -- there will be versioning issues in the future since the separate swfs are coming from a cms (especially now since we're still developing, but also in the future when other developers might create an incompatible tool). I'm trying hard to prevent them as much as possible but I'd really like to be able to display a message to the user of the system when an incompatible swf is loaded.
This would mean that we need to catch that VerifyError or at least determine the loading failed for some reason - I've got no idea how to handle that at the moment. I suspect it might be possible using 10.1 and the uncaughtError system, but we are currently targeting flash player 10. Does anyone have a good idea? (we are already handling IOErrorEvent.IO_ERROR)
UPDATE: I've built a solution that scans the bytecode before importing, looks like that will work. I'll post the solution later.
The best way to do this is by using one of the libraries bhups suggested. I used senocular's for the next example.
Also, because the senocular's library provides only basic operations for the parsed SWF you may need the SWF Format Spec (adobe.com/devnet/swf/pdf/swf_file_format_spec_v10.pdf) to get the info you want out of the loaded SWF.
The next example lists all the class names from a loaded SWF:
package swf
{
import flash.events.Event;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.utils.ByteArray;
import flash.utils.Endian;
import swf.SWFReader;
public class GetSWFInfo
{
private var swfInfo:SWFReader;
public function GetSWFInfo()
{
var urlRequest:URLRequest = new URLRequest("theswf.swf");
var loader:URLStream = new URLStream();
loader.load(urlRequest);
loader.addEventListener(Event.COMPLETE, onComplete);
}
public function onComplete(e:Event):void {
var recivedByteArray :ByteArray = new ByteArray();
URLStream(e.currentTarget).readBytes(recivedByteArray);
//create a new instance of SWFReader
swfInfo = new SWFReader();
//readTag it's a callback function that will be called when a tag is read during the SWF parse process.
//read more on tags in the SWF specification document
swfInfo.tagCallback = readTag;
//start parsing
swfInfo.parse(recivedByteArray);
}
public function readTag(tag:uint, bytes:ByteArray):void {
//76 it's the tag type for SymbolClass tag
//read more in the SWF specification document
if (76 == tag) {
var classesArray:Array = new Array();
var symbolsNumber:uint = 0;
var currentId:uint = 0;
bytes.endian = Endian.LITTLE_ENDIAN;
//read the symbols Number
//again read more in the SWF specification document
symbolsNumber = bytes.readShort();
bytes.position = 4;
while (true) {
var i:uint = bytes.position;
//every string name ends with a null byte
//again read more in the SWF specification document
while(bytes[i] != 0) i++;
var readAmount:uint = i - bytes.position;
classesArray.push(bytes.readUTFBytes(readAmount));
//the last ID is always the base class Id, and it's 0
currentId=bytes.readUnsignedShort();
bytes.position++;
if (currentId==0) {
break;
}
}
//this two should be equal
trace(classesArray.length + 1);//the number of elements in the classesArray
trace(symbolsNumber);//the number of classes retrived from the SWF
//list the names
var name:String;
for each (name in classesArray) {
trace(name);
}
//now you have an array with all the class names that you can use to compare
}
}
}
}
I did misunderstand what you are trying to do.
Well, actually, I guess there is no handler for verify error and to detect it, you have to fight with byte-codes.
By the way, I have and idea which is not the very answer for your question but may helps you.
a 3rd party swf is depending on a class that should be in my swf -- if that class is missing I get the VerifyError.
From this point, I can advice that if you link the 'missing class' into your swf and load the 3rd party swf into ApplicationDomain.currentDomain or new ApplicationDomain(ApplicationDomain.currentDomain), you can avoid the 'Verify Error'.
(This is because the flash player will find the diffinition of the missing class in the parent swf.)
Here is my sample code which loads a swf with verify error(http://teionclub.com/test/xml/main.swf).
Avoiding VerifyError - wonderfl build flash online
I think there is a way to workaround this issue.
load the swf using a URLLoader or
URLStream into a ByteArray.
Use any open source library for parsing SWF binary like this or
this.
check if it verifies that the whole byte array represents valid
SWF file.
If above test succeeds then load this ByteArray into loader using
loadBytes method.
Else show user that this is not working.
Disclaimer: A binary file can be a valid SWF still might not be render-able, but with this you can discard all the invalid SWFs or any other formats whose extension are changed to swf.
I've worked with that kind of application in the past but I think it would be better to fix the SWF loaded rather than handling VerifyError. VeriyError indicates that the SWF loaded is corrupted or malformed.
And it's natural that the SWF itself is malformed rather than that the SWF is corrupted during the transfer. I guess you are trying to load png or other format named ".swf" or the SWF is generated by some software other than Flex compiler or Flash such as swfmill(In the latter case, there would be a bug in that software).
To finally answer my own question, this is the utility class I've been using to detect possible errors. I load the SWF as a bytearray and scan the contents before loading it as an actual MovieClip.
As you can see my code heavily depends on the com.segfaultlabs.swfutils package
Important: I've stopped using this method of preventing errors, opting for the more manual approach of checking the files by actually trying to load them and see if they work. This is because the utility is not complete, and my current knowledge of the ABC format is not good enough to make sure I can develop a check that will always be correct.
Posting my code here as starting point for others who want to take a stab at it :-)
package nl.ijsfontein.utils
{
import com.segfaultlabs.swfutils.ABC.ABCCPool;
import com.segfaultlabs.swfutils.ABC.ABCClass;
import com.segfaultlabs.swfutils.ABC.ABCInstance;
import com.segfaultlabs.swfutils.ABC.ABCMethodInfo;
import com.segfaultlabs.swfutils.ABC.ABCMultiname;
import com.segfaultlabs.swfutils.ABC.ABCParser;
import com.segfaultlabs.swfutils.ABC.ABCTraitConstSlot;
import com.segfaultlabs.swfutils.ABC.ABCTraitsInfo;
import com.segfaultlabs.swfutils.ABC.ABCinfo;
import com.segfaultlabs.swfutils.SWFDataInput;
import com.segfaultlabs.swfutils.SWFFile;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
/**
* utility to see which classes a swf uses, but doesn't contain itself
* - this can be used to detect possible VerifyErrors before they happen.
*/
public class SwfDependencyUtil
{
public function SwfDependencyUtil()
{
}
// return null if ok, or name of needed class if external depencendy
private static function resolveSuper(abc:ABCinfo, superClass:String):String
{
//if (superClass.indexOf("flash.") == 0 || superClass.indexOf("*") == 0 || superClass.indexOf("Object") == 0)
if (superClass.indexOf("*") == 0)
{
trace(' super: ' + superClass + " (ignore)");
}
else
{
var superClassClass:ABCClass = null;
for each ( var c:ABCClass in abc.classes )
{
if (c.name == superClass)
{
superClassClass = c;
}
}
if (superClassClass)
{
trace(' super: ' + superClass + " (resolved internally)");
return resolveSuper(abc, superClassClass.iref.base);
}
else
{
trace(' super: ' + superClass + " (NOTFOUND)");
return superClass;
}
}
return null;
}
/*
* checks: classes, superclasses, static variables, member variables
* TODO: function arguments
* won't check: method bodies
*
* TODO: refactor to multiple methods
*/
public static function getDependencies(swfBytes:ByteArray):Array /* of String */
{
var result:Array = [];
swfBytes.position = 0;
var swfr:SWFFile = new SWFFile(swfBytes);
var arr:Array;
if ( swfr.compressed )
{
swfr.dataInput = swfr.uncompress();
swfr.readHeader();
};
arr = swfr.parseTags();
if ( arr[82] != null )
{
var abc:ABCinfo = new ABCinfo();
var cpool:ABCCPool = new ABCCPool();
var abcparse:ABCParser = new ABCParser();
abcparse.readMethodBytes = true;
abcparse.readExceptions = false;
for ( var j:int = 0; j < arr[82].length; j += 1 )
{
swfr.dataInstance.position = arr[82][j].position;
try
{
abcparse.parse( swfr.dataInput as SWFDataInput, abc, cpool, new FakeLogger() );
for each ( var c:ABCClass in abc.classes )
{
trace('class:', c.name);
var superClass:String = c.iref.base;
var dependency:String = resolveSuper(abc, superClass);
if (dependency)
{
result.push(dependency);
}
for each (var mn:ABCMultiname in c.iref.interfaces)
{
var interfaceName:String = mn.nsset[0] != "" ? mn.nsset[0] + "::" + mn.name : mn.name;
var interfaceDependency:String = resolveSuper(abc, interfaceName);
if (interfaceDependency)
{
result.push(interfaceDependency);
}
}
for each (var ti:ABCTraitsInfo in c.traits)
{
if (ti is ABCTraitConstSlot)
{
var constName:String
if (QName(ABCTraitConstSlot(ti).type).uri)
{
constName = QName(ABCTraitConstSlot(ti).type).uri + "::" + QName(ABCTraitConstSlot(ti).type).localName
}
else
{
constName = QName(ABCTraitConstSlot(ti).type).localName
}
var constDependency:String = resolveSuper(abc, constName);
if (constDependency)
{
result.push(constDependency);
}
}
else if (ti is ABCMethodInfo)
{
trace('method', ABCMethodInfo(ti).name);
} else
{
trace(ti);
}
// trace(ti.type.localName);
}
// const (static?) members: c.traits
}
for each ( var i:ABCInstance in abc.instances )
{
// trace(i);
for each (var instanceTi:ABCTraitsInfo in i.traits)
{
if (instanceTi is ABCTraitConstSlot)
{
trace('instance:', createClassNameFromQname(ABCTraitConstSlot(instanceTi).type));
var csdep:String = resolveSuper(abc, createClassNameFromQname(ABCTraitConstSlot(instanceTi).type));
if (csdep)
{
result.push(csdep);
}
}
else if (instanceTi is ABCMethodInfo)
{
}
else
{
trace('unexpected trait type');
}
}
}
abc.dispose();
}
catch ( e:Error )
{
trace( " Error ",e.getStackTrace() );
};
};
cpool.dispose();
}
else
{
trace("No DoABC block... ;(");
}
return result;
}
private static function createClassNameFromQname(qn:QName):String
{
var result:String
if (qn.uri)
{
result = qn.uri + "::" + qn.localName
}
else
{
result = qn.localName
}
return result;
}
public static function getUnsatisfiedDependencies(swfBytes:ByteArray):Array /* of String */
{
var result:Array = [];
var dependencies:Array = SwfDependencyUtil.getDependencies(swfBytes)
for each (var dependency:String in dependencies)
{
if (ApplicationDomain.currentDomain.hasDefinition(dependency))
{
trace('ok: ', dependency);
}
else
{
trace('ERROR: unsatisfied dependency: ', dependency);
result.push(dependency);
}
}
return result;
}
}
}