캠화면 서버에 FLV로 저장하기

RED5의 RTMP 프로토콜을 이용하면 NetStream의 데이타를 flv로 저장할 수 있습니다.

먼저 RED5의 샘플에서 제공되는 as2.0 소스를 보여드리겠습니다.

/*
Author: John Grden
email: neoRiley@gmail.com

This sample is a basic recorder.  It saves the stream to the webapps/oflaDemo/streams folder and plays
it back once you click the stop button.
*/


import mx.utils.Delegate;

// create basic netConnection object
var nc:NetConnection = new NetConnection();

// connect to the local Red5 server
nc.connect(“rtmp://localhost/oflaDemo“);

// create the netStream object and pass the netConnection object in the constructor
var ns:NetStream = new NetStream(nc);

// get references to the camera and mic
var cam:Camera = Camera.get();
var mic:Microphone = Microphone.get();

// setup some simple settings with the cam and mic for quality
setupCameraMic();

// we store the last saved recording so we can play it back when stop is clicked
var lastVideoName:String = “”;

// listen for the button clicks
playButton.addEventListener(“click“, Delegate.create(this, playClick));
stopButton.addEventListener(“click“, Delegate.create(this, stopClick));

function playClick():Void
{
        // This FLV is recorded to webapps/oflaDemo/streams/ directory
        // attach cam and mic to the NetStream Object
        ns.attachVideo(cam);
        ns.attachAudio(mic);

        // attach the cam to the videoContainer on stage so we can see ourselves
        videoContainer.attachVideo(cam);

        // create a random number to store a unique name
        lastVideoName = “red5RecordDemo_” + random(getTimer());
        ns.publish(lastVideoName, “record“);

        // disable the playbutton
        playButton.enabled = false;

        // enable the stop button
        stopButton.enabled = true;
}

function stopClick():Void
{
        // close the netStream object
        ns.close();

        // clear the videoContainer
        videoContainer.attachVideo(null);
        videoContainer.clear();

        // enable the playbutton
        playButton.enabled = true;

        // disable the stop button
        stopButton.enabled = false;

        // play the recording back
        playLastVideo();
}

function playLastVideo():Void
{
        // attach the netStream object to the video object
        videoContainer.attachVideo(ns);

        // play back the recorded stream
        ns.play(lastVideoName);
}

function setupCameraMic():Void
{
        // setup cam
        cam = Camera.get();
        // setting dimensions and framerate
        cam.setMode(320, 240, 30);
        // set to minimum of 70% quality
        cam.setQuality(0,70);

        // setup mic
        mic = Microphone.get();
        mic.setRate(44);
}


소스 분석까지 할 것도 없는 소스긴 한데
비디오를 안해보신분들은 모를 수도 있으니까 한마디 하자면

var nc:NetConnection = new NetConnection();

// connect to the local Red5 server
nc.connect(“rtmp://localhost/oflaDemo“);

// create the netStream object and pass the netConnection object in the constructor
var ns:NetStream = new NetStream(nc);

사실 이거면 as2.0에서는 끝나는겁니다.
나머지는 부수적인 것들입니다.

NetConnection객체를 만들고 접속을 시도합니다. 여기서는 rtmp 프로토콜로 접속을 하게 됩니다.
끊기전까지는 계속 연결이 유지 되는 프로토콜입니다.
그리고 NetStream의 생성자에 NetConnection 만 물려주면 이제 끝나는겁니다.
스트림으로 데이타가 오고갈 수 있는 상태가 된거죠.
여기 부수적으로 캠을 붙이고, 저장하기 위해 publish라는걸 하고 뭐 그게 답니다.

만약 비디오쪽 코딩을 해본적이 없는 관계로 내용을 잘 모르셔도, 이 소스 대로만 하면 문제가 없습니다.
분석할만한 것도 없는 그냥 API의 나열입니다.


문제는 as3.0 입니다.

플래시 레퍼런스에도 없고, 왠만해선 찾을기도 힘든 에러와 예외가 무지 발생합니다.
특히 보도 못한 onBWDone() 이라는게 계속 뜨면서 제가 3일 삽질한 원인을 제공했습니다.
짜증이 슬슬 밀려오면서 오기를 같이 모시고 오더군요.

샘플에서 as3.0으로 된 소스는 제공되지 않고, 제대로 된 소스도 구할 수 없었던 것도 이유입니다.
일단 국내 검색엔진에서 검색되는건 없고 플렉스컴포넌트 카페에서 어떤분이 질문을 하셨던데
제대로된 소스는 역시 없더군요.

구글에서도 찾기 힘들어서 미국야후 전전긍긍하다가 이렇게 해보라는 글이 있길래
해봤더니 된겁니다. 역시 제대로된 소스는 외국검색엔진에서도 찾기 힘들었습니다 -_-
내가 정보검색력이 딸리는건지 원…….

암튼 시작 합니다.

소스는 나중에 보여드리고 어떻게 해야 예외와 에러 발생을 피할 수 있는지에 대해
설명을 할께염.

코드 구성 순서대로~

conn = new NetConnection();
conn.client = this;
conn.addEventListener(NetStatusEvent.NET_STATUS, netStatus_handler);
conn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, security_handler);

conn.objectEncoding = ObjectEncoding.AMF0;
conn.connect(connURL);

자 먼저 커넥션 하는 부분입니다.
넷커넥션 객첼르 만들고 리스너를 꼭 해줘야 합니다. 안그러면 예외 발생합니다.
무슨 예외 상황을 방지해야 하는지는 레퍼런스에 잘 나와있더라구요.
그리고 ObjectEncoding의 AMF0 이라고 나왔는데
AMF 라는건 ActionSript Message Format 입니다. 스트림을 통해 왔다갔다할 이진데이타의 포멧을
말하는데, AMF0은 as1.0이나 2.0이고 AMF3은 as3.0이랍니다.
일단 디폴트값이 있기 때문에 안해줘도 되긴 합니다.
그리고 커넥션을 겁니다.

여기서 connURL 에는 RED5 설치값인
private var connURL:String = “rtmp://localhost/oflaDemo”;
이렇게 잡혀 있습니다.

as2.0에서는 다음에 그대로 NetStream을 연결하면 되지만, as3.0에서는 알 수 없는
예외가 쭉 듭니다. 사실 이게 제가 삽질한 부분의 가장 큰 부분이었네요.
3.0에서는 커넥션메서드를 쓰고, 커넥션이 완료 된 후에 NetStream을 연결해야 합니다.
안그러면 예외 쭉 뜹니다.

private function netStatus_handler(evt:NetStatusEvent):void
{
        var info:Object = evt.info;
        // 커넥션이 성공적으로 연결되면
        trace(info.code);
        if (info.code == “NetConnection.Connect.Success“) {
                trace(“Successful connection“);
                connectStream();
                connectCam();
        }
}

뭐 이런식으로 핸들러로 들어온 이벤트의 내용에 커넥션 성공 메시지가 있는데
이걸 확인해서 다음으로 넘어가면 됩니다.

private function connectStream():void
{
        stream =  new NetStream(conn);
        stream.addEventListener(NetStatusEvent.NET_STATUS, netStatus_handler);
        stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, async_error_handler);
}

스트림역시 필요한 리스너를 걸어줘야 합니다. 합니다. 안그러면 예외없이 예외가 쭉 듭니다.
스트림에는 조금전에 만든 커넥션 객체를 넣어주면 됩니다.

private function connectCam():void
{
        // 캠 객체를 만들고 비디오에 연결합니다.
        var cam:Camera = Camera.getCamera();
        cam.setMode(320, 240, 30, true);
        cam.setQuality(0, 80);

        // 마이크로폰 객체
        var mic:Microphone = Microphone.getMicrophone();
  var myVideo:Video = getChildByName(“myVideo“) as Video;

        stream.attachCamera(cam, -1);
        stream.attachAudio(mic);
        myVideo.attachCamera(cam);
}

이제 캠과 연결 하는데, 캠을 화면에 표시하기 위해 myVideo에 넣는거고,
stream을 통해 데이타 전송을 해야하기 때문에 스트림에도 캠객체를 넣습니다.

주의하실건 Camera 객체는 new Camera로 하시면 작동이 안된다는거
Camera.getCamera() 하셔야 합니다. 마이크도 마찬가지구요.
myVideo 는 플래시 IDE의 Stage에 놓여져 있는 비디오객체구요.
스테이지에 놓여있는 참조를 얻기 위해 저런 형태로 차일드를 가져왔습니다.

자 이제 여기까지 해서 실행을 하면 일단 화면에 캠이 나옵니다.
이제 저장을 해봐야죠.

private function replay_handler(evt:MouseEvent):void
{
        var myVideo:Video = getChildByName(“myVideo“) as Video;
        myVideo.attachNetStream(stream);
        stream.play(“hihihi“);
}
private function end_handler(evt:MouseEvent):void
{
        trace(“레코딩 끝“);
        stream.close();

}
private function start_handler(evt:MouseEvent):void
{
        trace(“레코딩 시작“);
        stream.publish(“hihihi“, “record“);

}

화면에 버튼이 3개 놓여져 있는데
녹화시작, 녹화끝, 저장된비됴 보기

이렇게 3개 입니다.
위의 핸들러가 대응되구요. 서버에 레코딩은 그냥 .publish(“파일명”, “record”);
이렇게 하시면 끝납니다.
publish의 두번째 파라메터는3가지 형태가 있는데
“live” 는 브로드캐스팅 목적,
“record”는 서버에 flv로 저장하려는 목적,
“append”는 record와 비슷하지만, record는 파일을 오버라이드 하고, append는 이어서 붙입니다.

이렇게 녹화가 끝나면 stream.close()해서 스트림을 끝냅니다.
그리고 attachNetStream해서 스트림객체를 비디오에 넣고, play에다가 파일명을 넣어주면
그대로 플레이가 됩니다.

그러면 flv는 어디 저장이 되느냐
c:\Program Files\Red5\webapps\oflaDemo\streams\
여기 저장이 됩니다.

긴 글 읽느라고 고생하셨쎄여

여까징 히히
소스 첨부합니다.

서진우

슈퍼컴퓨팅 전문 기업 클루닉스/ 상무(기술이사)/ 정보시스템감리사/ 시스존 블로그 운영자

You may also like...

페이스북/트위트/구글 계정으로 댓글 가능합니다.