• 718 阅读
  • 1 回复

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

视频在线上传+队列转换FLV+水印+捉图+修复+获时+转3GP(API语言不限,开视频站必备!)
本主题由 张小鱼 于 2010/10/12 18:25:00 执行 移动主题 [查看记录]
如果不考虑安全因素(指任何人都可连接FluorineFx进行视频录制,而不需要登录认证),其实服务端不用写一行代码,仅需要在apps目录下建一个子目录当作应用,以及在services-config.xml中配置一下rtmp的Channel即可

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


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

本地下载:
VideoRecording.rar (您是游客您没有权限下载)
本帖最后由 张小鱼 于 2010-10-12 18:24 编辑
小鱼的淘宝店铺-多多支持哇

代码

视频在线上传+队列转换FLV+水印+捉图+修复+获时+转3GP(API语言不限,开视频站必备!)

代码 复制 - 运行

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; 
  } 

 } 
} 

小鱼的淘宝店铺-多多支持哇