Проблема AS3 Динамическое добавление ключевых точек в flv и поиск следующей ключевой точки - PullRequest
2 голосов
/ 14 марта 2011

У меня есть компонент 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 , рамка смещается к ключевой точке1, независимо от того, где находится текущая ключевая точка. Когда я нажимаю кнопку nextFrame , ключевая точка и дисплей, по-видимому, меняются на следующую, но вскоре после нескольких щелчков ключевая точка меняется на 1, и видео начинается с начала.

  • Вопрос 1: Что такое правильный способ динамического добавления ключевых точек в ActionScript 3.0 по длине загруженного фильма с помощью addASCuePoint ()

  • Вопрос 2: Можем ли мы добавить ключевые точки с интервалами в 33 мс, при которых мы можно правильно искать?

  • Вопрос 3: Что не так в приведенном выше коде?

    обновление: Добавление награды: решить проблему и ответить на 3 вопроса

Обновление:


После долгих неудачных испытаний вышеуказанными методами и опробования предложений Тревора. Я получил функциональность, работающую через метод 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

Edit:

  • Вопрос 1: Как мы можем вызвать MetadataEvent.CUE_POINT для последовательных ключевых точек, т. Е. Без пропуска ключевой точки.
  • Вопрос 2: Каким образом мы запускаем событие MetadataEvent.CUE_POINT в каждой ключевой точке, когда они, скажем, с интервалом 100 мс.

Ответы [ 3 ]

3 голосов
/ 22 марта 2011

Третья группа вопросов

* Как мы можем вызвать MetadataEvent.CUE_POINT для последовательных ключевых точек, т. Е. Без пропуска ключевой точки. *

* Как мы можем вызвать событие MetadataEvent.CUE_POINT в каждой ключевой точке, когда они, скажем, с интервалом 100 мс. *

Это может показаться странным, но вы не можете гарантировать, что получите конкретное событие ключевой точки. События ключевой точки не маршалируются и не ставятся в очередь. Поскольку частота кадров между контейнером FLV и swf различна, некоторые события просто будут выброшены. Если ваш содержащий SWF-файл находится «между кадрами», он почти наверняка пропустит контрольные точки на FLV. Если контрольные точки разнесены на 100 мс, и вы используете стандартные 24fps для SWF. Я предполагаю, что вы можете ожидать потерять как минимум 1 из каждых 5 событий ключевой точки Это похоже на то, как flash обрабатывает множество вещей (например, сборщик мусора), он делает все возможное, но останавливает выполнение базового процесса, если 'frame' должен двигаться дальше. Даже если вы синхронизируете частоту кадров и интервал ключевой точки, вы все равно время от времени пропускаете события.

Теперь ... все это сказано. Вы можете достичь желаемого, не используя контрольные точки. Просто следите за событием playheadUpdate и отправляйте столько событий, сколько вам нужно по мере увеличения времени воспроизведения. Например ... если вы хотите, чтобы событие происходило каждые 100 мс, а точка воспроизведения переместилась на 223 мс с последнего раза, отправьте 2 события. Если он перемещен только на 30 мс, не отправляйте никаких событий ....

Вторая группа вопросов

Вопрос 1: Почему поиск пропускает ключевые точки и не работает при каждом вызове

Вы сможете искать только ключевые кадры в своем видео. Вы можете определить ключевые точки, где захотите, однако поиск всегда будет искать следующий ближайший ключевой кадр. Вот почему вы видите поведение, которое вы видите.

выдержка из FLVPlayback.seek () для liveocs

... для последовательной загрузки вы можете выполнять поиск только по ключевому кадру, поэтому поиск приводит вас ко времени первого ключевого кадра после указанного времени ... поиск выполняется асинхронно, ... Чтобы получить время после завершения поиска, прослушайте событие поиска ...


Вопрос 2: Как заставить это работать на второй ключевой точке мельницы

Никто не любит это слышать, но вы, вероятно, не сможете сделать это , если только вы не сможете изменить flv и вставить ключевой кадр в эти точки. Однако я предполагаю, что, если бы вы могли сделать это, вам не нужно было бы динамически добавлять ключевые точки.


Вопрос 3. Как динамически добавлять метки в миллисекундном диапазоне без прерывания программы.

Итак, вот где я немного отклонюсь и рекомендую вам вообще не использовать контрольные точки. Похоже, что вы пытаетесь получить событие для запуска в данный интервал во время игры на flv и / или пытаетесь искать заданные позиции на flv.

Поиск любой позиции на flv не требует контрольных точек. Просто передайте время в миллисекундах команде поиска. (С учетом оговорки, о которой говорилось выше, вы сможете искать только ключевые кадры.)

Существует более простой способ получить события на интервале от flvplayback, для которого вы хотите установить playheadUpdateInterval и добавить прослушиватель для события playheadUpdate . Это событие включает время начала игры на момент его отправки.

В вашем случае просто установите интервал 33 мс и делайте все, что хотите, в слушателе, прикрепленном к событию.

При этом следует иметь в виду, что воспроизведение FLV происходит на отдельной «временной шкале» с частотой кадров, отличной от вашего SWF-файла. Из-за этого время между ними почти никогда не будет точным.


Первая группа вопросов

Вопрос 1. Какой правильный способ динамически добавлять ключевые точки в ActionScript 3.0 по длине загруженного фильма с помощью addASCuePoint ()

коррекция вышеприведенный цикл for выглядит нормально


Вопрос 2: Можем ли мы добавить контрольные точки с интервалами в 33 мс, к которым мы можем правильно стремиться? Да, вы можете добавлять ключевые точки в любой интервал или место по вашему желанию, но это никак не влияет на то, где существуют ключевые кадры.


Вопрос 3. Что не так в приведенном выше коде? Честно говоря, это злоупотребление контрольными точками.Они действительно не то, что вы ищете.


2 голосов
/ 15 марта 2011

Попробуйте добавлять ключевые кадры в flv, когда вы экспортируете его каждую секунду, потому что если он прогрессивный, вы можете искать только ключевые кадры в своем видео.При потоковой передаче вы можете перейти к точному времени.

Q1.video1.addASCuePoint(i, "cuePoint"+String(i)); будет работать нормально, мое единственное небольшое беспокойство по поводу этого - начальное значение i, равное 0, я не уверен, будет ли это значение сохранено или запущено ... но это может быть.

Q2.Да, если видео потоковое или оно прогрессивное, и в нем есть ключевой кадр, а частота кадров составляет 30 кадров в секунду или выше.Чтобы иметь контрольные точки каждые 33 мс, ваше видео должно быть 30 кадров в секунду.Если бы вы могли жить с контрольными точками каждые 40 мсек, было бы неплохо иметь 25fps.Частота кадров устанавливается во время кодирования и обычно остается такой же, как у источника.

Q3.Несколько вещей, чтобы попробовать:

Попробуйте установить seekToPrevOffset() на более низкое значение, например.0.1 (или что-то намного меньшее, если вы планируете размещать контрольные точки на кадрах), по умолчанию он равен 1, что означает, что он может пропускать контрольные точки.

Также попробуйте уменьшить значение playheadUpdateInterval до 50 с250, это может помочь с поиском.При частом поиске через каждые 30 мс вам придется поставить его еще ниже.

Если видео прогрессивное, не ищите дальше, чем загружено, в противном случае точка воспроизведения вернется к началу.

Не позволяйте пользователю нажимать кнопку «Далее» до тех пор, пока не будет выполнена предыдущая команда поиска, поскольку seekToNextNavCuePoint() зависит от текущего времени воспроизведения.В качестве альтернативы вы можете передать значение в seekToNextNavCuePoint(myCheckForwardFromHereVar), чтобы пользователь мог нажимать следующие несколько раз, не дожидаясь завершения команды поиска.

Если вы хотите иметь еще больший контроль, вы можете отслеживать, где вы находитесьв видео, а затем используйте seekToNavCuePoint() для создания собственных функций seekToNextNavCuePoint и seekToNextPrevCuePoint.например,

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

1 голос
/ 19 марта 2011

Вопрос 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: Можем ли мы добавить метки с интервалами в 33 мс, к которым мы можем стремиться?
См. Ответ на вопрос 1: не пропускайте длину flv
Если вы меняете визуальные элементы на 33 мс, у людей кровоточат глаза

Вопрос 3. Что не так в приведенном выше коде?
Вы никогда не определяли, где и что делают ключевые точки. Можете ли вы привести пример того, что вы будете делать в каждой ключевой точке?

Я отредактирую это, когда вы дадите больше информации.

...