Знаниями нужно делится...

Потоковое видео as3 «красивым способом»

Назад к списку | Просмотров: 2996

В одной из предыдущих статей я писал как сделать потоковое видео применяя технологию flash. В основе способа лежала идея передачи байт массива через сокетное соединение. Надо сказать с учетом производительности as3 идея не самая удачная и интересна лишь на уровне эксперимента. Возникает идея сделать сервер на более быстром языке, например C++ или JAVA. Кстати сказать уже есть и готовые варианты, например сервер red5(о нем в другой статье (кстати, код приведенный ниже будет подходить для разных мультимедийных серверов)).

Но если вы не желаете изобретать велосипед, то корпорация Adobe предлагает использовать свой фирменный сервер для передачи потокового видео. Сервер работает быстро и достаточно качественно. Но есть одно «но» - это цена. Но и тут есть небольшая лазейка. Adobe любезно предоставляет свой сервер потокового видео для тестирования. Поэтому если ваша цель учеба или очень небольшой проект, то вам сюда (https://www.adobe.com/cfusion/entitlement/index.cfm?e=cirrus). Создайте аккаунт на сайте и получите ключ разработчика, который нам пригодится далее.

Ядром всей системы будут являться два класса NetConnection и NetStream, первый устанавливает соединение сервером, второй осуществляет управление потоком мультимедиа данных (звук, видео).

Привожу реализацию обертки:

package  
{
	import flash.net.NetConnection;
	import flash.events.NetStatusEvent;
	import flash.net.NetStream;
	import flash.net.GroupSpecifier; 
	import utils.MD5;
	import flash.events.EventDispatcher;
	import flash.events.Event;
	
	/**
	 * ...
	 * @author Vench
	 * Получения трансляции
	 */
	public class VideoStramOutIn extends EventDispatcher
	{
		/**
		 * Событие указывает на готовность объекта потока к передачи или чтению данных
		 */
		public static const EVT_NET_STREAM_COMPL:String = "evtNetStreamCompl";
		
		/**
		 * Предназначение объекта для передачи данных
		 */
		public static const TYPE_OUT:uint = 1;
		/**
		 * Предназначение объекта для получения данных
		 */
		public static const TYPE_IN:uint = 2;
		
		/**
		 * Адрес сервера
		 * 
		 */
		private const SERVER:String = 'XXXX';
		/**
		 * Ваш ключ разработчика
		 */
        private const DEVKEY:String = 'XXXX';
		/**
		 * Название потока
		 * Простая строка
		 */
		private var nameStream:String;
		/**
		 * Уникальный индикатор потока в вашем сервисе
		 */
		private var sidStraem:String;
		
		private var netConnection:NetConnection;
		private var netStream:NetStream;
		private var type:uint;
		
		public function VideoStramOutIn(type:uint ) 
		{ 
			this.type = type;
		}
		
		/**
		 * Получить название потока
		 * @return
		 */
		public function getNameStream():String {
			return nameStream;
		}
		
		/**
		 * Получить идентификатор потока
		 * @return
		 */
		public function getSidStraem():String {
			return sidStraem;
		}
		
		/**
		 * Получить ссылку на объект потока
		 * @return
		 */
		public function getNetStream():NetStream {
			return netStream;
		}
		
		/**
		 * Закрытие текущего потока
		 */
		public function closeNetConnection():void {
			
			if (netStream != null) {
				try {
					netStream.close();
				} catch(e1:Error){}
				netStream = null;
			}
			
			if (netConnection != null) {
				try {
					netConnection.close();
				} catch(e2:Error){}
				netConnection = null;
			}
		}
		
		/**
		 * Начало трансляции 
		 * Попытка открытия
		 * @param	nameStream
		 * @param	sidStraem
		 */
		public function openStream(nameStream:String, sidStraem:String) :void {
			this.nameStream = nameStream;
			this.sidStraem = sidStraem;
			
			closeNetConnection();
			netConnection = new NetConnection();
			netConnection.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
            netConnection.connect(SERVER);
		}
		
		/**
		 * События открытия соединения NetConnection | NetStream
		 * @param	event
		 */
        private function netStatus(event:NetStatusEvent) : void
        { 
            switch(event.info.code)
            {
                case "NetConnection.Connect.Success":
					setupStream();
                break;                 
                case "NetStream.Connect.Success": 
                    netStreamComplite();
                break; 
            }
        }
		
		/**
		 * Установка потока
		 */
		private function setupStream():void {
			if (type == TYPE_OUT) {
				sidStraem = MD5.encrypt(nameStream);
			}
			
			//
			var groupspec:GroupSpecifier = new GroupSpecifier(sidStraem);
            groupspec.serverChannelEnabled = true;
            groupspec.multicastEnabled = true;
			
			netStream = new NetStream(netConnection, groupspec.groupspecWithAuthorizations());
            netStream.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
		}
		
		/**
		 * Готов к вещанию, «рассылаем» событие EVT_NET_STREAM_COMPL
		 */
		private function netStreamComplite():void {
			dispatchEvent(new Event(EVT_NET_STREAM_COMPL));			
		}
	}

}

Далее приведу простой пример открытие потока и получения данных:

package  
{
	import flash.display.Sprite;
	import models.VideoStramOutIn;
	import flash.media.*;
	import flash.events.*;
	
	/** 
	 * ...
	 * @author Vench
	 */
	public class Test extends Sprite 
	{
		/**
		 * Поток вещания
		 */
		private var videoStramOut:VideoStramOutIn;
		/**
		 * Поток получения данных
		 */
		private var  videoStramIn:VideoStramOutIn;
		/**
		 * Видео отображаемое при отправке
		 */
		private var videoOut:Video;
		/**
		 * Видео отображаемое при получении
		 */
		private var videoIn:Video;
		
		public function Test() 
		{
			super();
			if (Camera.getCamera() == null) {
				trace("Not detect camera");
				return;
			}
			 
			videoOut = new Video(320, 240);
            addChild(videoOut); 
			
			videoIn = new Video(320, 240);
			videoIn.x = 340;
            addChild(videoIn); 
			
			var sessionName:String = "SomeName_"+Math.random();
			videoStramOut = new VideoStramOutIn(VideoStramOutIn.TYPE_OUT);
			videoStramOut.addEventListener(VideoStramOutIn.EVT_NET_STREAM_COMPL, videoStramOutOpen);
			videoStramOut.openStream(sessionName, null);
		}
		
		/**
		 * Поток вещания готов, начинаем трансляцию
		 * @param	e
		 */
		public function videoStramOutOpen(e:Event):void {
			videoStramOut.removeEventListener(VideoStramOutIn.EVT_NET_STREAM_COMPL, videoStramOutOpen);
			
			var cam:Camera = Camera.getCamera(); 
            cam.setMode(320, 240, 24);
            videoOut.attachCamera(cam);
			//транслируем аудио
            videoStramOut.getNetStream().attachAudio(Microphone.getMicrophone());
			//транслируем видео
            videoStramOut.getNetStream().attachCamera(cam);
			//публикуем
            videoStramOut.getNetStream().publish(videoStramOut.getNameStream());
			
			
			//теперь можно открыть поток на получения данных, получать мы будем разумеется свой  поток (пока).
			videoStramIn = new VideoStramOutIn(VideoStramOutIn.TYPE_IN);
			videoStramIn.addEventListener(VideoStramOutIn.EVT_NET_STREAM_COMPL, videoStramInOpen);
			//Ставим название и идентификатор нашего, открытого потока
			videoStramIn.openStream(videoStramOut.getNameStream(), videoStramOut.getSidStraem());
		}	
		
		/**
		 * Поток приема готов 
		 * @param	e
		 */
		public function videoStramInOpen(e:Event):void {
			videoIn.attachNetStream(videoStramIn.getNetStream());
			videoStramIn.getNetStream().receiveAudio(true);
			//Начинаем проигрывание потока
			videoStramIn.getNetStream().play(videoStramOut.getNameStream());  
		}
	}

}

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

Исходник


автор admin дата 01/08/2013


Оставить комментарий
3 + 3 =