AS3问题动态地将提示点添加到flv并寻找下一个提示点

时间:2011-03-14 17:19:45

标签: flash actionscript-3 video-streaming frame flvplayback

我有一个flvplayback组件,我正在加载视频。

为了模仿下一帧和前一帧动作,我将为每一秒的长度添加提示点。

下一帧/上一帧功能在视频上实现seekToNextNavCuePoint和seekToPrevNavCuePoint

但它没有像我预期的那样工作。

这是实际的类文件。您可以使用包含库中按钮实例的fla文件直接编译它以进行播放暂停停止...此外,您还需要一些示例flv文件。

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();
        }
    }

}

我在这里缺少什么?只是在不调用next / prev帧功能的情况下运行它会显示根据flvPlayback_cuePoint函数每秒激活提示点。


update:

当我单击 previousFrame 按钮时,无论当前提示点在何处,帧都会切换到cuepoint1。当我点击 nextFrame 按钮时,提示点和显示屏似乎会更改为下一个,但只需点击几下,提示点就会变为1,视频将从头开始。

  • 问题1:使用 addASCuePoint()

  • 问题2:我们能否以33ms的间隔添加提示点,我们可以在此处添加提示点 可以正确地寻求?

  • 问题3:上述代码有什么问题?

    更新: 添加赏金:解决问题并回答3个问题

  

更新


使用上述方法进行了多次不成功的试验并尝试了Trevor的建议。 我通过seek()方法获得了功能,但缺乏精确度。

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;
        }
    }
}

下面的输出如下所示。问题是下一个和以前的功能一直在跳过提示点,似乎不适用于某些提示点。下面的描述应该给出清晰的图像。

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

编辑:

  
      
  • 问题1:如何在连续的提示点上触发MetadataEvent.CUE_POINT,即不跳过提示点。
  •   
  • 问题2:我们如何在每个提示点触发MetadataEvent.CUE_POINT事件时,让它们以100 ms的间隔发出。
  •   

3 个答案:

答案 0 :(得分:3)

第三组问题

*我们如何在连续的提示点上触发MetadataEvent.CUE_POINT,即不跳过提示点。*

*我们如何在每个提示点触发MetadataEvent.CUE_POINT事件时,如果它们以100毫秒的间隔发出。*

看起来很奇怪,但您不能保证会收到特定的提示点事件。提示点事件未被编组或排队。由于FLV容器和swf之间的帧速率不同,因此某些事件将被抛弃。如果您的包含swf文件是“帧之间”,它几乎肯定会错过flv上的提示点。如果提示点相距100毫秒,并且您使用标准的24fps作为swf。我估计你可能会在每5个提示点事件中至少松开一个。这类似于flash处理许多事情(如垃圾收集)的方式,它尽其所能,但如果“框架”需要继续,它将停止执行底层进程。即使您同步帧速率和提示点间隔,您仍会偶尔错过事件。

现在......所有这一切。你可以通过不使用提示点来完成你想要的。只需监视playheadUpdate事件,然后在播放头时间增加时调度所需的许多事件。例如......如果您希望每100毫秒一次该事件并且播放头自上次移动后移动了223毫秒,则发送2个事件。如果只移动30ms,请不要发送任何事件......

第二组问题

问题1:为什么寻求跳过提示点而不是每次通话

您只能在视频中寻找关键帧。您可以在任何地方定义提示点,但搜索将始终寻找 下一个最近的 关键帧。这就是你看到你所看到的行为的原因。

excerpt from FLVPlayback.seek() on livedocs

  

...对于渐进式下载,您只能搜索关键帧,因此搜索会将您带到指定时间后第一个关键帧的时间...搜索是异步的,...获取寻求完成后的时间,听取寻求事件......


问题2:如何在工厂的第二个提示点

中使用它

没有人喜欢听到这个,但你可能无法做到这一点除非你能够修改flv并在那些点插入一个关键帧。但是我猜你是否可以这样做,你不需要动态添加提示点。


问题3:如何在不破坏程序的情况下以毫秒范围动态添加提示点。

所以这里是我分散一点点的地方,并建议你根本不使用提示点。看起来你正试图在播放flv和/或试图寻找flv中的给定位置时,在给定的时间间隔内触发事件。

寻找flv中的任何位置都不需要提示点。只需将时间(以毫秒为单位)传递给seek命令即可。 (如上所述,您只能寻求关键帧。)

有一种更简单的方法可以从您希望设置 playheadUpdateInterval 的flvplayback获取一段时间的事件,并为 playheadUpdate 事件添加一个侦听器。此事件包括发送时的播放时间。

在您的情况下,只需将间隔设置为33毫秒,并在附加到事件的侦听器中执行您想要执行的任何操作。

要记住这一切的一件事是FLV播放是在一个单独的“时间轴”上进行的,帧速率与swf文件不同。因为这两者之间的时间几乎不会是准确的。


第一组问题

问题1:使用addASCuePoint()

沿着加载的电影的长度在ActionScript 3.0中动态添加提示点的正确方法是什么?

更正 你上面的for循环看起来很好


问题2:我们能否以33毫秒的间隔添加提示点,我们可以正确地寻找? 是的,您可以在任何间隔或地点添加提示点,但这与关键帧的存在无关。


问题3:上述代码有什么问题? 坦率地说,这是滥用提示点。他们真的不是你想要的。


答案 1 :(得分:2)

尝试在每秒导出时将关键帧添加到flv,因为如果它是渐进式的,您只能在视频中寻找关键帧。流式传输时,您可以进入准确的时间。

Q1。 video1.addASCuePoint(i, "cuePoint"+String(i));会正常工作,我唯一关心的是i的初始值为0,我不确定这个值是否会被存储或触发......但它可能是。

Q2。是的,如果视频是流式传输的,或者它是渐进式的,并且那里有一个关键帧,帧速率为30fps或更高。为了每33毫秒获得一次提示点,您的视频需要为30fps。如果你可以每40毫秒使用一次提示点,那么25fps就可以了。帧速率在编码时设置,通常只与源相同。

Q3。一些事情要尝试:

尝试将seekToPrevOffset()设置为较低的值,例如。 0.1(或者如果你计划在帧上放置cuepoints,那么会小很多),默认设置为1,这意味着它可能会跳过提示点。

同时尝试将playheadUpdateInterval从250降低到50,这可能有助于寻求。如果频繁寻求每30毫秒,你将不得不把它降低。

如果视频是渐进式的,请不要进一步搜索,否则播放头会跳回到开头。

不允许用户单击下一个,直到上一个搜索命令完成,因为seekToNextNavCuePoint()基于当前的播放时间。或者,您可以将值传递给seekToNextNavCuePoint(myCheckForwardFromHereVar),以便用户可以多次按下一次,而无需等待搜索命令完成。

如果您希望获得更好的控制权,可以跟踪视频中的位置,然后使用seekToNavCuePoint()创建自己的seekToNextNavCuePointseekToNextPrevCuePoint功能。例如

seekToNavCuePoint("cuePoint" + String(Math.floor(playheadTime))); seekToNavCuePoint("cuePoint" + String(Math.floor(playheadTime)+1));

答案 2 :(得分:1)

问题1:使用addASCuePoint()沿着加载的电影的长度在ActionScript 3.0中动态添加提示点的正确方法是什么

var cue:Object = new Object();
cue.time = 4;
cue.type = "actionscript";
cue.name = "myCue";
video1.addASCuePoint(cuePoints_array[i]);


问题2:我们能否以33ms的间隔添加提示点,我们可以正确地寻找?
请参阅问题1的答案,确保不要超过flv的长度。如果你在33ms更换视觉项目,你会让人眼睛流血

问题3:上述代码有什么问题?
您从未定义过提示点的位置和内容。你能举个例子说明你会在每个提示点做什么吗?
当你提供更多信息时,我会编辑这个。