2012-12-19 2 views
4

Windows 8 시스템에 RED5 1.0 Final을 설정했는데 제대로 작동하려면 녹음을 시도하고 있습니다. 내가 읽은 튜토리얼은 클라이언트 쪽 (플래시)의 데이터를 버퍼링 한 다음 버퍼가 비어 있으면 연결을 종료한다고 말합니다.RED5 1.0 녹음 문제 NetStream.Buffer.Empty

내가 겪고있는 문제는 녹음을 시작할 때 버퍼가 비어 있다고 즉시보고한다는 것입니다 (NetStream.Buffer.Empty). 버퍼가 실제로 채워지는 곳을 한 두 번 작동 시켰지만 어떤 이유로 그 방법으로 작동을 멈췄습니다.

서버 측의 파일이 계속 커지기 때문에 클라이언트가 넷 스트림에서 카메라를 분리 한 후에도 서버에 데이터를 보내고있는 것을 볼 수 있습니다. 내 솔루션은 연결을 닫기 전에 녹음이 중지 된 후 60 초를 기다리는 것입니다.

보낼 패킷이 더 이상 없을 때는 파일이 mystream.ser에서 mystream.flv로 전환되고 크기가 커지는 것을 서버 측에서 확인합니다. 나는이 이벤트가 일어날 때까지 기다린 다음 클라이언트에게 스트림을 닫을 수 있음을 알리는 코드를 서버 측에 작성하려고 생각했다.

이것은 내가 뭔가 잘못하고있는 것처럼 행동 스크립트에 첫 발을 내디뎠다. 저에게 알려주세요.

편집 다음은 클라이언트 코드를

<?xml version="1.0" encoding="utf-8"?> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
       xmlns:s="library://ns.adobe.com/flex/spark" 
       xmlns:mx="library://ns.adobe.com/flex/mx" 
       xmlns:ns1="*" 
       minWidth="955" minHeight="600" applicationComplete="init()" > 

    <fx:Script> 
     <![CDATA[ 

      import flash.display.DisplayObject; 
      import flash.display.Sprite; 
      import flash.events.NetStatusEvent; 
      import flash.media.Camera; 
      import flash.media.H264Level; 
      import flash.media.H264Profile; 
      import flash.media.H264VideoStreamSettings; 
      import flash.media.Video; 
      import flash.net.NetConnection; 
      import flash.net.NetStream; 


      var cam:Camera = Camera.getCamera(); 
      var mic:Microphone = Microphone.getMicrophone(); 
      var nc:NetConnection = new NetConnection(); 
      var activeStream:NetStream; 
      private var bufferCheckTimer:Timer; 
      var recordHalted:Boolean = false; 


      protected function init(): void{ 
       recordButton.enabled = false; 
       stopButton.enabled = false; 
       nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);    
       nc.connect("rtmp://localhost/oflaDemo"); 
       nc.client = this; 
      } 

      public function onMetaData(info:Object):void { 

       trace("playback called onMetaData");   
      } 

      public function onBWDone(... rest) : void { 
       // have to have this for an RTMP connection 
       trace('onBWDone'); 
      } 

      public function onBWCheck(... rest) : uint { 
       trace('onBWCheck'); 
       //have to return something, so returning anything :) 
       return 0; 
      } 


      protected function onNetStatus(event:NetStatusEvent):void{ 
       trace(event.info.code); 
       if(nc.connected) 
       { 
        SetupCameraAndMic(); 
        recordButton.enabled = true; 
        stopButton.enabled = true; 
       }   
      } 

      protected function SetupCameraAndMic(): void{ 
       activeStream = new NetStream(nc); 
       activeStream.bufferTime = 60; 
       activeStream.client = this; 
       activeStream.addEventListener(NetStatusEvent.NET_STATUS, handleStreamStatus,false,0,true); 


       var h264Settings:H264VideoStreamSettings = new H264VideoStreamSettings(); 
       h264Settings.setProfileLevel(H264Profile.BASELINE, H264Level.LEVEL_2); 
       activeStream.videoStreamSettings = h264Settings; 

       cam.addEventListener(StatusEvent.STATUS, handleCameraStatus, false, 0, true); 
       mic.addEventListener(StatusEvent.STATUS, handleMicrophoneStatus, false, 0, true); 

       cam.setMode(320,240, 15); 
       cam.setQuality(0, 80); 
       cam.setKeyFrameInterval(7); 

       mic.rate = 44; 
       mic.gain = 75; 
       mic.setSilenceLevel(0); 
       mic.setUseEchoSuppression(true); 



       activeStream.attachCamera(cam); 
       activeStream.attachAudio(mic); 
       videoContainer.attachCamera(cam); 






      } 

      private function handleCameraStatus(e:StatusEvent):void { 
       trace("handleCameraStatus - " + e.code); 
       switch(e.code) { 
        case 'Camera.muted': 
         // Show a message 
         break; 
        case 'Camera.Unmuted':    
         //finishCamAndMicSetup(); 
         break; 
       } 
      } 


      private function handleMicrophoneStatus(e:StatusEvent):void { 
       trace("handleMicrophoneStatus - " + e.code); 
       switch(e.code) { 
        case 'Microphone.Muted': 
         // Show a message 
         break; 
        case 'Microphone.Unmuted':    
         //finishCamAndMicSetup(); 
         break; 
       } 
      } 


      private function handleStreamStatus(e:NetStatusEvent):void { 
       switch(e.info.code) { 
        case 'NetStream.Buffer.Empty': 
         trace("NetStream.Buffer.Empty"); 
         break; 
        case 'NetStream.Buffer.Full': 
         trace("NetStream.Buffer.Full"); 
         break; 
        case 'NetStream.Buffer.Flush': 
         trace("NetStream.Buffer.Flush"); 
         break; 
       } 
      } 

      protected function recordButton_clickHandler(event:MouseEvent):void 
      { 
       if(activeStream == null) 
       { 
        SetupCameraAndMic(); 
       } 
       if(activeStream != null){ 
        var tempDate:Date = new Date(); 
        var uniqueFileName:String = "RecordME_" + String(tempDate.getMinutes()) + String(tempDate.getMilliseconds()); 

        bufferLabel.text = ""+ activeStream.bufferTime; 
        activeStream.publish(uniqueFileName, "record"); 
        bufferCheckTimer = new Timer(100); 
        bufferCheckTimer.addEventListener(TimerEvent.TIMER, handleBufferCheck, false, 0, true); 
        bufferCheckTimer.start(); 

       } 

      } 

      private function handleBufferCheck(e:TimerEvent):void { 
       if(activeStream != null) { 
        trace("Buffer: " + activeStream.bufferLength); 
        statusLabel.text = "Buffer: " + activeStream.bufferLength; 
        if (recordHalted == true) { 
         if (activeStream.bufferLength == 0) { 
          activeStream.close(); 
          activeStream = null; 



          bufferCheckTimer.stop(); 
          bufferCheckTimer.removeEventListener(TimerEvent.TIMER, handleBufferCheck); 
          bufferCheckTimer = null; 

          // OK - playback time 
          //doRecordingPlayback(); 
         } 
        } 


       if (bufferCheckTimer != null) { 
        bufferCheckTimer.reset(); 
        bufferCheckTimer.start(); 
       } 
      } 
      } 

      protected function stopButton_clickHandler(event:MouseEvent):void 
      { 

       activeStream.attachCamera(null); 
       activeStream.attachAudio(null); 
       videoContainer.attachCamera(null);      
       recordHalted = true; 

      } 

     ]]> 
    </fx:Script> 

    <fx:Declarations> 
     <!-- Place non-visual elements (e.g., services, value objects) here --> 
    </fx:Declarations> 
    <mx:VideoDisplay id="videoContainer" x="158" y="53" width="640" height="480" 
        chromeColor="#3C2020" /> 
    <s:Button id="recordButton" x="396" y="546" label="Record" 
       click="recordButton_clickHandler(event)"/> 
    <s:Button id="stopButton" x="491" y="546" label="Stop Recording" 
       click="stopButton_clickHandler(event)"/> 
    <s:Label id="statusLabel" x="158" y="555" width="207"/> 
    <s:Label x="14" y="408" text="Buffer Set to:"/> 
    <s:Label id="bufferLabel" x="91" y="408" text="0"/> 
</s:Application> 

감사

+0

클라이언트 코드를 보지 않고서는 정말 도움이되지 않습니다. 녹음을 시작하거나 시작하기 위해 무엇을하는지보아야합니다. –

+0

클라이언트 코드가 추가되었습니다. –

답변

1

나는이 생각을 RED5 최종 V1.0 릴리스의 버그로 인해 발생합니다. 나는 0.80 버전으로 돌아 왔고 나는 잘 기록 할 수있다.

1

내가 지금 실행중인 RTMP 서버를 필요는 없습니다, 그래서 난 그냥 코드에 표시되는 내용에 주석하고있다.

버퍼링에 대한 조언은 스트림을 게시 (녹음) 할 때 좋은 아이디어가 아닐 수도 있습니다. 아마도 튜토리얼은 퍼블리싱이 아니라 기존 스트림을 구독하는 것이 었습니다.이 경우 버퍼링은 좋은 아이디어입니다.

bufferTime을 60 초로 설정합니다. docs은 라이브 녹음의 경우 bufferTime을 0으로 설정해야한다고 말합니다. 즉, 카메라/마이크에 의해 생성되는 즉시 데이터를 보내려고합니다.

다음은 사용중인 Timer입니다. 이것은 버퍼 길이를 검사하여 녹음이 중지되었음을 감지하는 것 같습니다. 두 경우 녹화가 중지됩니다 때 정말 있습니다

  • 사용자가 버튼을 "중지"를 클릭하고 코드가
  • 서버 또는 뭔가 다른이 중지됩니다 어떤 시나리오를 중지

    (네트워크 문제 등)

라는 메시지가 "NetStream.Record.Stop"를 확인하기 위해 귀하의 NetStatusEvent 처리기 메서드 (handleStreamStatus())를 사용하는 대신 bufferLength을 확인하기 위해 타이머를 사용하는 것이 좋습니다 것입니다. 이렇게하면 사용자가 "중지"를 클릭하는 것보다 다른 이유로 레코딩이 중단 된 경우 코드가 감지 할 수 있습니다.

타이머가 문제의 원인 일 수 있습니다. bufferTime 값을 크게 설정 했더라도 Red 5 서버에서는 작동하지 않거나 다르게 동작하거나 서버 측 설정에 의해 무시 될 수 있습니다. 그럼에도 불구하고 요점은 bufferLength을 사용하여 녹음이 중지되었는지 감지하는 것입니다.

NetStatusEvent으로 발송되는 useful messages 묶음이 있는데, 그 중 하나를 읽고 이상이 있는지 확인하는 것이 좋습니다. 그들은 꽤 신뢰할 수 있으며 발생할 수있는 대부분의 모든 상황을 처리하는 것 같습니다.

내가 발견 한 마지막 것은 (문제가되지 않습니다,하지만 수정의 가치가) : 당신이 마이크에 에코 억제를 가능하게하지만, 당신이 강화 된 마이크 도착하지 않는 문제가 해결되지 않습니다

var mic:Microphone = Microphone.getEnhancedMicrophone(); 
+0

귀하의 자세한 답변을 위해 Sunil에게 감사드립니다. 대단히 감사합니다. 내가 가진 타이머 메서드 대신 NetStream.Record.Stop을 사용하여 곧 다시 시도해 보겠습니다. 이 두 위치 https://gist.github.com/987076 및 http://www.technogumbo.com/tutorials/Recording-Decent-Quality-Video-And-Audio-With-Flash-and에서 자습서를 수행했습니다. -Red5/index.php 둘 다 길이가 60 인 버퍼를 사용한다고 언급했습니다. –

+0

흥미 롭습니다. 필자는 녹음하는 동안 아무 것도 버퍼링하지 않은 몇 가지 응용 프로그램에서 작업했습니다. 이 상황에서 버퍼링의 이점이 무엇인지 확신 할 수 없습니다. 예를 들어, "라이브 비디오 채팅"응용 프로그램에서 버퍼링을 원하지 않을 것입니다. 그러나 다른 시나리오에서는이를 사용할 수 있을지도 모릅니다. –

+0

버퍼가없고 그냥 스트림을 닫으면 문제는 녹화 된 비디오가 전체 레코딩의 짧은 세그먼트에 불과하다는 것입니다. 녹화를 중지하고 activeStream.attachAudio (null) 및 activeStream .attachCamera (null) 서버가 패킷 수신을 중지하지만 FLV 파일을 디스크에 계속 작성합니다. 따라서 red5에 모든 패킷이 있기 때문에 문제가 클라이언트 측에 있지 않을 수 있습니다. 일단 파일이 디스크에 쓰기 만 완료되면 activeStream을 닫을 수 있습니다. Record.Stop 이벤트를 기다리려고했지만 activeStream.close를 수행 한 후에 만 ​​트리거됩니다. –

0

녹음은 대기열 임계 값을 변경하여 Red5 V1.0.2에서 잘 작동합니다. 저는 video resume website이라는 jobma가 비디오를 아주 잘 녹화하고있는 것을 보았습니다. 그들은 빨간색을 사용하는 것 같습니다