2

我有一个要加载视频的 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();
        }
    }

}

我在这里想念什么?仅在不调用下一个/上一个帧函数的情况下运行它表明提示点每秒钟都根据 flvPlayback_cuePoint 函数被激活。


update:

当我单击previousFrame按钮时,无论当前提示点在哪里,帧都会转移到 cuepoint1 。当我单击nextFrame按钮时,提示点和显示似乎更改为下一个,但单击几下后提示点立即更改为 1,并且视频从头开始。

  • 问题 1:在 ActionScript 3.0 中使用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 毫秒的间隔说。
4

3 回答 3

3

第三组问题

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

*我们如何在每个提示点触发 MetadataEvent.CUE_POINT 事件,让我们说每隔 100 毫秒。*

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

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

第二组问题

问题 1:为什么寻求跳过提示点而不是在每个呼叫上都起作用

您将只能寻找视频中的关键帧。你可以在任何你喜欢的地方定义提示点,但是 seek 总是会搜索到下一个最近的关键帧。这就是为什么你看到你正在看到的行为。

摘自 livedocs 上的 FLVPlayback.seek()

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


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

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


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

所以在这里我有点分歧,建议你根本不要使用提示点。似乎您正在尝试在播放 flv 和/或尝试寻找 flv 中的给定位置时让事件在给定的时间间隔内触发。

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

有一种更简单的方法可以在您想要设置playheadUpdateInterval的 flvplayback 的某个时间间隔内获取事件,并将侦听器添加到playheadUpdate事件。此事件包括调度时的播放头时间。

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

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


第一组问题

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

更正 你上面的 for 循环看起来不错


问题 2:我们可以以 33ms 的间隔添加提示点,我们可以正确地寻找吗? 是的,您可以在任何您想要的间隔或位置添加提示点,但这与关键帧存在的位置无关。


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


于 2011-03-22T15:11:51.077 回答
2

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

Q1。video1.addASCuePoint(i, "cuePoint"+String(i));可以正常工作,我对此唯一的轻微担忧是 i 为 0 的初始值,我不确定该值是否会被存储或触发......但它可能会。

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

Q3。有几件事要尝试:

尝试设置seekToPrevOffset()为较低的值,例如。0.1(或者如果您打算在帧上放置提示点,则更小一些),默认设置为 1,这意味着它可能会跳过提示点。

还可以尝试将playheadUpdateInterval250 降低到 50,这可能有助于寻找。如果每 30 毫秒频繁搜索一次,您将不得不把它放得更低。

如果视频是渐进式的,请不要比已加载的内容更远,否则播放头会跳回到开头。

seekToNextNavCuePoint()根据当前播放头时间,在前一个搜索命令完成之前,不允许用户单击下一步。或者,您可以传递一个值seekToNextNavCuePoint(myCheckForwardFromHereVar),以便用户可以多次按下 next 而无需等待 seek 命令完成。

如果您想拥有更大的控制权,您可以跟踪您在视频中的位置,然后使用它seekToNavCuePoint()来创建您自己的seekToNextNavCuePoint功能seekToNextPrevCuePoint。例如。

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

于 2011-03-15T07:40:43.880 回答
1

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

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:上面的代码有什么问题?
你从来没有定义过提示点在哪里和做什么。你能举例说明你在每个提示点会做什么吗?

当您提供更多信息时,我将对其进行编辑。

于 2011-03-18T22:34:46.127 回答