AVI 파일 다루기

Program Visual C++ 2011. 8. 30. 17:18 Posted by HisPark

가장 기본적인 방법만 소개 드리겠습니다.

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

}

}

}

[출처] AVI 파일 다루기 (차니의 컴퓨터 마을) |작성자 newchany