가장 기본적인 방법만 소개 드리겠습니다.
Video For Windows라는 윈도우즈의 비디오 라이브러리가 있는데
모두 Windows API함수로 되어 있어 쉽게 사용할 수 있습니다.
vfw.h 파일을 인클루드시키고 컴파일한 후 프로그램을 링크시킬 때 vfw32.lib를
함께 링크하면 됩니다.
함수 사용 순서는 다음과 같습니다.
AVIFile 라이브러리를 시작시킵니다. [AVIFileInit()]
작업하고자 하는 비디오 파일을 엽니다. [AVIFileOpen()]
그 비디오 파일의 비디오 스트림을 엽니다. [AVIFileGetStream()]
필요하다면 그 스트림의 정보를 얻습니다. [AVIStreamInfo()]
프레임 추출 작업을 준비시킵니다. [AVIStreamGetFrameOpen()]
필요한 프레임 데이터를 추출합니다. [AVIStreamGetFrame()]
프레임 추출 작업을 종료합니다. [AVIStreamGetFrameClose()]
열려 있는 스트림을 닫습니다. [AVIStreamRelease()]
열려 있는 파일을 닫습니다. [AVIFileRelease()]
AVIFile 라이브러리를 종료시킵니다. [AVIFileExit()]
이와 같이 스트림의 GetFrame기능을 사용하면 프로그래머가 일일이 코덱을 사용해서
압축을 해제하는 일이 필요 없고 시스템에 코덱만 깔려 있으면 알아서 복원해 주니
사용하기가 아주 편리합니다. 또, 이때 추출된 프레임 영상 데이터는 Packed DIB형태
이므로 여기에 BITMAPFILEHEADER만 추가하면 그대로 BMP파일로 저장할 수 있습니다.
또한 영상 데이터가 DIB라서 직접 픽셀 데이터를 조작하기가 쉬어 여러가지 영상 처리
기법을 구사할 수 있습니다.
===========================================================================================
Avi 파일을 여는 부분<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Avi파일을 다루는 함수는 기본적으로 Windows API로 제공된다. 이 프로그램에서는 LoadAviFile()함수가 그런 API 를 이용하여 Avi파일을 열고 있다. 먼저 AVIFileOpen()함수를 이용해서 파일의 핸들을 얻고 AVIFileInfo()함수를 통해서 헤더에 해당하는 정보를 얻어온다. 여기서 얻어온 헤더정보를 이용해서 Avi파일을 처리하게 된다.
void CAviDialog::LoadAviFile()
{
int ErrorCode;
gcpavi=0;
m_bSearchArea=false;
m_MouseRect=CRect(-1,-1,-1,-1);
// Avi 파일을 개방한다.
ErrorCode = AVIFileOpen(&ppAviFile, AviFilePath, OF_READ, NULL);
if (ErrorCode == AVIERR_BADFORMAT)
MessageBox("AVIERR_BADFORMAT", NULL, MB_OK);
else if (ErrorCode == AVIERR_MEMORY)
MessageBox("AVIERR_MEMORY", NULL, MB_OK);
else if (ErrorCode == AVIERR_FILEREAD)
MessageBox("AVIERR_FILEREAD", NULL, MB_OK);
else if (ErrorCode == AVIERR_FILEOPEN)
MessageBox("AVIERR_FILEOPEN", NULL, MB_OK);
AVIFileInfo(ppAviFile, &pAviInfo, sizeof(pAviInfo));
AviPlayRate = 1000 / (pAviInfo.dwRate / pAviInfo.dwScale);
// Refresh time
m_sFS.Format("%df/s", pAviInfo.dwRate / pAviInfo.dwScale);
UpdateData(FALSE);
// 파일에 포함된 스트림의 종류를 얻는다. audio, midi, text, video
// 파일에 포함된 스트림의 종류만큼 반복한다.
// pavi값을 배열에 저장해야 한다.
for (int i = 0; i <= MAXNUMSTREAMS; i++)
{
if (AVIFileGetStream(ppAviFile, &pavi, 0L, i) != AVIERR_OK)
break;
if (i == MAXNUMSTREAMS)
{
AVIStreamRelease(pavi);
MessageBox("Exceeded maximum number of streams", NULL, MB_OK);
break;
}
gapavi[i] = pavi;
}
gcpavi = i;
for (i = 0; i < gcpavi; i++)
{
// 스트림헤더의 정보를 얻는다.
AVIStreamInfo(gapavi[i], &avis, sizeof(avis));
switch (avis.fccType)
{
case streamtypeVIDEO:
// 전체 프레임 수를 얻는다.
length = AVIStreamLength(gapavi[i]);
// 전체프레임수를 나타낸다.
m_sFrameRate.Format("%d/%d", 1, length);
UpdateData(FALSE);
l= sizeof(format);
// 비트맵 정보를 읽는다.
AVIStreamReadFormat(gapavi[i], AVIStreamStart(gapavi[i]), &format, &l);
bi = (LPBITMAPINFOHEADER)format;
pgf = AVIStreamGetFrameOpen(gapavi[i], NULL);
// BITMAPINFOHEADER의 정보를 설정한다.
bi = (LPBITMAPINFOHEADER)format;
// BITMAPFILEHEADER의 정보를 설정한다.
bf.bfType = 19778;
// 트루컬러는 RGBQUAD 정보가 없다.
bf.bfSize =
sizeof(BITMAPINFOHEADER) +
sizeof(BITMAPFILEHEADER) +
bi->biWidth * bi->biHeight * 3;
bf.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
// 현재 나타낼 프레임을 첫번째로 설정한다.
AviFramePosition = 0;
break;
case streamtypeAUDIO:
LPWAVEFORMAT pwf = (LPWAVEFORMAT)abFormat;
l = sizeof(wf);
length = AVIStreamLength(gapavi[i]);
AVIStreamReadFormat(gapavi[i], AVIStreamStart(gapavi[i]), &wf, &l);
/*fp=fopen("sample.pcm", "wb");
for (pos=0; pos<length; pos++)
{
AVIStreamRead(gapavi[i], (long) pos, 1L, lpAudio, sizeof(lpAudio), &s, NULL);
fwrite(lpAudio, s, 1, fp);
}
fclose(fp);*/
break;
}
}
Invalidate();
}
Avi 파일에서 프레임별로 Bmp파일을 추출하는 부분
AVIStreamGetFrame()함수는 원하는 위치의 프레임을 얻어오는 역할을 수행하는 API함수이다. 일단 이 함수를 통해서 얻어온 프레임은 다시 비트맵의 정보를 가지고 있는 LPBITMAPINFOHEADER구조체를 통해서 비트맵화 된다.
void CAviDialog::GetAviFrame(int AviFramePosition, HDC dc)
{
// 현재 나타낼 이미지의 프레임을 얻는다.
if ((gf = (unsigned char *) AVIStreamGetFrame(pgf, AviFramePosition))==NULL && CameraState==NONACTIVE)
MessageBox("CODEC이 컴퓨터에 설치되어 있지 않습니다.", NULL, MB_OK);
else
{
bi = (LPBITMAPINFOHEADER)gf;
bi->biXPelsPerMeter = 0;
bi->biYPelsPerMeter = 0;
bitmapinfo.bmiHeader.biBitCount = bi->biBitCount;
bitmapinfo.bmiHeader.biClrImportant = bi->biClrImportant;
bitmapinfo.bmiHeader.biClrUsed = bi->biClrUsed;
bitmapinfo.bmiHeader.biCompression = bi->biCompression;
bitmapinfo.bmiHeader.biHeight = bi->biHeight;
bitmapinfo.bmiHeader.biWidth = bi->biWidth;
bitmapinfo.bmiHeader.biPlanes = bi->biPlanes;
bitmapinfo.bmiHeader.biSize = bi->biSize;
bitmapinfo.bmiHeader.biSizeImage = bi->biSizeImage;
bitmapinfo.bmiHeader.biXPelsPerMeter = bi->biXPelsPerMeter;
bitmapinfo.bmiHeader.biYPelsPerMeter = bi->biYPelsPerMeter;
gf += sizeof(BITMAPINFOHEADER);
rect.left = 8;
rect.top = 7;
rect.right = bitmapinfo.bmiHeader.biWidth + 8;
rect.bottom = bitmapinfo.bmiHeader.biHeight + 7;
// 이미지를 다이얼로그에 나타낸다.
if (m_bHSBMode!=TRUE)
{
// 이미지 분석모드가 아닐경우
SetDIBitsToDevice(dc, 8, 7, bitmapinfo.bmiHeader.biWidth, bitmapinfo.bmiHeader.biHeight ,
0 ,0, 0, (WORD)bitmapinfo.bmiHeader.biWidth, gf, &bitmapinfo, DIB_RGB_COLORS);
} else
{
// 이미지 분석모드일 경우
AnalysisImage(gf);
SetDIBitsToDevice(dc, 8, 7, bitmapinfo.bmiHeader.biWidth, bitmapinfo.bmiHeader.biHeight ,
0 ,0, 0, (WORD)bitmapinfo.bmiHeader.biWidth, m_BinImg, &bitmapinfo, DIB_RGB_COLORS);
}
}
}
'Program Visual C++' 카테고리의 다른 글
레지스트리 등록 (RegCreatekeyEx, RegDeleteValue, RegOpenkeyEX, RegSetValueEx (0) | 2012.01.05 |
---|---|
MFC CInternetSession클래스 사용시_유의점 (0) | 2011.12.01 |
정적 라이브러리에서 MFC 사용 (0) | 2011.08.25 |
Event, Thread (0) | 2011.08.25 |
MFC 더블버퍼링 메모리 버퍼 이용 (0) | 2011.08.25 |