Доброго времени суток!
Это вторая часть статьи о написании своего видеоплеера(первая часть). В этой части мы будем писать плеер, который будет воспроизводить файлы с вашего или другого сервера а так же при отсутствии Flash'a в браузере будет открывать html5 «версию».
Финальный вид плеера не измениться от первой части, но будут убраны кнопки переключения качества(так как не всегда можно найти две копии файла с разным качеством(hd и обычное)) и логотип(вы сможете их добавить), но всё же я приложу скриншот плеера:
Шаг 1: Flash
Для начала создадим новый проект. Как и в первой части я использую Adobe Flash CS4 и Action Script 3. Сохраним проект в любую папку. Так же создадим файл в котором будет храниться весь код и сохраним его в одной папке с проектом. Я назвал файл VideoPlayerClass.as. От имени файла будет зависить дальнейший код.
Открываем VideoPlayerClass.as.
Под спойлером я привёл полный код плеера:
package {
import flash.display.Sprite;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.events.FullScreenEvent;
import flash.media.Video;
import flash.media.SoundTransform;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.Event;
import flash.display.MovieClip;
import flash.display.SimpleButton;
//all
import flash.system.*;
import flash.display.*;
import flash.text.TextField;
//timer
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
public class VideoPlayerClass extends Sprite {
private var videoURL:String = stage.loaderInfo.parameters['file'];
private var autoplay:String = stage.loaderInfo.parameters['autoplay'];
private var width_player:String="720";
private var height_player:String="480";
private var connection:NetConnection;
private var stream:NetStream;
private var video:Video = new Video();
private var cbar:MovieClip = new c_bar();
private var client:Object = new Object();
private var duration:int;
private var fs:SimpleButton = new fs_btn();
private var volume_:SimpleButton = new v();
private var mute:SimpleButton = new vm();
private var sound:SoundTransform=new SoundTransform();
private var play_:SimpleButton = new play_btn();
private var pause_:SimpleButton = new pause_btn();
private var timenow:SimpleButton = new time_now();
private var timenow_i:SimpleButton = new time_now_i();
private var tf:TextField = new TextField();
private var clw, clh, w, h, sec, newstatic;
private var m:Boolean = true;
private var hd_bool:Boolean = false;
private var play__:Boolean = true;
private var time="0";
private var min="0";
private var timer_:Timer = new Timer(1000);
public function VideoPlayerClass() {
connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
connection.connect(null);
}
private function netStatusHandler(event:NetStatusEvent):void {
switch (event.info.code) {
case "NetConnection.Connect.Success":
connectStream();
break;
case "NetStream.Play.StreamNotFound":
trace("Stream not found: " + videoURL);
break;
}
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
private function connectStream():void {
stream=new NetStream(connection);
stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
//stream.client = new CustomClient();
video.attachNetStream(stream);
stream.play(videoURL);
addChild(video);
video.width=this.stage.stageWidth;
video.height=this.stage.stageHeight;
//Get video duration
client.onMetaData = function(metadata:Object):void {
duration=metadata.duration;
};
stream.client = client;
addChild(cbar);
addChild(fs);
addChild(volume_);
addChild(timenow);
addChild(timenow_i);
addChild(tf);
timer();
if(autoplay=='no'){
stream.togglePause();
play__=false;
addChild(play_);
} else {
play__=true;
addChild(pause_);
timer_.start();
}
setParams_start();
tf.textColor=0xFFFFFF;
tf.text="0:0";
tf.width=38;
fs.addEventListener(MouseEvent.CLICK, fs_toogle);
volume_.addEventListener(MouseEvent.CLICK, mute_toogle);
mute.addEventListener(MouseEvent.CLICK, mute_toogle);
play_.addEventListener(MouseEvent.CLICK, play_toogle);
pause_.addEventListener(MouseEvent.CLICK, play_toogle);
timenow.addEventListener(MouseEvent.CLICK, goto);
timenow_i.addEventListener(MouseEvent.CLICK, goto);
stage.addEventListener(FullScreenEvent.FULL_SCREEN, fs_toggle);
}
private function setParams_start(){
w=width_player;
h=height_player;
clw=(w-video.width)/2;
clh=(h-video.height)/2;
cbar.x=110;
cbar.y=407;
play_.x=127;
play_.y=422;
pause_.x=127;
pause_.y=422;
fs.y=422;
fs.x=573;
volume_.x=172;
volume_.y=425;
mute.x=172;
mute.y=425;
lg.x=5;
lg.y=5;
timenow.y=427;
timenow.x=240;
timenow_i.y=427;
timenow_i.x=240;
timenow_i.width=0;
tf.x=200;
tf.y=423;
//Video
video.x=0;
video.y=0;
video.width=w;
video.height=h;
}
private function setParams_new(){
w=this.stage.stageWidth;
h=this.stage.stageHeight;
clw=(w-video.width)/2;
clh=(h-video.height)/2;
newstatic=-clh+h;
cbar.y=newstatic-100;
play_.y=newstatic-85;
pause_.y=newstatic-85;
mute.y=newstatic-85;
volume_.y=newstatic-85;
fs.y=newstatic-88;
tf.y=newstatic-85;
timenow.y=newstatic-81;
timenow_i.y=newstatic-81;
//Video
video.x=-clw;
video.y=-clh;
video.width=w;
video.height=h;
}
private function fs_toogle(event:Event):void{
if(stage.displayState==StageDisplayState.NORMAL){
stage.displayState=StageDisplayState.FULL_SCREEN;
stage.scaleMode=StageScaleMode.NO_SCALE;
setParams_new();
} else {
stage.displayState=StageDisplayState.NORMAL;
setParams_start();
}
}
private function mute_toogle(event:Event):void{
if(m==true){
//No sounds
sound.volume=0;
stream.soundTransform=sound;
m=false;
removeChild(volume_);
addChild(mute);
} else {
//Play sounds
sound.volume=1;
stream.soundTransform=sound;
m=true;
removeChild(mute);
addChild(volume_);
}
}
private function play_toogle(event:Event):void{
stream.togglePause();
if(play__){
removeChild(pause_);
addChild(play_);
play__=false;
timer_.stop();
} else {
timer_.start();
removeChild(play_);
addChild(pause_);
play__=true;
}
}
private function goto(event:Event):void{
var onePixOnOneSec=duration/timenow.width;
var goto_=Math.round(onePixOnOneSec * (this.mouseX-timenow.x));
stream.seek(goto_);
timenow_i.width=this.mouseX-timenow.x;
trace(duration);
if(goto_<60){
min=0;
sec=String(Math.floor(goto_));
} else if (goto_>=60){
var now=goto_;
var newnow=String(now/60);
var split=newnow.split(".");
min=split[0];
sec=Math.floor(now-min*60);
}
tf.text=min+":"+sec;
}
private function fs_toggle(event:FullScreenEvent):void{
if (!event.fullScreen) {
setParams_start();
}
}
public function timer() {
timer_.addEventListener("timer", timer_event);
timer_.start();
}
public function timer_event(event:TimerEvent):void {
var goto_=stream.time;
if(goto_<60){
min=0;
sec=String(Math.floor(goto_));
} else if (goto_>=60){
var now=goto_;
var newnow=String(now/60);
var split=newnow.split(".");
min=split[0];
sec=Math.floor(now-min*60);
}
tf.text=min+":"+sec;
}
}
}
class CustomClient {
public function onMetaData(info:Object):void {
trace("metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate);
}
public function onCuePoint(info:Object):void {
trace("cuepoint: time=" + info.time + " name=" + info.name + " type=" + info.type);
}
}
Создадим новый класс:
package {
import flash.display.Sprite;
public class VideoPlayerClass extends Sprite {
public function VideoPlayerClass() {
}
}
}
Подключим нужные для дальнейшей работы классы:
import flash.display.Sprite;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.events.FullScreenEvent;
import flash.media.Video;
import flash.media.SoundTransform;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.Event;
import flash.display.MovieClip;
import flash.display.SimpleButton;
import flash.system.*;
import flash.display.*;
import flash.text.TextField;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
Создадим переменные:
private var videoURL:String = stage.loaderInfo.parameters['file']; //Получаем файл для воспроизведения
private var autoplay:String = stage.loaderInfo.parameters['autoplay']; // Узнаём, нужно ли сразу запускать ролик или нет
private var width_player:String="720"; //Задаём ширину и высоту плеера
private var height_player:String="480";
private var connection:NetConnection;//Переменные для работы видео
private var stream:NetStream;
private var video:Video = new Video();
private var cbar:MovieClip = new c_bar();
private var client:Object = new Object();
private var duration:int;
//Кнопки и прочие элементы
private var fs:SimpleButton = new fs_btn();
private var volume_:SimpleButton = new v();
private var mute:SimpleButton = new vm();
private var sound:SoundTransform=new SoundTransform();
private var play_:SimpleButton = new play_btn();
private var pause_:SimpleButton = new pause_btn();
private var timenow:SimpleButton = new time_now();
private var timenow_i:SimpleButton = new time_now_i();
private var tf:TextField = new TextField();
//Второстепенные переменные
private var clw, clh, w, h, sec, newstatic;
private var m:Boolean = true;
private var hd_bool:Boolean = false;
private var play__:Boolean = true;
//Переменные для отсчёта времени
private var time="0";
private var min="0";
//Таймер
private var timer_:Timer = new Timer(1000);
В функцию VideoPlayerClass пишем следующий код:
public function VideoPlayerClass() {
connection = new NetConnection(); //Создаём подключение
connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);//Получения статуса подключения
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);//Ошибка безопасности
connection.connect(null);
}
Следующие две функции, эти статус установки подключения и отлавливание ошибки безопасности:
private function netStatusHandler(event:NetStatusEvent):void {
switch (event.info.code) {
case "NetConnection.Connect.Success": // Если успешно
connectStream(); //Выполняем следующую функцию
break;
case "NetStream.Play.StreamNotFound": // Если ошибка
trace("Stream not found: " + videoURL); // Выводим её
break;
}
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event); // Выводим ошибку
}
Следующая функция будет выполняться если ошибок не было. В этой функции мы будем загружать сам видео файл, добавлять элементы управления, прикреплять к ним события:
private function connectStream():void {
stream=new NetStream(connection);
stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
//stream.client = new CustomClient();
stream.play(videoURL);
addChild(video); // Загружаем файл и добавляем его на сцену
video.width=this.stage.stageWidth; // Задаём ширину и высоту проигрывателю
video.height=this.stage.stageHeight;
client.onMetaData = function(metadata:Object):void {
duration=metadata.duration; // Получаем полную длину файла в секундах
};
stream.client = client;
addChild(cbar); // Добавляем элементы управления н асцену
addChild(fs);
addChild(volume_);
addChild(timenow);
addChild(timenow_i);
addChild(tf);
timer(); // Запускаем таймер
if(autoplay=='no'){ // Если не задано воспроизведение по умолчанию, то ролик не воспроизводиться
stream.togglePause();
play__=false;
addChild(play_);
} else { //Если же нужно воспроизводить - воспроизводим
play__=true;
addChild(pause_);
timer_.start();
}
setParams_start(); // Вызываем функцию, которая задаёт стандартные атрибуты элементам управления
tf.textColor=0xFFFFFF; // Базовые настройки текстового поля с временем
tf.text="0:0";
tf.width=38;
fs.addEventListener(MouseEvent.CLICK, fs_toogle); //Добавляем события на нужные элементы управления
volume_.addEventListener(MouseEvent.CLICK, mute_toggle);
mute.addEventListener(MouseEvent.CLICK, mute_toggle);
play_.addEventListener(MouseEvent.CLICK, play_toggle);
pause_.addEventListener(MouseEvent.CLICK, play_toggle);
timenow.addEventListener(MouseEvent.CLICK, goto);
timenow_i.addEventListener(MouseEvent.CLICK, goto);
stage.addEventListener(FullScreenEvent.FULL_SCREEN, fs_toggle);
}
Далее две функции: одна задаёт стандартные атрибуты, вторая — новые(которые будут применены при полноэкранном):
private function setParams_start(){
w=width_player;
h=height_player;
clw=(w-video.width)/2;
clh=(h-video.height)/2;
cbar.x=110;
cbar.y=407;
play_.x=127;
play_.y=422;
pause_.x=127;
pause_.y=422;
fs.y=422;
fs.x=573;
volume_.x=172;
volume_.y=425;
mute.x=172;
mute.y=425;
lg.x=5;
lg.y=5;
timenow.y=427;
timenow.x=240;
timenow_i.y=427;
timenow_i.x=240;
timenow_i.width=0;
tf.x=200;
tf.y=423;
//Video
video.x=0;
video.y=0;
video.width=w;
video.height=h;
}
private function setParams_new(){
w=this.stage.stageWidth;
h=this.stage.stageHeight;
clw=(w-video.width)/2;
clh=(h-video.height)/2;
newstatic=-clh+h;
cbar.y=newstatic-100;
play_.y=newstatic-85;
pause_.y=newstatic-85;
mute.y=newstatic-85;
volume_.y=newstatic-85;
fs.y=newstatic-88;
tf.y=newstatic-85;
timenow.y=newstatic-81;
timenow_i.y=newstatic-81;
//Video
video.x=-clw;
video.y=-clh;
video.width=w;
video.height=h;
}
В этих функциях нет ничего сложного, поэтому их комментировать не буду.
Далее я писал переключать в полноэкранный режим и выход из него:
private function fs_toggle(event:Event):void{
if(stage.displayState==StageDisplayState.NORMAL){// Если сейчас нормальный режим, то переходим в полноэкранный
stage.displayState=StageDisplayState.FULL_SCREEN;
stage.scaleMode=StageScaleMode.NO_SCALE;
setParams_new(); // Задаём новые атрибуы
} else { // И наоборот
stage.displayState=StageDisplayState.NORMAL;
setParams_start(); // Задаём старые атрибуты
}
}
Следующее — включение и выключение звука:
private function mute_toggle(event:Event):void{
if(m==true){ // если нужно сделать беззвучный режим
//No sounds
sound.volume=0; // Убираем звук
stream.soundTransform=sound; // Применяем к видео
m=false;
removeChild(volume_); // Меням кнопки
addChild(mute);
} else {
//Play sounds
sound.volume=1; // Так же само как и несколько строчек выше
stream.soundTransform=sound;
m=true;
removeChild(mute);
addChild(volume_);
}
}
Далее одно из самых важных — остановка на паузу и продолжение видео:
private function play_toggle(event:Event):void{
stream.togglePause(); // Ставим на паузу и воспроизводим
if(play__){ // Если воспроизводиться ролик
removeChild(pause_); // Меняем кнопки
addChild(play_);
play__=false; //Меняем значение переменной
timer_.stop(); // Останавливаем таймер
} else {
timer_.start(); // Запускаем дальше таймер
removeChild(play_); // Аналогично вышенаписанному коду
addChild(pause_);
play__=true;
}
}
Второе по важности — перемотка. Её реализация такая же как и в первой части, но некоторые переменные были заменены:
private function goto(event:Event):void{
var onePixOnOneSec=duration/timenow.width;
var goto_=Math.round(onePixOnOneSec * (this.mouseX-timenow.x));
stream.seek(goto_);
timenow_i.width=this.mouseX-timenow.x;
trace(duration);
if(goto_<60){
min=0;
sec=String(Math.floor(goto_));
} else if (goto_>=60){
var now=goto_;
var newnow=String(now/60);
var split=newnow.split(".");
min=split[0];
sec=Math.floor(now-min*60);
}
tf.text=min+":"+sec;
}
Посмотреть комментарии вы можете в первой части.
И в конце три небольшие функции:
private function fs_toggle(event:FullScreenEvent):void{
if (!event.fullScreen) { // Отлавливаем выход из полноэкранного режима кнопкой "Esc"
setParams_start(); // Применяем начальные атрибуты
}
}
public function timer() {
timer_.addEventListener("timer", timer_event); // Добавляем таймеру обработчик событий и запускаем его
timer_.start();
}
public function timer_event(event:TimerEvent):void { // Обработчик событий для таймера
var goto_=stream.time;
if(goto_<60){
min=0;
sec=String(Math.floor(goto_));
} else if (goto_>=60){
var now=goto_;
var newnow=String(now/60);
var split=newnow.split(".");
min=split[0];
sec=Math.floor(now-min*60);
}
tf.text=min+":"+sec;
}
Комментарии к обработчику события для таймера вы сможете увидеть в первой части. Код почти такой же за исключением одной переменной.
Шаг второй — подключение файла и добавление графики
Теперь добавим всю графику. Открываем наш проект который мы создали в самом начале до написания класса. Добавляем элементы на сцену так, как я описывал ранее в первой части(«Шаг 1: Подготовка»).
Что бы подключить файл с классом, нужно в свойствах ролика прописать его. Для этого делаем так как на скриншотах ниже:
В поле «Класс» вводим название нашего класса. В моём случае это VideoPlayerClass. Нажимаем на иконку с карандашом и если откроется Ваш класс, то он успешно подключён к проекту. Если же нет, то убедитесь что вы всё сделали правильно(создание класса, его сохранение, подключение). Далее можно просто запустить ролик с помощью горячих клавиш «Ctrl+Enter». Если не будет предупреждений и будут ваши элементы как показано ниже, то плеер успешно создан:
Шаг 3: подключение на страницу
В первой части было много комментариев в которых говорили что нужно бросать flash и переходить на html5. Я с этим частично согласен, но некоторые вещи лучше делать во flash'e. Что бы было хорошо всем(и людям в ПК и обладателям мобильных устройств) я написал небольшую функцию, которая подключает плеер.
Создадим html документ и подключим к нему jquery, этот файл и скрипт, который я приведу ниже.
Допустим что мы всё подключили и страница выглядит приблизительно так:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
<title>player</title>
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script src="flashplayer_detect.js"></script>
</head>
<body>
</body>
</html>
В примере страницы ниже я скачал файл определяющий наличие flash'a на устройстве и переименовал его в flashplayer_detect.js.
Далее подключаем javascript файл со следующим содержанием:
function insertPlayer(json){
var html5=json.html5;
var autoplay=json.autoplay;
var file=json.file;
var element=json.element;
if(FlashDetect.installed){
var player='<object style="background-color: black;" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0" height="'+json.height+'" width="'+json.width+'">';
player+='<param name="movie" value="'+json.swf+'">';
player+='<param name="quality" value="high">';
player+='<param value="true" name="allowFullScreen">';
player+='<param value="always" name="allowScriptAccess">';
player+='<param value="all" name="AllowNetworking">';
player+='<param name="flashvars" value="width='+json.width+'&height='+json.height+'&autoplay='+json.autoplay+'&file='+json.file+'">';
player+='<embed allownetworking="all" allowfullscreen="true" allowscriptaccess="always" src="'+json.swf+'?width='+json.width+'&height='+json.height+'&autoplay='+json.autoplay+'&file='+json.file+'" quality="high" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" height="'+json.height+'" width="'+json.width+'">';
player+='</object>';
} else {
if(html5){
var player='<video width="'+json.width+'" height="'+json.height+'" controls>';
if(json.html5_files.mp4){
player+='<source src="'+json.html5_files.mp4+'" type="video/mp4" />';
}
if(json.html5_files.webm){
player+='<source src="'+json.html5_files.webm+'" type="video/webm" />';
}
if(json.html5_files.ogg){
player+='<source src="'+json.html5_files.ogg+'" type="video/ogg" />';
}
player+='</video>';
} else {
var player="Для просмотра видео установите Flash Player либо обновите свой браузер";
}
}
document.getElementById(element).innerHTML=player;
}
Код прост, его я не буду комментировать.
На странице в месте где должен быть плеер пишем:
<div id="BLOCK_ID"></div>
и в любое место добавляем JavaScript код:
$(function(){
insertPlayer({
'file': 'file',
'element': 'BLOCK_ID',
'width': 720,
'height': 480,
'swf': 'player.swf',
'autoplay': 'no',
'html5': true,
'html5_files':
{
'mp4': false,
'webm': false,
'ogg': false
}
});
});
Где:
-file — имя файла который будет воспроизводиться
-element — id блока в котором будет плеер(BLOCK_ID)
-ширина и высота
-swf — путь к самому плееру
-autoplay — авто воспроизведение(no — нет, yes — да)
-html5 — наличие html5 версии
-html5_files — файлы для html5 версии(mp4, webm, ogg).
После этого сохраняем страницу и запускаем её. В нужном месте должен появиться плеер.
HTML5 версия плеера стандартная.
Заключение
На этом написание плеера закончилось. Всем спасибо за внимание.
Если у вас есть пожелание, уточнение или советы буду рад их прочитать.
Используемое при написании плеера:
Автор: AlexRudkowskij
А нельзя его сделать полностью невидимым, но всего лишь с двумя функциями – пуск/стоп на изображении и с таймером запуска?