I guess I’m Megatron…

Use a Datagrid to Verify and Test Dozens of Videos at Once.

So, you have a couple hundred videos and you need to find out if the duration, cue point information, etc. is correct. What do you do? Well, you could use the MetaData Tester I gave you in my last post about this topic and test the videos one at a time… Or you could load the videos information into a datagrid and see all of them at once.

You can see the example here.

So how do we do this… well, I am using the same PHP script referenced in my other posts on Flash video viewing and testing. This script crawls the directory and parses it into XML.

On stage, I have added a scrollpane to contain the Datagrid (it could get very big horizontally and AS2 datagrids don’t scroll horizontally, if you are using AS3 you don’t need this scrollpane component). In my library I have added a datagrid and put it inside a linked movieClip called videoGrid for placement on stage.

Once my library is all ready, I open the actions editor to write the script that will set up an iterator “currVideo” to store the current video that needs to be loaded in the player. I also create two arrays “allVideos” and “videosData”. The array “allVideos” will be used as the rows in the datagrid and “videosData” will populate the columns in each row. So, how does this all come together:

var currVideo:Number = new Number();
var allVideos:Array = new Array();
var videosData:Array = new Array();
 
var metalistenerObject:Object = new Object();
metalistenerObject.metadataReceived = function(eventObject:Object):Void {
//trace(myPlayer.metadata.cuePoints.length);
var videosData:Array = new Array();
videosData[0] = myPlayer.contentPath;
videosData[1] = myPlayer.metadata.cuePoints.length
videosData[2] = myPlayer.metadata.framerate;
videosData[3] = myPlayer.metadata.height;
videosData[4] = myPlayer.metadata.width;
videosData[5] = myPlayer.metadata.duration;
videosData[6] = myPlayer.metadata.videocodecid;
videosData[7] = myPlayer.metadata.videodatarate;
videosData[8] = myPlayer.metadata.audiodatarate;
for(i=0;i<myPlayer.metadata.cuePoints.length;i++) {
videosData[i+9] = myPlayer.metadata.cuePoints[i].type.substr(0,1) + " : " + myPlayer.metadata.cuePoints[i].name + " : " +  myPlayer.metadata.cuePoints[i].time;
}
 
allVideos.push(videosData);
 
scrolly.spContentHolder.videoGrid.addItem({file:videosData[0].substr(7,videosData[0].length) , CP:videosData[1], FPS:videosData[2], H:videosData[3], W:videosData[4], D:videosData[5], Codec:videosData[6], Video:videosData[7], Audio:videosData[8], CP1:videosData[9], CP2:videosData[10], CP3:videosData[11], CP4:videosData[12], CP5:videosData[13], CP6:videosData[14], CP7:videosData[15], CP8:videosData[16], CP9:videosData[16], CP10:videosData[17], CP11:videosData[18], CP12:videosData[19], CP13:videosData[20], CP14:videosData[21], CP15:videosData[22], CP16:videosData[23], CP17:videosData[24], CP18:videosData[25], CP19:videosData[26], CP20:videosData[27]});
currVideo = currVideo+1;
 
myPlayer.play(null);
myPlayer.play("videos/" + video_arr[currVideo].video);
 
//trace(currVideo + " : " + video_arr[currVideo].video);
 
scrolly.spContentHolder.videoGrid.getColumnAt(0).width = 200; //file
scrolly.spContentHolder.videoGrid.getColumnAt(1).width = 23; //cuepoints
scrolly.spContentHolder.videoGrid.getColumnAt(2).width = 30; //frame rate
scrolly.spContentHolder.videoGrid.getColumnAt(3).width = 28; //height
scrolly.spContentHolder.videoGrid.getColumnAt(4).width = 28; //width
scrolly.spContentHolder.videoGrid.getColumnAt(5).width = 33; //duration
scrolly.spContentHolder.videoGrid.getColumnAt(6).width = 25; //codec
scrolly.spContentHolder.videoGrid.getColumnAt(7).width = 30; //video
scrolly.spContentHolder.videoGrid.getColumnAt(8).width = 30; //audio
scrolly.spContentHolder.videoGrid.getColumnAt(9).width = 120; //cue point 1
scrolly.spContentHolder.videoGrid.getColumnAt(10).width = 120; //cue point 2
scrolly.spContentHolder.videoGrid.getColumnAt(11).width = 120; //cue point 3
scrolly.spContentHolder.videoGrid.getColumnAt(12).width = 120; //cue point 4
scrolly.spContentHolder.videoGrid.getColumnAt(13).width = 120; //cue point 5
scrolly.spContentHolder.videoGrid.getColumnAt(14).width = 120; //cue point 6
scrolly.spContentHolder.videoGrid.getColumnAt(15).width = 120; //cue point 7
scrolly.spContentHolder.videoGrid.getColumnAt(16).width = 120; //cue point 8
scrolly.spContentHolder.videoGrid.getColumnAt(17).width = 120; //cue point 9
scrolly.spContentHolder.videoGrid.getColumnAt(18).width = 120; //cue point 10
scrolly.spContentHolder.videoGrid.getColumnAt(19).width = 120; //cue point 11
scrolly.spContentHolder.videoGrid.getColumnAt(20).width = 120; //cue point 12
scrolly.spContentHolder.videoGrid.getColumnAt(21).width = 120; //cue point 13
scrolly.spContentHolder.videoGrid.getColumnAt(22).width = 120; //cue point 14
scrolly.spContentHolder.videoGrid.getColumnAt(23).width = 120; //cue point 15
scrolly.spContentHolder.videoGrid.getColumnAt(24).width = 120; //cue point 16
scrolly.spContentHolder.videoGrid.getColumnAt(25).width = 120; //cue point 17
scrolly.spContentHolder.videoGrid.getColumnAt(26).width = 120; //cue point 18
scrolly.spContentHolder.videoGrid.getColumnAt(27).width = 120; //cue point 19
scrolly.spContentHolder.videoGrid.getColumnAt(28).width = 120; //cue point 20
scrolly.spContentHolder.videoGrid.getColumnAt(29).width = 120; //cue point 21
scrolly.spContentHolder.videoGrid.getColumnAt(30).width = 120; //cue point 22
};
myPlayer.addEventListener("metadataReceived", metalistenerObject);

You could certainly economize the code above by writing more loops and possibly using array length data a bit more frugally, but it works. It takes a bit of time to crawl a large directory and load each video in order to get the metadata for each one, so once you load this webpage, go check you email or send a twitter or get some coffee. ;-) We used this datagrid to help test and view the videos for our Flash video based site where you can send personalized video message to friends. Go check it out.

You can download the FLA file with all the code above in it, here.

Illustrator used all the RAM in the world.

Yesterday, I was working on some satellite maps and some vector maps of the United States for a project we are working on for a trade show a client is attending. I had these maps open in Illustrator and was attempting to scale/manipulate the vector state, county and sales regions outline layers to match the raster satellite image as closely as possible. I somehow managed to use 16 Million Terabytes of RAM to do so… According to the activity monitor that is… take a look at this screenshot. (click for the full view)

16 Million Terabytes of RAM

The raster image was 8000 pixel wide JPEG and the vector maps had about a half a million points total. Let’s just say I saw a lot of beachballs in the last couple days, even on the Eight Core Mac Pro we have here with 4GB ram.

Easily learn more about your Flash Videos – MetaData Viewer

Building off of my last post on making a Flash Video Jukebox with PHP, we’ll now be adding some functionality to it that allows us to see more information about our FLV file currently playing. All of the metadata. Duration, Codec Type, Cue Point Information, everything. Very useful when QA-ing a batch of files that need to be formatted a certain way, right?

I built this tool to help me and the video team test our assets for CluckHere.com, as there were too many videos and as always not enough time! Because this made checking the videos far quicker than the alternative of dropping them into our application every time we rendered a new clip, it was a godsend. I hope you can find this code useful, too.

Let’s get started.

So after you have a combobox and a FLV Playback component on stage we’ll need to add some more code to interpret the metadata and then send it out to a textarea for read out. I have left a few trace statements in here but have them commented out in case you prefer that method of debugging to onscreen UI elements.

var metalistenerObject:Object = new Object();
metalistenerObject.metadataReceived = function(eventObject:Object):Void {
var messageToOutput:String;
messageToOutput = “canSeekToEnd is ” + myPlayer.metadata.canSeekToEnd + “\n”;
messageToOutput += “Number of cue points is ” + myPlayer.metadata.cuePoints.length + “\n”;
messageToOutput += “=/=/=/=/=\n”;
//trace(“canSeekToEnd is ” + myPlayer.metadata.canSeekToEnd);
//trace(“Number of cue points is ” + myPlayer.metadata.cuePoints.length);
//trace(“=/=/=/=/=”);
for(i=0;i<myPlayer.metadata.cuePoints.length;i++) {
cuePointsArray[i].name = myPlayer.metadata.cuePoints[i].name;
cuePointsArray[i].type = myPlayer.metadata.cuePoints[i].type;
cuePointsArray[i].time = myPlayer.metadata.cuePoints[i].time;

messageToOutput += “–CuePoint-” + i + “-name: ” + myPlayer.metadata.cuePoints[i].name + “\n”;
messageToOutput += “–CuePoint-” + i + “-type: ” + myPlayer.metadata.cuePoints[i].type + “\n”;
messageToOutput += “–CuePoint-” + i + “-time: ” + myPlayer.metadata.cuePoints[i].time + “\n”;
messageToOutput +=”–CuePoint-” + i + “-parameters: ” + myPlayer.metadata.cuePoints[i].parameters + “\n”;
messageToOutput += ” \n”;
//trace(“–CuePoint-” + i + “-name: ” + myPlayer.metadata.cuePoints[i].name);
//trace(“–CuePoint-” + i + “-type: ” + myPlayer.metadata.cuePoints[i].type);
//trace(“–CuePoint-” + i + “-time: ” + myPlayer.metadata.cuePoints[i].time);
//trace(“–CuePoint-” + i + “-parameters: ” + myPlayer.metadata.cuePoints[i].parameters);
//trace(” “);
}
messageToOutput += “=/=/=/=/=\n”;
messageToOutput += “Frame rate is ” + myPlayer.metadata.framerate + “\n”;
messageToOutput += “Height is ” + myPlayer.metadata.height + “\n”;
messageToOutput += “Width is ” + myPlayer.metadata.width + “\n”;
messageToOutput += “Duration is ” + myPlayer.metadata.duration + ” seconds” + “\n”;
messageToOutput += “Video Codec is ” + myPlayer.metadata.videocodecid + “\n”;
messageToOutput += “Video Data Rate is ” + myPlayer.metadata.videodatarate + “\n”;
messageToOutput += “Audio Data Rate is ” + myPlayer.metadata.audiodatarate + “\n”;
_root.textArea.text = messageToOutput;
_root.totalTime_txt.text = myPlayer.metadata.duration;
};
myPlayer.addEventListener(“metadataReceived”, metalistenerObject);

This would probably be good enough, right? Well another thing I wanted to know was exactly when are cue points occurring. In order to do that, we need to set up another listener…

var cplistenerObject:Object = new Object();
cplistenerObject.cuePoint = function(eventObject:Object):Void {
cp_burn.play();
cp_burn.cuePointName.text = eventObject.info.name;
currPoint = currPoint++;
//trace(“Cue Listener Hit”);
};
myPlayer.addEventListener(“cuePoint”, cplistenerObject);

That’ll do it… When a cue point gets hit, a little cigarette burn animation plays on screen along with the name of the cuepoint in a text field to let the viewer know that the cue point was reached.

If you want to see it in action check it out here. You can also download the source file here and pretty easily get this running yourself.

Bonus points to anyone who knows who the cigarette burn animation is. ;-)

How to create a simple Flash Video Jukebox using PHP

NOTE: This example is a little old and uses Actionscript 2, though, if you know AS3 it could be easily converted.

Recently, we completed a project that contained nearly 200 video clips. As part of the development process we needed a way to quickly review the clips that had been selected for the piece. I decided to make a quick and dirty Flash video jukebox that used PHP to generate the XML for the Flash movie. A user could then visit the web page and chose any of the videos and easily watch the desired clip.So, how did I do this? It’s a pretty simple bit of code, really. First the PHP (click to download the source):

&lt;videos&gt;&lt;?php
if ($handle = opendir('videos')) {
 while (false !== ($file = readdir($handle))) {
 if ($file != "." &amp;&amp; $file != ".."){
 echo "t&lt;video&gt;$file&lt;/video&gt;n";} 
}closedir($handle);} ?&gt;

In that snippet, I create the basic element and then open the directory that contains the videos with PHP. I then loop over that directory reading all the files in and then outputting them into the XML as “video” elements that contain the name of the file.Next the Flash… I’ll need to load the XML, obviously and parse it. I like to use Darron Schall’s method for parsing the XML, so I’ll be using that here as well… After it’s loaded and ready, I set the created array to be a data provider for a combo box on the stage:

var filesXML:XML = new XML(); 
filesXML.ignoreWhite = true;
var video_arr:Array = new Array();
 // After loading is complete, trace the XML object.filesXML.onLoad = function(success) { if (success) {var startTime = getTimer();
var videos_xml = filesXML.firstChild;
for (var i = 0; i &lt; videos_xml.childNodes.length; i++) {
 var videoData = new Object(); 
for (var j = 0; j &lt; videos_xml.childNodes[i].childNodes.length; j++) { videoData[videos_xml.childNodes[i].nodeName] = videos_xml.childNodes[i].firstChild.nodeValue; }video_arr.push(videoData); 
} //trace("Total parse time: " + (getTimer()-startTime)) 
} else { trace("Error loading playlist."); 
} // clean up after ourselves 
 delete playlist_xml;
 combo_cb.dataProvider = video_arr; } ;

After that’s ready, I wrap it up by creating the actions for a load button, the FLV playback component and the combo box.

my_button.onRelease = function() { //myPlayer.contentPath = combo_cb.selectedItem; 
file_lbl.text = _root.combo_cb.selectedItem;
 var item_obj:Object = combo_cb.selectedItem;
 var i:String; for (i in item_obj) { trace(i + ":t" + item_obj[i]); file_lbl.text = item_obj[i]; }myPlayer.play("videos/" + item_obj[i]);
 }myPlayer.addEventListener("cuePoint", cplistenerObject); 
var cbListener:Object = new Object(); 
cbListener.change = function(evt_obj:Object) { var item_obj:Object = combo_cb.selectedItem; 
var i:String;for (i in item_obj) { trace(i + ":t" + item_obj[i]);
 } trace(""); }; 
combo_cb.addEventListener("change", cbListener); // Load the XML into the filesXML object.filesXML.load("dirListXML.php"); 
stop();

That’s about it. You’ll now be able to choose a video and quickly see it load in the FLV Playback component. Dead simple.You can check it out here. You can also download a copy of the FLA here. In the next few days I’ll be expanding on this to show how we used Flash to debug and track metadata in the many videos we had to manage.

Page 2 of 212