Native/C

Video Capture에 대하여

aucd29 2013. 10. 2. 18:46

Video Capture에 대하여


Windows는 비디오 캡쳐기능을 지원하기 위해서 AVICap 이라는 WNDCLASS를 지원한다. AVICap은 윈도우이기 때문에 이 윈도우로 보내는 메시지를 통해서 제어를 하게 된다. AVICap은 비디오와 오디오를 캡쳐하고 이것을 가공하며, 디스크에 저장할 수 있는 기능이 있다.

About Video Capture

AVICap은 비디오를 스트리밍하거나 한 프레임을 캡쳐하는 기능을 제공한다. AVICap 윈도우는 다음과 같은 기능을 가지고 있다.

  • 오디오와 비디오를 캡쳐해서 AVI로 저장할 수 있다.
  • 동적으로 비디오와 오디오 장치와 연결하거나 끊을 수 있다.
  • 현재 입력중인 비디오 시그널을 오버레이나 프리뷰를 이용하여 실시간으로 볼 수 있다.
  • 비디오를 저장할 파일을 지정할 수 있다.
  • 캡쳐 레이트를 지정할 수 있다.
  • 비디오 소스와 포맷을 지정하는 대화상자를 지원한다.
  • 팔레트를 생성하고, 저장하고, 로드할 수 있다.
  • 이미지와 팔레트를 클립보드에 복사할 수 있다.
  • 한 이미지를 캡쳐하여 DIB로 저장할 수 있다.

Video Capture : A Minimal Approach

다음과 같은 코드로 간단하게 비디오를 캡쳐할 수 있다.

hWndC = capCreateCaptureWindow("My Own Capture Window", 
			       WS_CHILD | WS_VISIBLE , 
			       0, 0, 160, 120, hwndParent, nID); 
SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0 /* wIndex */, 0L);
SendMessage(hWndC, WM_CAP_SEQUENCE, 0, 0L);

AVICap 윈도우를 생성하고 나면 SendMessage를 통해서 AVICap을 제어할 수 있다. 그러나 읽기 쉬운 코드를 위해서 간편한 마크로들을 지원한다.

hWndC = capCreateCaptureWindow("My Own Capture Window", 
	 		       WS_CHILD | WS_VISIBLE , 
	 		       0, 0, 160, 120, hwndParent, nID); 
capDriverConnect(hWndC, 0);
capCaptureSequence(hWndC);

capCreateCaptureWindow로 AVICap윈도우를 생성하고, capDriverConnect로 디바이스와 연결한 뒤에 capCaptureSequence()를 호출하면 실제로 캡쳐를 시작한다.

디폴트로 capCaptureSequence()는 CAPTURE.AVI라는 파일에 저장한다. 캡쳐의 중단은 다음과 같은 경우에 된다.

  • 사용자가 ESC키를 누르거나 마우스 버튼을 눌렀을 때
  • 어플리케이션이 캡쳐를 중단할 때
  • 디스크가 꽉 찼을 때

캡쳐를 중단하기 위해서는 capCaptureStop (WM_CAP_STOP)이나 capCaptureAbort (WM_CAP_ABORT)를 이용한다.

Basic Capture Options

캡쳐 옵션은 CAPTUREPARMS에 설정한다. 다음과 같은 설정을 할 수 있다.

  • 캡쳐 레이트를 조절한다.
  • 캡쳐를 끝내는 방법 (키보드 혹은 마우스)을 설정한다.
  • 캡쳐 기간을 설정한다.

Capture Rate

캡쳐레이트는 CAPTUREPARMS의 dwRequestMicroSecPerFrame 멤버로 설정한다. 예를 들어 초당 x 프레임을 원한다면 1000 / x 를 넣으면 된다.

현재 캡쳐 파라미터는 capCaptureGetSetup (WM_CAP_GET_SEQUENCE_SETUP)을 이용하여 얻는다. 그리고 설정은 capCaptureSetSetup (WM_CAP_SET_SEQUENCE_SETUP)으로 한다.

dwRequestMicroSecPerFrame의 디폴트 값은 66667이며 이것은 초당 15프레임에 해당한다.

Keys Ending Capture

키나 마우스 버튼에 의해서 캡쳐를 중단할 수 있다. 어떤 키나 버튼에서 중단할 것인지는 CAPTUREPARMS의 vKeyAbort, fAbortLeftMouse, fAbortRightMouse에 설정된다.

capCaptureGetSetup을 통해 현재 설정을 얻고, capCaptureSetSetup을 통해 설정할 수 있다.

vKeyAbort에는 Virtual Key Code가 들어가며, 제대로 동작하게 하기 위해서는 RegisterHotKey를 이용하여 핫키를 설정해주어야 한다.

디폴트로는 vKeyAbort == VK_ESCAPE이고, fAbortLeftMouse == fAbortRightMouse == TRUE로 설정되어 있다.

Time Limit

CAPTUREPARMS의 fLimitEnabled와 wTimeLimit을 통해서 캡쳐기간을 정할 수 있다. wTimeLimit의 초단위이다.

Capture Windows

캡쳐 윈도우는 일반적인 컨트롤과 비슷하다. 통상적으로 WS_CHILD와 WS_VISIBLE 스타일을 가진다.

Creating an AVICap Capture Window

capCreateCaptureWindow로 캡쳐 윈도우를 생성한다.

Connecting a Capture Window to a Capture Driver

캡쳐 윈도우와 드라이버는 동적으로 연결되거나 끊어 질 수 있다. 드라이버와의 연결은 capDriverConnect (WM_CAP_DRIVER_CONNECT)로 이루어진다. 일단 드라이버와 연결되고 나면 device-specific한 메시지들을 캡쳐 윈도우로 보낼 수 있다.

만일 시스템에 하나 이상의 캡쳐 디바이스가 설치되어 있다면 원하는 드라이버의 번호를 인자로 주어야 한다. 드라이버의 목록은 레지스트리나 SYSTEM.INI의 [drivers] 항목에 있다. 첫번째 드라이버의 인덱스는 0이다.

설치된 캡쳐 디바이스들을 얻고 싶다면 capGetDriverDescription()함수를 이용한다. 이 함수를 통해 디바이스들의 리스트를 얻을 수 있다.

이미 연결된 디바이스의 이름을 얻고 싶다면 capDriverGetName (WM_CAP_DRIVER_GET_NAME)을, 디바이스 드라이버의 버전을 알고 싶다면 capDriverGetVersion (WM_CAP_DRIVER_GET_VERSION)을 사용하면 된다.

디바이스와의 연결을 끊고 싶다면 capDriverDisconnect (WM_CAP_DRIVER_DISCONNECT)를 사용하면 된다.

만일 캡쳐 윈도우가 제거된다면 자동적으로 드라이버와의 연결은 종료된다.

Parent-Child Window Interaction

WM_PALETTECHANGED와 WM_QUERYNEWPALETTE와 같은 시스템 레벨 메시지들은 오버랩드 윈도우나 톱레벨 윈도우로만 전해진다. 캡쳐 윈도우가 차일드 윈도우라면 부모 윈도우는 이들 메시지들을 캡쳐 윈도우로 전해주어야 한다.

비슷하게 부모 윈도우의 크기가 변할 때 캡쳐윈도우에 이것을 알려주어야 하며, 캡쳐 윈도우의 크기가 변할 때도 부모 윈도우에 알려주어야 한다.

Capture Window Status

캡쳐 윈도우의 상태는 capGetStatus (WM_CAP_GET_STATUS)로 얻을 수 있다. 이 함수는 CAPSTATUS구조체를 리턴한다. CAPSTATUS는 이미지의 크기, 스크롤 위치, 오버레이나 프리뷰가 작동중인가 등이 실려 있다.

Capture and Audio Drivers

캡쳐 드라이버는 비디오의 캡쳐 뿐 아니라 오디오의 캡쳐도 겸할 수 있다.

Capture Driver Capablilities

디바이스의 기능을 알고 싶다면 capDriverGetCaps (WM_CAP_DRIVER_GET_CAPS)를 사용하면 된다. 이 함수는 CAPDRIVERCAPS에 정보를 넘겨 준다.

Video Dialog Boxes

캡쳐 드라이버는 최대 4개의 대화상자를 지원한다. 대화상자의 모양과 내용은 드라이버의 구현에 따른다.

Video Source Dialog Box

주로 비디오의 입력 채널을 선택하고, 비디오 이미지에 영향을 주는 인자를 설정한다. capDlgVideoSource (WM_CAP_DLG_VIDEOSOURCE)에 의해 표시된다.

Video Format Dialog Box

주로 비디오 프레임의 크기와 칼라포맷을 결정한다. capDlgVideoFormat (WM_CAP_DLG_VIDEOFORMAT)에 의해 표시된다.

Video Display Dialog Box

Display 대화상자는 비디오를 보는데 필요한 색상과 위치정보를 설정한다. 이 설정은 비디오를 화면에 표시하는 데에만 영향을 준다. 즉 비디오 스트림 자체에는 영향을 주지 않는다. capDlgVideoDisplay (WM_CAP_DLG_VIDEODISPLAY) 로 표시한다.

Video Compression Dialog Box

Compression 대화상자는 캡쳐 후의 압축에 대해 설정한다. capDlgVideoCompression (WM_CAP_DLG_VIDEOCOMPRESSION)으로 표시한다.

Preview and Overlay Modes

캡쳐 드라이버는 들어오는 비디오 스트림을 보는 두가지 방법을 제공한다. 하나는 preview모드이고, 다른 하나는 overlay 모드이다. 드라이버가 둘 다 제공한다면 사용자는 하나를 택하면 된다. 두 모드는 서로 배타적이다.

preview 모드는 캡쳐 장치에 의해 디지타이즈된 이미지를 메모리로 옮긴 다음 GDI함수를 사용하여 캡쳐 윈도우에 그려준다. 캡쳐 윈도우를 사용하는 어플리케이션이 포커스를 잃을 때 갱신속도를 늦출 수도 있다. preview 모드는 CPU를 많이 사용하기 때문에 이런 정책이 필요하다.

preview 모드에 관련해서는 세가지 명령이 있다.

overlay 모드는 하드웨어의 기능을 이용하여 CPU를 전혀 쓰지 않고 직접 디스플레이 한다. overlay 모드의 설정은 capOverlay (WM_CAP_SET_OVERLAY)를 이용한다.

preview 모드, overlay 모드 공히 표시 영역이 적다면 스크롤을 시킬 수 있다. capSetScrollPos (WM_CAP_SET_SCROLL) 을 이용하면 된다.

Video Format

비디오 포맷을 얻는 것은 capGetVideoFormat이나 capGetVideoFormatSize를 이용하고, 비디오 포맷을 설정하는 것은 capSetVideoFormat을 이용한다.

Video Capture Settings

CAPTUREPARMS는 캡쳐에 필요한 인자를 구성한다. 다음과 같은 내용을 가진다.

  • 프레임 레이트를 설정
  • 비디오 버퍼의 크기 설정
  • 오디오 캡쳐를 할 것인가?
  • 캡쳐의 time interval 설정
  • 캡쳐중에 MCI장치 (VCR or videodisc)를 사용할 것인가?
  • 캡쳐의 중지를 위한 키보드와 마우스 버튼 설정
  • 캡쳐중의 type of video averaging 설정

CAPTUREPARMS를 얻고 설정하는 것은 capCaptureGetSetupcapCaptureSetSetup으로 한다.

Audio Format

현재의 오디오 캡쳐 포맷을 얻기 위해서는 capGetAudioFormatcapGetAudioFormatSize를 사용한다. 디폴트는 8비트, 모노, 11KHz PCM이다. 위 두 함수는 WAVEFORMATEX를 인자로 사용한다.

오디오 캡쳐 포맷의 설정은 capSetAudioFormat으로 한다. 인자로는 WAVEFORMAT, WAVEFORMATEX, PCMWAVEFORMAT 을 사용할 수 있다.

Capture File and Buffers

Capture Filename

디폴트는 현재 사용 디스크의 루트 디렉토리에 CAPTURE.AVI라는 이름으로 저장한다. 다른 이름을 지정하려면 capFileSetCaptureFile을 사용한다.

현재 설정된 파일이름을 알려면 capFileGetCaptureFile을 사용한다.

Saving Captured Data to a New File

캡쳐된 데이타를 디스크에 저장하려면 capFileSaveAs를 사용한다.

Disk Space Preallocation for the Capture File

캡쳐된 데이타는 매우 큰 양을 가지기 때문에 점진적으로 파일크기를 늘리면 성능이 안 좋아진다. 그래서 미리 큰 양을 할당하는데, 이 때 capFileAlloc을 사용한다. 캡쳐 도중 이 크기를 넘어서면 자동적으로 파일의 크기를 늘려간다.

Index Size

AVI파일은 비디오와 오디오 청크들의 위치를 인덱스에 저장한다. 인덱스의 ㈀穗?사용가능한 프레임의 갯수를 제한한다.

인덱스의 크기를 얻으려면 capCaptureGetSetup을 이용하여 CAPTUREPARMS의 dwIndexSize를 보면 되고, 설정은 capCaptureSetup을 이용한다. 디폴트는 34,952이다.

Video and Audio Chunk Granularity

청크 granularity는 논리적인 블럭의 크기를 의미한다. 그래서 남은 부분은 채움 청크 (RIFF "JUNK")로 채운다.

granularity는 capCaptureGetSetup으로 얻은 CAPTUREPARMS의 wChunkGranularity에서 얻을 수 있고, capCaptureSetSetup으로 설정한다.

Video Buffers

캡쳐할 때 사용하는 비디오 버퍼의 수를 조절할 수 있다. CAPTUREPARMS의 wNumVideoRequested 멤버로 설정하며 capCaptureGetSetup과 capCaptureSetSetup으로 얻고 설정한다.

Audio Buffers

CAPTUREPARMS의 fCaptureAudio는 오디오를 캡쳐할 것인가를 결정한다. wNumAudioRequested는 버퍼의 수를, dwAudioBufferSize는 버퍼의 크기를 결정한다.

디폴트로는 fCaptureAudio == TRUE, dwNumAudioRequested == 4, dwAudioBufferSize == max(10K, 0.5sec) 이다.

Capture Variations

Manual Frame Capture

때로는 각 프레임 별로 제어를 할 필요가 있을 것이다. 이를 위해서 capCaptureSingleFrameOpen, capCaptureSingleFrame, capCaptureSingleFrameClose를 사용한다.

이 방법을 사용하면 오디오를 동시에 캡쳐할 수 없다.

Still-Image Capture

만일 한 프레임을 정지화상으로 캡쳐하고 싶다면 capGrabFrameNoStop이나 capGrabFrame을 사용한다.

이렇게 캡쳐된 이미지는 capEditCopy로 클립보드에 복사하거나, capFileSaveDIB로 DIB파일로 저장할 수 있다.

Capture Without Using Disk Storage

capCaptureSequenceNoFile 을 사용하면 캡쳐 데이타를 파일에 저장하지 않는다. 대신 콜백들을 이용하여 순간 캡쳐된 이미지들을 사용해야 한다.

직접 화상통신을 할 경우 이 모드를 사용해야 할 것이다.

Streaming Capture from an MCI Device

videodisc나 VCR등을 마치 비디오 소스인 것처럼해서 캡쳐할 수 있다. 이 때capSetMCIDeviceName을 사용하여 디바이스를 설정한다. 설정을 얻으려면 capGetMCIDeviceName을 사용한다.

MCI장치를 제어하기 위해서는 CAPTUREPARMS의 fMCIControl을 TRUE로 놓고, dwMCIStartTime과 dwMCIStopTime을 msec단위로 설정해야 한다.

Realtime Capture와 Step-frame Capture가 있는데 구분을 잘 모르겠다. 자세한 내용은 여기를.

Advanced Capture Options

Measuring Video Quality

CAPTUREPARMS에는 wPercentDropForError 멤버가 있는데, 실제 캡쳐 중에 누락된 프레임이 이 비율을 넘어서면 에러를 발생한다. 이 때 에러 메시지나 에러 콜백이 실행된다.

User-Initiated Capture

CAPTUREPARMS의 fMakeUserHitOKToCapture 멤버가 TRUE이면 캡쳐를 시작할 때 시작을 확인하는 대화상자를 표시한다. 이것은 캡쳐가 시작될 때 버퍼를 준비하는 등의 지연시간을 건너뛰고 캡쳐를 하기 위한 것이다.

Working with Palettes

캡쳐 드라이버는 자신의 팔레트를 초기에 설정한다. 이 팔레트는 일반적인 색상을 충분히 포함하고 있다.

현재의 캡쳐 드라이버의 팔레트를 얻기 위해서는 capPalettePastecapPaletteOpen을 사용한다. 또한 팔레트를 설정하기 위해서 capPaletteAutocapPaletteManual을 사용한다.

또한 사용중인 팔레트를 저장하기 위해 capPaletteSave를, 사용중인 팔레트를 클립보드로 보내기 위해 capEditCopy를 사용한다.

Embedding Information Chunks in an AVI File

여기를 참고

User Data Message

여기를 참고

AVICap Callback Functions

캡쳐 윈도우에서 상태 변화나, 에러 등의 통보를 받을 수 있는 콜백 메카니즘을 사용할 수 있다.

Precise Capture Control

콜백의 인자 nState에 다음과 같은 값이 넘어온다.

  • CONTROLCALLBACK_PREROLL : 버퍼가 모두 할당되고, 다른 캡쳐 준비가 완료되었음. TRUE를 리턴하면 캡쳐를 시작하고, FALSE를 리턴하면 중단한다.
  • CONTROLCALLBACK_CAPTURING : 캡쳐중에 빈번히 불려진다. 이때 FALSE를 리턴하면 캡쳐를 중단한다.

Error

디스크가 부족하거나, 파일이 읽기전용이거나, 하드웨어 에러이거나, 너무 많은 프레임이 누락되면 에러가 발생한다. 콜백의 인자로는 에러 코드와 에러 메시지가 전해진다. 에러 메시지는 사용자에게 보여질 수 있다.

에러코드로 0이 넘어올 경우는 새로운 동작이 시작되는 것이므로 에러 메시지 표시를 없애야 한다.

Frame

프레임이 완성되었음을 알린다. preview rate가 0이 아니고, 캡쳐중이 아닐 때만 호출된다.

Status Callback Functions

콜백의 인자는 상태ID와 상태 메시지가 있다. 캡쳐가 시작되면 IDS_CAP_BEGIN이 전해지며, 캡쳐가 끝나면 IDS_CAP_END가 전해진다. 0이 전해지면 새로운 작업이 시작됨을 알리는 것이기 때문에 이전의 상태를 클리어해야 한다.

Video Stream

버퍼가 완성되었고, 그것을 디스크에 쓰기 직전에 호출된다.

Wave Stream

오디오 버퍼가 완성되었고, 그것을 디스크에 쓰기 직전에 호출된다.

Yield Callback Functions

원할한 UI를 위해서 최소한 한 프레임이 완성될 때마다 호출한다. 그러나 정확하지는 않다. Yield 콜백은 주로 PeekMessage, TranslateMessage, DispatchMessage를 사용하여 구현한다.

Disabling Callback Functions

콜백 설정함수에 NULL을 설정하고 호출하면 콜백이 중지된다.

컴파일 하기 위해서는

#include

링크할 때는 vfw32.lib을 포함시킨다.

"); // :script -->