Using Flash video metadata to display annotations

Now that you can create a streaming Flash video player with PHP or Ruby and you know add metadata for cuepoints to Flash videos you are ready for something else. The following code will show you how to create a video player with PHP that will watch for metadata events and display annotations contained inside the metadata either over the video itself or in a div on the same page as the movie.

The first steps are to create your Flash video if you haven't already and then add the metadata to it. See my post on adding cuepoint metadata with flvtool2 if you want to know more on how to create the Flash video and add the metadata. I'm using the same video from that post but a different set of metadata.

Here is the metadata I've added to the video for the following examples:

<tags>
    <metatag event="onCuePoint" overwrite="true">
        <name>Cue Point 1</name>
        <timestamp>4000</timestamp>
        <parameters>
            <mydata>Some data 1</mydata>
        </parameters>
        <type>event</type>
    </metatag>
    <metatag event="onCuePoint" overwrite="true">
        <name>Cue Point 2</name>
        <timestamp>8000</timestamp>
        <parameters>
            <mydata>Some data 2</mydata>
        </parameters>
        <type>event</type>
    </metatag>
    <metatag event="onCuePoint" overwrite="true">
        <name>Cue Point 3</name>
        <timestamp>12000</timestamp>
        <parameters>
            <mydata>Some data 3</mydata>
        </parameters>
        <type>event</type>
    </metatag>
    <metatag event="onCuePoint" overwrite="true">
        <name>Cue Point 4</name>
        <timestamp>16000</timestamp>
        <parameters>
            <mydata>Some data 4</mydata>
        </parameters>
        <type>event</type>
    </metatag>
</tags>

The main thing to notice here is that the type for each metatag is event and in the parameters list there is a tag called mydata that contains some text. The text inside mydata is what we will be using for annotations. This tag can be called anything you like and you can have more than one.

I am using icons from the famfamfam silk collection in the following examples. You will want to download them before trying these examples.

wget http://www.famfamfam.com/lab/icons/silk/icons/control_pause.png
wget http://www.famfamfam.com/lab/icons/silk/icons/control_pause_blue.png
wget http://www.famfamfam.com/lab/icons/silk/icons/control_start.png
wget http://www.famfamfam.com/lab/icons/silk/icons/control_start_blue.png
wget http://www.famfamfam.com/lab/icons/silk/icons/control_play.png
wget http://www.famfamfam.com/lab/icons/silk/icons/control_play_blue.png

The first example will display the annotation over the video itself. Here is the PHP code for generating the Flash player to display the annotations:

<?php
function createImage($img)
{
  $shape = new SWFShape();
  $shape->setRightFill($shape->addFill(new SWFBitmap(fopen($img, "rb"))));
  $shape->drawLine(16,0);
  $shape->drawLine(0,16);
  $shape->drawLine(-16,0);
  $shape->drawLine(0,-16);
  return $shape;
}

function createButton($movie, $name, $loc, $script)
{
  $button = new SWFButton();
  $button->addShape(createImage("control_" . $name . ".png"), SWFBUTTON_UP);
  $button->addShape(createImage("control_" . $name . "_blue.png"), SWFBUTTON_DOWN | SWFBUTTON_HIT | SWFBUTTON_OVER);
  $button->addAction(new SWFAction($script), SWFBUTTON_HIT);
  $item=$movie->add($button);
  $item->moveto($loc,248);
}

Ming_setScale(20.0000000);
ming_useswfversion(7);

$movie = new SWFMovie(7);
$movie->setDimension(320,270); // width x height
$movie->setBackground(0x33,0x33,0x33);
$movie->setRate(8);

createButton($movie, "start", 10, "_root.videoStream.seek(0);");
createButton($movie, "pause", 40, "_root.videoStream.pause(true);");
createButton($movie, "play", 70, "_root.videoStream.pause(false);");

$strAction = "
this.createTextField('video_txt', 999, 0, 0, 100, 100);
video_txt.autoSize = 'left';
video_txt.multiline = true;
video_txt.textColor = 0xeeeeee;

stop();
nc=new NetConnection();
nc.connect(null);
videoStream=new NetStream(nc);
videoStreamItem.attachVideo(videoStream);
videoStream.setBufferTime(10);
videoStream.play('http://localhost/test.flv');
videoStream.pause();

videoStream.onCuePoint = function(infoObject)
{
  video_txt.text = 'Name: ' + infoObject.name + '\n';
  if( infoObject.parameters != undefined )
  {
    video_txt.text += 'Info: ' + infoObject.parameters['mydata'] + '\n';
  }
  else
  {
    video_txt.text += 'Info: undef\n';
  }
};
";

$stream = new SWFVideoStream();
$stream->setDimension(320, 240);
$item=$movie->add($stream);
$item->setName("videoStreamItem");
$movie->add(new SWFAction($strAction));

$movie->nextFrame();

$movie->save("test.swf");
?>

The following part of the above PHP is what connects the cuepoints to the overlay text. Notice the use of the mydata tag. The tag data is available in the parameters hash:

videoStream.onCuePoint = function(infoObject)
{
  video_txt.text = 'Name: ' + infoObject.name + '\n';
  if( infoObject.parameters != undefined )
  {
    video_txt.text += 'Info: ' + infoObject.parameters['mydata'] + '\n';
  }
  else
  {
    video_txt.text += 'Info: undef\n';
  }
};

Here is the result (hit the play button to start the video):

The following examples is the same as the above example except that it uses a javascript call to display the annotation data in a div on the page:

<?php
function createImage($img)
{
  $shape = new SWFShape();
  $shape->setRightFill($shape->addFill(new SWFBitmap(fopen($img, "rb"))));
  $shape->drawLine(16,0);
  $shape->drawLine(0,16);
  $shape->drawLine(-16,0);
  $shape->drawLine(0,-16);
  return $shape;
}

function createButton($movie, $name, $loc, $script)
{
  $button = new SWFButton();
  $button->addShape(createImage("control_" . $name . ".png"), SWFBUTTON_UP);
  $button->addShape(createImage("control_" . $name . "_blue.png"), SWFBUTTON_DOWN | SWFBUTTON_HIT | SWFBUTTON_OVER);
  $button->addAction(new SWFAction($script), SWFBUTTON_HIT);
  $item=$movie->add($button);
  $item->moveto($loc,248);
}

Ming_setScale(20.0000000);
ming_useswfversion(7);

$movie = new SWFMovie(7);
$movie->setDimension(320,270); // width x height
$movie->setBackground(0x33,0x33,0x33);
$movie->setRate(8);

createButton($movie, "start", 10, "_root.videoStream.seek(0);");
createButton($movie, "pause", 40, "_root.videoStream.pause(true);");
createButton($movie, "play", 70, "_root.videoStream.pause(false);");

$strAction = "
this.createTextField('video_txt', 999, 0, 0, 100, 100);
video_txt.autoSize = 'left';
video_txt.multiline = true;
video_txt.textColor = 0xeeeeee;

stop();
nc=new NetConnection();
nc.connect(null);
videoStream=new NetStream(nc);
videoStreamItem.attachVideo(videoStream);
videoStream.setBufferTime(10);
videoStream.play('http://localhost/test.flv');
videoStream.pause();

videoStream.onCuePoint = function(infoObject)
{
  if( infoObject.parameters != undefined )
  {
    geturl('javascript:aTestCall(\'' + infoObject.parameters['mydata'] + '\')');
  }
};
";

$stream = new SWFVideoStream();
$stream->setDimension(320, 240);
$item=$movie->add($stream);
$item->setName("videoStreamItem");
$movie->add(new SWFAction($strAction));

$movie->nextFrame();

$movie->save("test.swf");
?>

This javascript will display the data in the div (note that this won't work for all browsers, I'm just making it simple):

  function aTestCall(data)
  {
    document.getElementById("infoDisplayArea").innerHTML = data;
  }

This is how you would set up the div to display the data:

<div id="infoDisplayArea" style="border: solid 1px #000; padding: 5px 5px 5px 5px; width: 50%;">
No data yet...
</div>

Here is the result (hit the play button to start the video):

No data yet…

Keep an eye on the above box while the video is playing to see the annotations.

Tags: ,

Leave a Reply

Your email address will not be published. Required fields are marked *