2

ビデオを読み込んでいる flvplayback コンポーネントがあります。

次のフレームと前のフレームのアクションを模倣するために、ロードされたフレームの長さの 1 秒ごとにキュー ポイントを追加しています。

次のフレーム/前のフレーム関数は、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 : addASCuePoint() を使用してロードされたムービーの長さに沿って ActionScript 3.0 でキュー ポイントを動的に追加する正しい方法は何ですか?

  • 質問 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

質問の第 3 グループ

*キューポイントをスキップせずに、連続するキューポイントで MetadataEvent.CUE_POINT をトリガーするにはどうすればよいですか?*

*各キュー ポイントで MetadataEvent.CUE_POINT イベントをトリガーする方法は、たとえば 100 ミリ秒間隔です。*

奇妙に思えるかもしれませんが、特定のキュー ポイント イベントを受け取ることを保証することはできません。キュー ポイント イベントはマーシャリングまたはキューに入れられません。FLV コンテナと swf の間のフレーム レートが異なるため、一部のイベントは破棄されます。含まれている swf ファイルが「フレーム間」にある場合、ほとんどの場合、flv のキューポイントが失われます。キューポイントが 100 ミリ秒離れていて、swf に標準の 24 fps を使用している場合。5 つのキュー ポイント イベントごとに少なくとも 1 つが失われると予想できます。これは、フラッシュが多くのこと (ガベージ コレクションなど) を処理する方法と似ていますが、「フレーム」を移動する必要がある場合は、基礎となるプロセスの実行を停止します。フレーム レートとキュー ポイント間隔を同期しても、イベントを見逃すことがあります。

今... 言われていることはすべて。キュー ポイントを使用しないことで、目的を達成できます。playheadUpdate イベントを監視し、再生ヘッド時間が増加するにつれて必要な数のイベントをディスパッチするだけです。たとえば... 100 ミリ秒ごとに 1 回のイベントが必要で、再生ヘッドが前回から 223 ミリ秒移動した場合、2 つのイベントをディスパッチします。30 ミリ秒だけ移動した場合は、イベントを送出しないでください....

質問の 2 番目のグループ

質問 1 : シークがキュー ポイントをスキップし、すべての呼び出しで機能しないのはなぜですか

ビデオのキー フレームのみをシークできます。好きな場所にキュー ポイントを定義できますが、シークは常に次の最も近いキー フレームをシークします。これが、あなたが見ている行動を見る理由です。

livedocs の FLVPlayback.seek() からの抜粋

... プログレッシブ ダウンロードの場合、シークできるのはキーフレームのみであるため、シークは指定された時間の後に最初のキーフレームの時間に移動します...シークは非同期です...シーク後の時間を取得するには完了、seek イベントをリッスン...


質問 2: ミリ秒秒のキュー ポイントでこれを機能させる方法

誰もこれを聞きたがりませんが 、flv を変更してそれらのポイントにキー フレームを挿入することができない限り、おそらくこれを行うことはできません。ただし、これができれば、キュー ポイントを動的に追加する必要はないと思います。


質問 3 : プログラムを中断せずにキュー ポイントをミリ秒単位で動的に追加するにはどうすればよいですか。

ですから、ここで少し話が逸れますが、キュー ポイントをまったく使用しないことをお勧めします。flv の再生中、および/または flv 内の特定の位置をシークしようとしているときに、特定の間隔でイベントを発生させようとしているようです。

flv 内の任意の位置へのシークには、キュー ポイントは必要ありません。時間をミリ秒単位でシーク コマンドに渡すだけです。(上記の注意点として、シークできるのはキー フレームのみです。)

playheadUpdateInterval を設定し、 playheadUpdateイベントにリスナーを追加したい flvplayback から間隔でイベントを取得する簡単な方法があります。このイベントには、ディスパッチされた時点での再生ヘッド時間が含まれます。

あなたの場合、間隔を 33 ミリ秒に設定し、イベントにアタッチされたリスナーでやりたいことを何でもします。

これらすべてについて留意すべきことの 1 つは、FLV の再生が、swf ファイルとは異なるフレーム レートの別の「タイムライン」で発生していることです。このため、2 つの間のタイミングが正確になることはほとんどありません。


最初の質問グループ

質問 1 : addASCuePoint() を使用してロードされたムービーの長さに沿って ActionScript 3.0 でキュー ポイントを動的に追加する正しい方法は何ですか?

上記のforループを修正すると問題ないようです


質問 2 : 適切にシークできる 33ms 間隔でキュー ポイントを追加できますか? はい、任意の間隔または場所にキュー ポイントを追加できますが、これはキーフレームが存在する場所には関係ありません。


質問 3: 上記のコードのどこが間違っていますか? 率直に言って、それはキューポイントの乱用です。彼らは本当にあなたが探しているものではありません。


于 2011-03-22T15:11:51.077 に答える
2

flv を毎秒エクスポートするときにキー フレームを追加してみてください。これは、プログレッシブの場合、ビデオのキー フレームしかシークできないためです。ストリーミングするときは、正確な時間に行くことができます。

Q1. video1.addASCuePoint(i, "cuePoint"+String(i));これに関する私の唯一の懸念は、i の初期値が 0 であることです。この値が保存されるかトリガーされるかはわかりませんが、そうかもしれません。

Q2. ビデオがストリーミングの場合、またはプログレッシブで、そこにキー フレームがあり、フレーム レートが 30 fps 以上の場合は、はい。33 ミリ秒ごとにキューポイントを設定するには、ビデオを 30 fps にする必要があります。キューポイントを 40 ミリ秒ごとに設定できる場合は、25 fps で問題ありません。フレームレートはエンコード時に設定され、通常はソースと同じままです。

Q3. 試してみるいくつかのこと:

seekToPrevOffset()より低い値に設定してみてください。0.1 (または、フレームにキューポイントを配置する場合は、もっと小さい値)。デフォルトでは 1 に設定されています。これは、キュー ポイントをスキップする可能性があることを意味します。

playheadUpdateIntervalまた、 を 250 からおそらく 50 に下げてみてください。これはシークに役立つ場合があります。30 ミリ秒ごとに頻繁にシークする場合は、さらに低く設定する必要があります。

ビデオがプログレッシブの場合、ロードされたものより先にシークしないでください。そうしないと、再生ヘッドが最初に戻ります。

seekToNextNavCuePoint()現在の再生ヘッド時間に基づいて、前のシーク コマンドが完了するまで、ユーザーが [次へ] をクリックできないようにします。seekToNextNavCuePoint(myCheckForwardFromHereVar)または、ユーザーがシーク コマンドの完了を待たずに複数回 next を押すことができるように、値を渡すこともできます。

さらに細かく制御したい場合は、ビデオのどこにいるのかを追跡し、 を使用seekToNavCuePoint()して独自の機能を作成できseekToNextNavCuePointますseekToNextPrevCuePoint。例えば。

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

于 2011-03-15T07:40:43.880 に答える
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 の長さを超えないようにして
ください 33 ミリ秒でビジュアル アイテムを変更している場合、人々の目を出血させます

質問 3: 上記のコードのどこが間違っていますか?
キュー ポイントがどこで何をするかを定義したことはありません。各キューポイントで何をするかの例を挙げていただけますか?

あなたがより多くの情報を与えるとき、私はこれを編集します。

于 2011-03-18T22:34:46.127 に答える