I have a flvplayback component onto which I am loading a video.
To mimic next frame and previous frame actions I am adding cue points to the loaded for every second of its length.
The next frame /previous frame functions implement seekToNextNavCuePoint and seekToPrevNavCuePoint
on the video.
But its not working the way I expected it to.
Here is the actual class file. You can directly compile it with an fla file containing button instances in the library for play pause stop... Also you would need some sample flv file.
package
{
/*
The fla file contains buttons in the library;
*/
import flash.events.*;
import flash.display.*;
import fl.video.*;
public class testPlayer extends MovieClip
{
private var video1:FLVPlayback;
private var play_btn:PlayButton;
private var pause_btn:PauseButton;
private var stop_btn:StopButton;
private var nextFrame_btn:ForwardButton;
private var previousFrame_btn:ForwardButton;
public function testPlayer()
{
// constructor code
addEventListener(Event.ADDED_TO_STAGE,onAdded);
}
private function onAdded(event:Event)
{
setPlayer();
setPath();
setButtons();
}
private function setPlayer()
{
video1 = new FLVPlayback ;
this.addChild(video1);
video1.x = 50;
video1.y = 50;
}
private function setPath()
{
video1.addEventListener(VideoEvent.READY, flvPlayback_ready);
video1.addEventListener(MetadataEvent.CUE_POINT, flvPlayback_cuePoint);
// here you can give any flv you have and its total time
video1.load("test.flv",3600,false);
}
private function flvPlayback_ready(evt:VideoEvent):void
{
var num:Number = video1.totalTime;
for (var i:int=0; i<num; i++)
{
video1.addASCuePoint(i, "cuePoint"+String(i));
}
this.removeEventListener(VideoEvent.READY, flvPlayback_ready);
}
private function flvPlayback_cuePoint(evt:MetadataEvent):void
{
trace("CUE POINT!!!");
trace("\t", "name:", evt.info.name);// name: cuePoint1
trace("\t", "time:", evt.info.time);// time: 1
trace("\t", "type:", evt.info.type);// type: actionscript
}
private function setButtons()
{
play_btn=new PlayButton();
pause_btn=new PauseButton();
stop_btn=new StopButton();
nextFrame_btn=new ForwardButton();
previousFrame_btn=new ForwardButton();
play_btn.addEventListener(MouseEvent.CLICK,onPlay);
pause_btn.addEventListener(MouseEvent.CLICK,onPause);
stop_btn.addEventListener(MouseEvent.CLICK,onStop);
nextFrame_btn.addEventListener(MouseEvent.CLICK,onNextFrame);
previousFrame_btn.addEventListener(MouseEvent.CLICK,onPreviousFrame);
play_btn.x = 50;
play_btn.y = 350;
previousFrame_btn.x = 125;
previousFrame_btn.y = 350;
previousFrame_btn.scaleX *= -1;
nextFrame_btn.x = 150;
nextFrame_btn.y = 350;
pause_btn.x = 200;
pause_btn.y = 350;
stop_btn.x = 250;
stop_btn.y = 350;
addChild(play_btn);
addChild(pause_btn);
addChild(stop_btn);
addChild(previousFrame_btn);
addChild(nextFrame_btn);
}
private function onPlay(event:MouseEvent)
{
video1.play();
}
private function onPause(event:MouseEvent)
{
video1.pause();
}
private function onStop(event:MouseEvent)
{
video1.stop();
}
private function onNextFrame(event:Event)
{
if (video1.playing)
{
//video1.pause();
}
// this is not working the way i expected it to
video1.seekToNextNavCuePoint();
}
private function onPreviousFrame(event:Event)
{
if (video1.playing)
{
//video1.pause();
}
// this is not working the way i expected it to
video1.seekToPrevNavCuePoint();
}
}
}
What am I missing here? Just running it without invoking next/prev frame functions shows that the cue points being activated for every second as per the flvPlayback_cuePoint function.
update:
When I click the previousFrame button the frame shifts to cuepoint1 , irrespective of where the present cuepoint is. When I click the nextFrame button, the cue point and the display seemingly changes to next, but soon after a few clicks the cue point changes to 1 and the video starts from the beginning.
Question 1 : What is the Correct way to dynamically add Cue points in ActionScript 3.0 along the length of the loaded movie using addASCuePoint()
Question 2 : Can We add cue points with at intervals of 33ms, at which we can properly seek to?
Question 3: What is wrong in the above code?
update: Adding a bounty : To solve the problem and answers to The 3 questions
update:
After much unsuccessful trials with the above methods and trying out suggestions by Trevor. I got the functionality working through seek() method but with considerable lack of precision .
package
{
/*
The fla file contains buttons in the library;
*/
import flash.events.*;
import flash.display.*;
import fl.video.*;
public class testPlayer extends MovieClip
{
private var video1:FLVPlayback;
private var play_btn:PlayButton;
private var pause_btn:PauseButton;
private var stop_btn:StopButton;
private var nextFrame_btn:ForwardButton;
private var previousFrame_btn:ForwardButton;
private var playHeadTime:Number;
private var cue:Object;
public function testPlayer()
{
addEventListener(Event.ADDED_TO_STAGE,onAdded);
}
private function onAdded(event:Event)
{
setPlayer();
setPath();
setButtons();
playHeadTime = 0;
}
private function setPlayer()
{
video1 = new FLVPlayback ;
this.addChild(video1);
video1.x = 50;
video1.y = 50;
}
private function setPath()
{
video1.playheadUpdateInterval = 50;
video1.seekToPrevOffset = 0.01;
video1.addEventListener(VideoEvent.READY, flvPlayback_ready);
video1.addEventListener(MetadataEvent.CUE_POINT, flvPlayback_cuePoint);
video1.load("test.flv",3600,false);
}
private function flvPlayback_ready(evt:VideoEvent):void
{
// changing this loop to add more cue points causes the program to hang.
for (var i:int=0; i<video1.totalTime; i++)
{
cue= new Object();
cue.time = i;
cue.type = "navigation";// this does not seem to get set the type
cue.name = "cuePoint" + String(i);
video1.addASCuePoint(cue,cue.name);
}
video1.removeEventListener(VideoEvent.READY, flvPlayback_ready);
}
private function flvPlayback_cuePoint(evt:MetadataEvent):void
{
trace("CUE POINT!!!");
trace("\t", "name:", evt.info.name);// name: cuePoint1
trace("\t", "time:", evt.info.time ," playhead time :",String(Math.round(video1.playheadTime)));// time: 1
trace("\t", "====type:", evt.info.type);// traces actionscript instead of navigation
}
private function setButtons()
{
play_btn=new PlayButton();
pause_btn=new PauseButton();
stop_btn=new StopButton();
nextFrame_btn=new ForwardButton();
previousFrame_btn=new ForwardButton();
play_btn.addEventListener(MouseEvent.CLICK,onPlay);
pause_btn.addEventListener(MouseEvent.CLICK,onPause);
stop_btn.addEventListener(MouseEvent.CLICK,onStop);
nextFrame_btn.addEventListener(MouseEvent.CLICK,onNextFrame);
previousFrame_btn.addEventListener(MouseEvent.CLICK,onPreviousFrame);
play_btn.x = 50;
play_btn.y = 350;
previousFrame_btn.x = 125;
previousFrame_btn.y = 350;
previousFrame_btn.scaleX *= -1;
nextFrame_btn.x = 150;
nextFrame_btn.y = 350;
pause_btn.x = 200;
pause_btn.y = 350;
stop_btn.x = 250;
stop_btn.y = 350;
addChild(play_btn);
addChild(pause_btn);
addChild(stop_btn);
addChild(previousFrame_btn);
addChild(nextFrame_btn);
}
private function onPlay(event:MouseEvent)
{
video1.play();
}
private function onPause(event:MouseEvent)
{
video1.pause();
}
private function onStop(event:MouseEvent)
{
video1.stop();
}
private function onNextFrame(event:Event)
{
if (video1.playing)
{
video1.stop();
}
trace("Calling nextFrame :::",playHeadTime);
video1.seek(playHeadTime);
playHeadTime += 1;
}
private function onPreviousFrame(event:Event)
{
if (video1.playing)
{
video1.stop();
}
trace("Calling prevFrame ::::",playHeadTime);
video1.seek(playHeadTime);
playHeadTime -= 1;
}
}
}
The output for the following traces out like given below. The problem is the next and previous functions keep skipping cue points and don't seem to work at certain cue points. the trace below should give the clear picture.
Calling nextFrame ::: 0
CUE POINT!!!
name: cuePoint0
time: 0 playhead time : 0
====type: actionscript
Calling nextFrame ::: 1
CUE POINT!!!
name: cuePoint2
time: 2 playhead time : 2
====type: actionscript
Calling nextFrame ::: 2
Calling nextFrame ::: 3
CUE POINT!!!
name: cuePoint4
time: 4 playhead time : 4
====type: actionscript
Calling prevFrame :::: 4
Calling prevFrame :::: 3
Calling prevFrame :::: 2
CUE POINT!!!
name: cuePoint2
time: 2 playhead time : 2
====type: actionscript
Edit:
- Question 1 : How can we trigger the MetadataEvent.CUE_POINT on successive cue points i.e without it skipping a cue point.
- Question 2 : How cab we trigger the MetadataEvent.CUE_POINT event at each cue point when they are lets say at 100 ms intervals.
*How can we trigger the MetadataEvent.CUE_POINT on successive cue points i.e without it skipping a cue point.*
*How cab we trigger the MetadataEvent.CUE_POINT event at each cue point when they are lets say at 100 ms intervals.*
It may seem strange, but you cannot guarantee that you will receive a specific cue point event. Cue point events are not marshaled or queued. Since the frame rates between the FLV container and the swf are different some events will just get thrown out. If your containing swf file is "between frames" it will almost certainly miss cuepoints on the flv. If the cuepoints are 100ms apart and you are using the standard 24fps for the swf. I estimate that you could expect to loose at least 1 out of every 5 cue point events. This is similar to the way flash handles a number of things (like garbage collection) it does the best it can but it will halt execution of underlying process if the 'frame' needs to move on. Even if you sync the frame rate and the cue point interval you will still miss events occasionally.
Now... all that being said. You could accomplish what you want by not using cue points. Just monitor the playheadUpdate event and dispatch however many events you need as the playhead time increases. For example... if you want the event once every 100 ms and the playhead has moved 223ms since the last time, then dispatch 2 events. If it's only moved 30ms don't dispatch any events....
Question 1 : Why is the seek skipping cue points and not working on every call
You will only be able to seek to key frames in your video. You can define cue points wherever you like however seek will always seek to the next nearest key frame. This is why you see the behavior you are seeing.
excerpt from FLVPlayback.seek() on livedocs
... for a progressive download, you can seek only to a keyframe, so a seek takes you to the time of the first keyframe after the specified time...seeking is asynchronous, ... To obtain the time after the seek is complete, listen for the seek event...
Question 2 : How to get this working at mills second cue points
No one likes to hear this, but you probably won't be able to do this unless you are able to modify the flv and have a key frame inserted there at those points. However I am guessing that if you could do this you wouldn't need to dynamically add the cue points.
Question 3 : How do i add cue points dynamically in millisecond range without breaking the program.
So here is where I diverge a litle bit and recommend that you not use cue points at all. It seems that you are trying to get an event to fire on given interval while playing the flv and/or trying to seek to given positions in an flv.
Seeking to any position in an flv does not require cue points. Just pass the time in milliseconds to the seek command. (With the caveat as mentioned above that you will only be able to seek to key frames.)
There is an easier way to get events on an interval from the flvplayback you want to set the playheadUpdateInterval and add a listener to the playheadUpdate event. This event includes the play head time at the moment it was dispatched.
In your case just set the interval to 33 ms, and do whatever it is you want to do in a listener attached to the event.
One thing to keep in mind with all this is that the FLV playback is occurring on a separate "timeline" with a different frame rate than your swf file. Because of this timing between the two will almost never be exact.
Question 1 : What is the Correct way to dynamically add Cue points in ActionScript 3.0 along the length of the loaded movie using addASCuePoint()
correction the for loop you have above looks fine
Question 2 : Can We add cue points with at intervals of 33ms, at which we can properly seek to? Yes you can add cue points at any interval or place you would like, but this has no bearing on where keyframes exist.
Question 3: What is wrong in the above code? Frankly it's an abuse of cue points. They really aren't what you are looking for.