В данной статье детально рассматривается разработка видео флэш плеера с возможностями использования DVR-функций, таких как функция «TimeShift» и функция постановки на паузу «живого» потока.
В основе, представленного здесь, видео флэш плеера лежит компонент от компании Adobe – FLVPlayback 2.5, а также классы: DynamicStream, DynamicStreamItem.
Создаем новый объект vid, который является экземпляром класса FLVPlayback, а также контейнер для него — объект container типа UIComponent. Помещаем в контейнер объект vid с помощью метода addChild.
\\Создаем новый экземпляр класса FLVPlayback
var vid = new FLVPlayback();
\\Создаем новый экземпляр класса UIComponent
var container:UIComponent = new UIComponent();
container.addChild(vid);
Свойствам объекта vid, присваиваем значения для начала работы с DVR-функциями.
vid.isDVR = true; \\Если поток DVR, то true
vid.isLive = true; \\Если поток «живой», то true
vid.dvrSnapToLive = true; \\Если можно перемещаться к концу, то true
vid.dvrFixedDuration = false; \\Если постоянная длинна, то true
vid.dvrIncrement = 1800;
vid.dvrIncrementVariance = 300;
Добавляем обработчики событий (METADATA_RECEIVED, CUE_POINT, STATE_CHANGE, PROGRESS, PLAYHEAD_UPDATE) объекту vid:
vid.addEventListener(MetadataEvent.METADATA_RECEIVED, onMetaData);
vid.addEventListener(VideoEvent.STATE_CHANGE, onVideoStateChange);
vid.addEventListener(VideoProgressEvent.PROGRESS, progressEventHandler);
vid.addEventListener(VideoEvent.PLAYHEAD_UPDATE, onPlayheadUpdate);
Функция «TimeShift»
DVR-функция «TimeShift» представляет собой возможность воспроизведения «живого» потока с осуществлением функции «перемотки».
Добавляем таймер для исчисления диапазона времени, по которому можно производить перемотку потока назад, и в рамках которого будет осуществляться функция постановки потока на паузу. Для этого создаем новый объект timerNow типа Timer. Добавляем событие, которое через каждую секунду вызывает функцию onTimerNowTick.
var timerNow:Timer = new Timer(1000, 0);
timerNow.addEventListener(TimerEvent.TIMER, onTimerNowTick); Функция onTimerNowTick осуществляет подсчет временного диапазона, присвоение объектам timeEnd , timeStart значений, а также смещает временное окно на секунду назад путем изменения свойств maximum и minimum объекта slider.
private function onTimerNowTick(evt:TimerEvent):void
{
bufferCurrentTime = String(DynamicStream(vid.getVideoPlayer
(vid.activeVideoPlayerIndex).netStream).bufferLength);
if(!isSliderDragging)
{
totalTime++;
slider.maximum = totalTime;
slider.minimum = totalTime - 3600;
}
var timeNOW:Date = new Date();
var h:Number = timeNOW.getHours();
var m:Number = timeNOW.getMinutes();
var s:Number = timeNOW.getSeconds();
timeEnd = (h == 0 ? "00" + ":" : (h < 10 ? "0" + h.toString()
+ ":" : h.toString() + ":"))
+ (m < 10 ? "0" + m.toString() : m.toString()) + ":"
+ (s < 10 ? "0" + s.toString() : s.toString());
if(h == 0) h = 23; else h--;
timeStart = (h == 0 ? "00" + ":" : (h < 10 ? "0" + h.toString()
+ ":" : h.toString() + ":"))
+ (m < 10 ? "0" + m.toString() : m.toString())
+ ":" + (s < 10 ? "0"
+ s.toString() : s.toString());
}
Описываем обработчик события при получении метаданных. Присваиваем totalTime значение максимальной длительности записанного потока в текущий момент, а также корректируем свойства maximum и minimum объекта slider. Получение метаданных происходит один раз при подключении к потоку по инициативе серверной части.
private function onMetaData(evt:MetadataEvent):void
{
totalTime = evt.info.duration;
slider.maximum = totalTime;
slider.minimum = totalTime - 3600;
}
Описываем обработчик события при изменении состояния потока. При получении события PLAYING (начало воспроизведения) добавляем объекту netStream обработчик события NET_STATUS.
private function onVideoStateChange(evt:VideoEvent):void
{
switch(vid.state)
{
case VideoState.PLAYING:
\\Если статус «воспроизведение»
bufferingCanvas.visible = false;
DynamicStream(vid.getVideoPlayer
(vid.activeVideoPlayerIndex).netStream)
.addEventListener(NetStatusEvent.NET_STATUS, onNSStatus);
break;
case VideoState.BUFFERING:
\\Если статус «буферизация»
break;
case VideoState.STOPPED:
\\Если статус «остановлено»
break;
case VideoState.PAUSED:
\\Если статус «пауза»
break;
case VideoState.CONNECTION_ERROR:
\\Если статус «ошибка соединения»
break;
case VideoState.DISCONNECTED:
\\Если статус «соединение закрыто»
break;
case VideoState.LOADING:
\\Если статус «загрузка»
break;
case VideoState.REWINDING:
\\Если статус «перемотка»
break;
}
}
Описываем обработчик события при изменении playheadTime потока. Корректируем переменную currentTime, а также позицую объекта slider.
private function onPlayheadUpdate(evt:VideoEvent):void
{
if(!isSliderDragging)
slider.value = evt.playheadTime;
currentTime = evt.playheadTime;
if(!timerNow.running)
timerNow.start();
} Функция toggleDragging вызывается при перемещении ползунка объекта slider. Если ползунок захвачен, то в эту функцию передается значение true, в противном случае false. Полученное значение входящего параметра присваиваем переменной isSliderDragging. Если полученное значение не true, то вызываем функцию doSeek.
private function toggleDragging(param:Boolean):void
{
isSliderDragging = param;
if (!param)
doSeek();
}
Функция doSeek осуществляет вызов метода seek объекта vid, и передачу этому методу текущие значение свойства value объекта slider. После вызова этого метода осуществляется «прыжок» воспроизведения на указанную секунду.
private function doSeek():void
{
try{
vid.seek(slider.value);
}catch(e:Error){
}
}
Функция постановки на паузу «живого» потока
Описываем обработчик события при изменении состояния netStream. Если воспроизведение потока находится в состоянии пауза, то присваиваем значение true переменной pausedState, в противном случае значение false.
private function onNSStatus(evt:NetStatusEvent):void
{
switch (evt.info.code)
{
case "NetStream.Pause.Notify":
pausedState = true;
break;
case "NetStream.Unpause.Notify":
pausedState = false;
break;
}
}
Функция onPlay вызывается каждый раз при нажатии на кнопку btnPlay. Если текущий активный VideoPlayer объекта vid не равен null, то в зависимости от состояния переменной pausedState осуществляем постановку на паузу, либо начинаем воспроизведение видео потока. Если же текущий активный VideoPlayer объекта vid равен null, то вызываем метод play2, объекта vid, и передаем ему ссылку на объект dsi. После вызова этого метода, будет осуществлено соединение с FMS сервером и начато воспроизведение потока, указанного в dsi.
private function onPlay():void
{
if(DynamicStream(vid.getVideoPlayer(vid.activeVideoPlayerIndex)
.netStream) != null)
{
switch (pausedState)
{
case true:
btnPlay.label = "Play";
DynamicStream(vid.getVideoPlayer
(vid.activeVideoPlayerIndex).netStream).resume();
break;
case false:
btnPlay.label = "Pause";
DynamicStream(vid.getVideoPlayer
(vid.activeVideoPlayerIndex).netStream).pause();
break;
}
}else{
vid.play2(dsi);
}
}