FluorineFx:视频录制及回放(Flash/AS3环境)

如果不考虑安全因素(指任何人都可连接FluorineFx进行视频录制,而不需要登录认证),其实服务端不用写一行代码,仅需要在apps目录下建一个子目录当作应用,以及在services-config.xml中配置一下rtmp的Channel即可

 

下面这段flash客户端的as3代码,是从FluorineFx官方的Flash AS2示例修改而来的(当然:只一个示例,细节还有很多可优化的地方)

package 

{

	import fl.controls.Button;

	import fl.controls.Label;

	import fl.controls.TextInput;

	import fl.controls.CheckBox;

	import flash.display.Sprite;

	import flash.utils.Timer;

	import flash.events.ActivityEvent;

	import flash.events.TimerEvent;

	import flash.events.MouseEvent;

	import flash.events.NetStatusEvent;

	import flash.events.StatusEvent;

	import flash.media.Camera;

	import flash.media.Microphone;

	import flash.net.NetConnection;

	import flash.net.NetStream;

	import flash.media.Video;





	public class VideoRecord extends Sprite

	{

		private var _btnRecord:Button;

		private var _btnPlay:Button;

		private var _btnConnect:Button;

		private var _txtVideoFileName:TextInput;

		private var _chkAppend:CheckBox;

		private var _txtServerUrl:TextInput;

		private var _lblResult:Label;

		private var _nc:NetConnection = null;

		private var _nsPublish:NetStream = null;

		private var _nsPlay:NetStream = null;

		private var _ncPlay:NetConnection = null;

		private var _camera:Camera;

		private var _microphone:Microphone;

		private var _videoRecord:Video;

		private var _videoPlay:Video;

		private var _videoIsWorked = false;

		private var _timer:Timer;





		public function VideoRecord()

		{

			init();

		}



		private function init():void

		{



			this._btnRecord = this.btnRecord;

			this._txtVideoFileName = this.videoFileName;

			this._chkAppend = this.chk1;

			this._chkAppend.label = "追加";

			this._btnPlay = btnPlay;

			this._btnConnect = btnConnect;

			this._txtServerUrl = this.txtServerUrl;

			this._lblResult = lblResult;

			this._btnRecord.enabled = false;

			this._btnRecord.label = "录制";

			this._txtVideoFileName.enabled = false;

			this._chkAppend.enabled = false;

			this._btnPlay.enabled = false;

			this._btnPlay.label = "播放";

			this._btnConnect.label = "连接";

			this._txtServerUrl.text = "rtmp://localhost/VideoRecording";

			this._videoRecord = videoRecord;

			this._videoPlay = videoPlay;

			this._btnConnect.addEventListener(MouseEvent.CLICK, doConnect);

		}



		//连接服务器;

		private function doConnect(e:MouseEvent):void

		{



			if (this._nc == null)

			{

				this._nc = new NetConnection  ;

				this._nc.addEventListener(NetStatusEvent.NET_STATUS, ncNetStatus);

			}

			this._nc.connect(this._txtServerUrl.text);

			this._lblResult.text = "服务器连接中...";

		}



		//关闭与服务器的连接

		private function doCloseConn(e:MouseEvent):void

		{

			if (this._nc != null)

			{

				if (this._nsPublish != null)

				{

					this._nsPublish.attachCamera(null);

				}

				this._videoRecord.attachCamera(null);

				this._videoRecord.attachNetStream(null);

				this._videoRecord.clear();

				this._nc.close();				

				this._btnConnect.label = "连接";

				this._btnRecord.enabled = false;

				this._txtVideoFileName.enabled = false;

				this._chkAppend.enabled = false;

				this._videoRecord.clear();



				this._btnConnect.removeEventListener(MouseEvent.CLICK,doCloseConn);

				this._btnConnect.addEventListener(MouseEvent.CLICK,doConnect );



				stopPublish();

			}

		}



		//检测conn对象的状态变化

		private function ncNetStatus(e:NetStatusEvent):void

		{

			//trace(e.info.code);

			if (e.info.code == "NetConnection.Connect.Success")

			{

				//连接成功

				this._lblResult.text = "服务器已经连接!";

				this._btnConnect.label = "断开";

				this._btnConnect.removeEventListener(MouseEvent.CLICK,doConnect);

				this._btnConnect.addEventListener(MouseEvent.CLICK, doCloseConn);

				this._camera = Camera.getCamera();

				if (_camera == null)

				{

					this._lblResult.text = "未安装摄像头!";

					return;

				}



				_camera.addEventListener(StatusEvent.STATUS, cameraStatusHandler);

				_camera.addEventListener(ActivityEvent.ACTIVITY, cameraActivityHandler);

				this._videoRecord.attachCamera(this._camera);



				//点击"断开"后后,又重新点击"连接";

				if (_videoIsWorked)

				{

					//恢复控件的可用性;

					this._txtVideoFileName.enabled = true;

					this._chkAppend.enabled = true;

					this._btnRecord.enabled = true;



					if (this._txtVideoFileName.text == "")

					{

						//this._txtVideoFileName.text = Math.round(Math.random() * 10000).toString();

						this._txtVideoFileName.text = "demo";

					}

					this._btnRecord.label = "录制";

					this._btnRecord.removeEventListener(MouseEvent.CLICK,prepareStopRecord);

					this._btnRecord.addEventListener(MouseEvent.CLICK, startRecord);

				}

			}

			else if (e.info.code == "NetConnection.Connect.Closed")

			{

				this._lblResult.text = "服务器连接已关闭!";

			}

			else

			{

				this._lblResult.text = "错误-服务器连接失败!";

			}

		}



		//用户选择是否摄像头时触发

		function cameraStatusHandler(e:StatusEvent):void

		{

			//trace(e);

			if (e.code == "Camera.Muted")

			{

				this._lblResult.text = "您不允许使用摄像头!";

			}

			else if (e.code == "Camera.Unmuted")

			{

				this._lblResult.text = "摄像头视频获取中...";

				_timer = new Timer(100,20);//每隔100ms检测摄像头状态,一共检测20次  

				cameraActivityHandler(null);

			}

		}



		//摄像头有活动时被触发  

		private function cameraActivityHandler(e:ActivityEvent):void

		{

			//trace("cameraActivityHandler被调用!");

			if (! _videoIsWorked)

			{

				if (_timer != null)

				{

					_timer.addEventListener(TimerEvent.TIMER, checkCamera);

					_timer.addEventListener(TimerEvent.TIMER_COMPLETE, checkCameraComplete);

					_timer.start();

					//trace("_timer已经启动!");

				}

			}

		}





		//timer回调函数,用于检测摄像头设备是否正确

		function checkCamera(e:TimerEvent):void

		{

			this._lblResult.text = "摄像头视频获取中...";

			if (this._camera.currentFPS > 0)

			{

				_timer.stop();

				_videoIsWorked = true;

				this._lblResult.text = "摄像头工作正常";



				//恢复控件的可用性;

				this._txtVideoFileName.enabled = true;

				this._chkAppend.enabled = true;

				this._btnRecord.enabled = true;



				if (this._txtVideoFileName.text == "")

				{

					//this._txtVideoFileName.text = Math.round(Math.random() * 10000).toString();

					this._txtVideoFileName.text = "demo";

				}

				this._btnRecord.addEventListener(MouseEvent.CLICK, startRecord);

			}

		}



		//开始录制

		private function startRecord(e:MouseEvent):void

		{

			//trace("开始录制,_nsPublish=",_nsPublish);

			if (this._nsPublish == null)

			{

				//trace("重新创建ns");

				_nsPublish = new NetStream(this._nc);

			}

			this._nsPublish.attachCamera(this._camera);

			this._nsPublish.publish(this._txtVideoFileName.text, this._chkAppend.selected ? "append" : "record");

			this._nsPublish.addEventListener(NetStatusEvent.NET_STATUS, nsPublishNetStatus);

			//缓冲20秒;

			this._nsPublish.bufferTime = 20;







		}



		private function nsPublishNetStatus(e:NetStatusEvent):void

		{

			//trace(e.info.code);

			if (e.info.code == "NetStream.Play.StreamNotFound" || e.info.code == "NetStream.Play.Failed" || e.info.code == "NetStream.Publish.BadName")

			{

				this._lblResult.text = "推送失败,原因:" + e.info.code;



			}

			else if (e.info.code == "NetStream.Record.Start" || e.info.code == "NetStream.Buffer.Empty")

			{

				//录制开始

				this._btnRecord.removeEventListener(MouseEvent.CLICK, startRecord);

				this._btnRecord.addEventListener(MouseEvent.CLICK, prepareStopRecord);

				this._lblResult.text = "正在录制...";

				this._btnRecord.label = "停止";



				//录制时,禁止回放

				this._btnPlay.enabled = false;

				//this._btnPlay.label = "播放";

				this._btnPlay.removeEventListener(MouseEvent.CLICK,this.doStopPlay);

				this._btnPlay.addEventListener(MouseEvent.CLICK,this.doPlay);

			}

		}



		private function nsPlayNetStatus(e:NetStatusEvent):void

		{

			//trace(e.info.code);

			//失败

			if (e.info.code == "NetStream.Play.StreamNotFound" || e.info.code == "NetStream.Play.Failed")

			{



			}

			else if (e.info.code=="NetStream.Play.Start")

			{



			}

		}



		private function doStopPlay(e:MouseEvent):void

		{

			if (this._nsPlay != null)

			{

				this._videoPlay.attachNetStream(null);				

				this._videoPlay.clear();

				this._ncPlay.close();

				this._ncPlay = null;

				this._nsPlay.close();

				this._nsPlay = null;				

				

				this._btnPlay.label = "播放";

				this._btnPlay.removeEventListener(MouseEvent.CLICK,doStopPlay);

				this._btnPlay.addEventListener(MouseEvent.CLICK,doPlay);

				//trace("已经停止!");

			}



		}





		function doPlay(e:MouseEvent):void

		{

			if (this._ncPlay == null)

			{

				this._ncPlay = new NetConnection();

				this._ncPlay.addEventListener(NetStatusEvent.NET_STATUS,ncPlayNetStatus);

				this._ncPlay.connect(this._txtServerUrl.text);

			}

		}





		private function ncPlayNetStatus(e:NetStatusEvent):void

		{

			if (e.info.code == "NetConnection.Connect.Success")

			{

				if (this._nsPlay == null)

				{

					//trace("_nsPlay已经创建!");

					this._nsPlay = new NetStream(this._ncPlay);

					this._nsPlay.addEventListener(NetStatusEvent.NET_STATUS, nsPlayNetStatus);

					

					var _client:Object = new Object();

					_client.onMetaData = nsPlayOnMetaData;

					_client.onPlayStatus = nsPlayOnPlayStatus;

					this._nsPlay.client = _client;

					this._nsPlay.bufferTime = 5;



					this._nsPlay.play(this._txtVideoFileName.text);

					this._videoPlay.attachNetStream(this._nsPlay);

					this._btnPlay.label = "停止";

					this._btnPlay.removeEventListener(MouseEvent.CLICK,doPlay);

					this._btnPlay.addEventListener(MouseEvent.CLICK,doStopPlay);

				}



			}

		}



		private function nsPlayOnMetaData(e:Object):void

		{

			trace("onmetaData:" + e.duration);

		}



		private function nsPlayOnPlayStatus(e:Object):void

		{

			trace("onPlayStatus:" + e.code);



			if (e.code == "NetStream.Play.Complete")

			{

				trace("播放已经停止");

				this._videoPlay.attachNetStream(null);

				this._videoPlay.clear();

				this._btnPlay.label = "播放";

				this._btnPlay.removeEventListener(MouseEvent.CLICK,doStopPlay);

				this._btnPlay.addEventListener(MouseEvent.CLICK,doPlay);

				

				this._ncPlay.close();

				this._ncPlay = null;

				this._nsPlay.close();

				this._nsPlay = null;

			}

		}



		//准备停止录制

		private function prepareStopRecord(e:MouseEvent)

		{



			this._nsPublish.attachCamera(null);

			var _bufferLength = this._nsPublish.bufferLength;

			//必须等当前缓冲区中的数据全部发送完以后再正式停止

			if (_bufferLength > 0)

			{

				this._btnRecord.label = "稍等...";

				this._lblResult.text = "正在保存,请稍候...";

				//每0.1秒检查一次

				_timer = new Timer(100);

				_timer.addEventListener(TimerEvent.TIMER, doWait);

				_timer.start();

			}

			else

			{

				//trace("停止!");

				stopPublish();

			}

		}



		//停止发布(录制)

		private function stopPublish():void

		{

			if (this._nsPublish != null)

			{

				this._nsPublish.removeEventListener(NetStatusEvent.NET_STATUS, nsPublishNetStatus);

				this._nsPublish.close();

				this._nsPublish = null;

			}

			this._btnRecord.label = "录制";

			this._lblResult.text = "";

			this._btnRecord.removeEventListener(MouseEvent.CLICK, prepareStopRecord);

			this._btnRecord.addEventListener(MouseEvent.CLICK, startRecord);





			//允许回放;

			this._btnPlay.enabled = true;

			this._btnPlay.label = "播放";

			this._btnPlay.removeEventListener(MouseEvent.CLICK,doStopPlay);

			this._btnPlay.addEventListener(MouseEvent.CLICK,doPlay);

		}







		//等待录制视频缓冲区的数据全部保存到服务器上;

		private function doWait(e:TimerEvent)

		{

			var _bufferLength = this._nsPublish.bufferLength;

			if (_bufferLength <= 0)

			{

				_timer.removeEventListener(TimerEvent.TIMER, doWait);

				_timer.stop();

				_timer = null;

				stopPublish();

			}

		}



		function checkCameraComplete(e:TimerEvent):void

		{

			this._lblResult.text = "设备无法使用(有可能被占用)";

			_timer.removeEventListener(TimerEvent.TIMER, checkCamera);

			_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, checkCameraComplete);

			_timer = null;

		}



	}

}

 

界面:

FluorineFx:视频录制及回放(Flash/AS3环境)

 

示例源代码下载:http://cid-2959920b8267aaca.office.live.com/self.aspx/Flash/VideoRecording.rar

你可能感兴趣的:(Flash)