AVI操作函数

来源:互联网 发布:anywhere软件的用法 编辑:程序博客网 时间:2024/04/19 14:00

 


#include "stdafx.h"


#define AVIIF_KEYFRAME  0x00000010L // this frame is a key frame.


#include <memory.h>
#include <mmsystem.h>
#include <vfw.h>

BOOL AVI_Init()
{
        /* first let's make sure we are running on 1.1 */
        WORD wVer = HIWORD(VideoForWindowsVersion());
        if (wVer < 0x010a){
             /* oops, we are too old, blow out of here */
             //MessageBeep(MB_ICONHAND);
             MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP);
             return FALSE;
        }

        AVIFileInit();

        return TRUE;
}

BOOL AVI_FileOpenWrite(PAVIFILE * pfile, char *filename)
{
        HRESULT hr = AVIFileOpen(pfile,           // returned file pointer
                       filename,                  // file name
                       OF_WRITE | OF_CREATE,      // mode to open file with
                       NULL);                     // use handler determined
                                                  // from file extension....
        if (hr != AVIERR_OK)
                return FALSE;

        return TRUE;
}

DWORD getFOURCC(CString value)
{
 if(value.CompareNoCase("DIB") == 0)
 {
  return mmioFOURCC(value[0],value[1],value[2],' ');
 }
 else if((value.CompareNoCase("CVID") == 0)
   || (value.CompareNoCase("IV32") == 0)
   || (value.CompareNoCase("MSVC") == 0)
   || (value.CompareNoCase("IV50") == 0))
 {
  return mmioFOURCC(value[0],value[1],value[2],value[3]);
 }
 else
 {
  return NULL;
 }
}

// Fill in the header for the video stream....
// The video stream will run in rate ths of a second....
BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second
                      unsigned long buffersize, int rectwidth, int rectheight,
       CString _compressor)
{
  AVISTREAMINFO strhdr;
  memset(&strhdr, 0, sizeof(strhdr));
        strhdr.fccType                = streamtypeVIDEO;// stream type
  strhdr.fccHandler             = getFOURCC(_compressor);
        //strhdr.fccHandler             = 0; // no compression!
  //strhdr.fccHandler             = mmioFOURCC('D','I','B',' '); // Uncompressed
  //strhdr.fccHandler             = mmioFOURCC('C','V','I','D'); // Cinpak
  //strhdr.fccHandler             = mmioFOURCC('I','V','3','2'); // Intel video 3.2
  //strhdr.fccHandler             = mmioFOURCC('M','S','V','C'); // Microsoft video 1
  //strhdr.fccHandler             = mmioFOURCC('I','V','5','0'); // Intel video 5.0
  //strhdr.dwFlags                = AVISTREAMINFO_DISABLED;
  //strhdr.dwCaps                 =
  //strhdr.wPriority              =
  //strhdr.wLanguage              =
        strhdr.dwScale                = 1;
        strhdr.dwRate                 = rate;               // rate fps
  //strhdr.dwStart                = 
  //strhdr.dwLength               =
  //strhdr.dwInitialFrames        =
        strhdr.dwSuggestedBufferSize  = buffersize;
  strhdr.dwQuality              = -1; // use the default
  //strhdr.dwSampleSize           =
        SetRect(&strhdr.rcFrame, 0, 0,              // rectangle for stream
            (int) rectwidth,
            (int) rectheight);
  //strhdr.dwEditCount            =
  //strhdr.dwFormatChangeCount    =
  //strcpy(strhdr.szName, "Full Frames (Uncompressed)");

        // And create the stream;
        HRESULT hr = AVIFileCreateStream(pfile,             // file pointer
                                 ps,                // returned stream pointer
                                 &strhdr);          // stream header
        if (hr != AVIERR_OK) {
                return FALSE;
        }

        return TRUE;
}

CString getFOURCCVAsString(DWORD value)
{
 CString returnValue = "";
 DWORD ch0 = value & 0x000000FF;
 returnValue += (char) ch0;
 DWORD ch1 = (value & 0x0000FF00)>>8;
 returnValue += (char) ch1;
 DWORD ch2 = (value & 0x00FF0000)>>16;
 returnValue += (char) ch2;
 DWORD ch3 = (value & 0xFF000000)>>24;
 returnValue += (char) ch3;

 return returnValue;
}

CString dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts)
{
 CString tmp = "";
 CString returnValue = "Dump of AVICOMPRESSOPTIONS\n";

 tmp.Format("DWORD  fccType = streamtype(%s)\n", getFOURCCVAsString(opts.fccType));
 returnValue += tmp;
 
 tmp.Format("DWORD  fccHandler = %s\n", getFOURCCVAsString(opts.fccHandler));
 returnValue += tmp;

 tmp.Format("DWORD  dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery);
 returnValue += tmp;

 tmp.Format("DWORD  dwQuality = %d\n", opts.dwQuality);
 returnValue += tmp;

 tmp.Format("DWORD  dwBytesPerSecond = %d\n", opts.dwBytesPerSecond);
 returnValue += tmp;

 if(opts.dwFlags & AVICOMPRESSF_DATARATE == AVICOMPRESSF_DATARATE){tmp.Format("DWORD  fccType = AVICOMPRESSF_DATARATE\n");}
 else if(opts.dwFlags & AVICOMPRESSF_INTERLEAVE == AVICOMPRESSF_INTERLEAVE){tmp.Format("DWORD  fccType = AVICOMPRESSF_INTERLEAVE\n");}
 else if(opts.dwFlags & AVICOMPRESSF_KEYFRAMES == AVICOMPRESSF_KEYFRAMES){tmp.Format("DWORD  fccType = AVICOMPRESSF_KEYFRAMES\n");}
 else if(opts.dwFlags & AVICOMPRESSF_VALID == AVICOMPRESSF_VALID){tmp.Format("DWORD  fccType = AVICOMPRESSF_VALID\n");}
 else {tmp.Format("DWORD  dwFlags = Unknown(%d)\n", opts.dwFlags);}
 returnValue += tmp;

 tmp.Format("LPVOID lpFormat = %d\n", opts.lpFormat);
 returnValue += tmp;

 tmp.Format("DWORD  cbFormat = %d\n", opts.cbFormat);
 returnValue += tmp;

 tmp.Format("LPVOID lpParms = %d\n", opts.lpParms);
 returnValue += tmp;

 tmp.Format("DWORD  cbParms = %d\n", opts.cbParms);
 returnValue += tmp;

 tmp.Format("DWORD  dwInterleaveEvery = %d\n", opts.dwInterleaveEvery);
 returnValue += tmp;

 return returnValue;
}

BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi,
     CString _compressor)
{
        
        AVICOMPRESSOPTIONS opts;
        AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts};

  memset(&opts, 0, sizeof(opts));
  opts.fccType = streamtypeVIDEO;
  opts.fccHandler             = getFOURCC(_compressor);
  //opts.fccHandler  = 0;
  //opts.fccHandler            = mmioFOURCC('D','I','B',' '); // Uncompressed
  //opts.fccHandler             = mmioFOURCC('C','V','I','D'); // Cinpak
  //opts.fccHandler             = mmioFOURCC('I','V','3','2'); // Intel video 3.2
  //opts.fccHandler             = mmioFOURCC('M','S','V','C'); // Microsoft video 1
  //opts.fccHandler             = mmioFOURCC('I','V','5','0'); // Intel video 5.0
  //opts.dwKeyFrameEvery = 5;
  //opts.dwQuality
  //opts.dwBytesPerSecond
  //opts.dwFlags                = AVICOMPRESSF_KEYFRAMES;
  //opts.lpFormat
  //opts.cbFormat
  //opts.lpParms
  //opts.cbParms
  //opts.dwInterleaveEvery

  /* display the compression options dialog box if specified compressor is unknown */
  if(getFOURCC(_compressor) == NULL)
  {
   if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
   {
    return FALSE;
   }

   //printf("%s", dumpAVICOMPRESSOPTIONS(opts));
   MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts), "AVICOMPRESSOPTIONS", MB_OK);
  }  

        HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL);
        if (hr != AVIERR_OK) {
                return FALSE;
        }

        hr = AVIStreamSetFormat(*psCompressed, 0,
                               lpbi,                    // stream format
                               lpbi->biSize             // format size
                                   + lpbi->biClrUsed * sizeof(RGBQUAD)
                                   );
        if (hr != AVIERR_OK) {
        return FALSE;
        }

        return TRUE;
}

BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight)
{
        // Fill in the stream header for the text stream....
        AVISTREAMINFO strhdr;
        DWORD dwTextFormat;
        // The text stream is in 60ths of a second....

  memset(&strhdr, 0, sizeof(strhdr));
        strhdr.fccType                = streamtypeTEXT;
        strhdr.fccHandler             = mmioFOURCC('D', 'R', 'A', 'W');
        strhdr.dwScale                = 1;
        strhdr.dwRate                 = 60;
        strhdr.dwSuggestedBufferSize  = sizeof(szText);
        SetRect(&strhdr.rcFrame, 0, (int) height,
            (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20

        // ....and create the stream.
        HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr);
        if (hr != AVIERR_OK) {
                return FALSE;
        }

        dwTextFormat = sizeof(dwTextFormat);
        hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat));
        if (hr != AVIERR_OK) {
                return FALSE;
        }

        return TRUE;
}

BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi)
{
 int ImageSize = lpbi->biSizeImage;
 if (ImageSize == 0)
 {
  if (lpbi->biBitCount == 24)
  {
   ImageSize = lpbi->biWidth * lpbi->biHeight * 3;
  }
 }
 HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer
  time, // time of this frame
  1, // number to write
  (LPBYTE) lpbi + // pointer to data
  lpbi->biSize +
  lpbi->biClrUsed * sizeof(RGBQUAD),
  ImageSize, // lpbi->biSizeImage, // size of this frame
  AVIIF_KEYFRAME, // flags....
  NULL,
  NULL);
 if (hr != AVIERR_OK)
 {
  CString strMsg;
  strMsg.Format("Error: AVIStreamWrite, error %d",hr);
  AfxMessageBox(strMsg);
  return FALSE;
 }
 
 return TRUE;
}

BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText)
{
        int iLen = strlen(szText);

        HRESULT hr = AVIStreamWrite(psText,
                        time,
                        1,
                        szText,
                        iLen + 1,
                        AVIIF_KEYFRAME,
                        NULL,
                        NULL);
        if (hr != AVIERR_OK)
                return FALSE;

        return TRUE;
}

BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText)
{
        if (ps)
                AVIStreamClose(ps);

        if (psCompressed)
                AVIStreamClose(psCompressed);

        if (psText)
                AVIStreamClose(psText);

 

        return TRUE;
}

BOOL AVI_CloseFile(PAVIFILE pfile)
{
        if (pfile)
                AVIFileClose(pfile);
       
        return TRUE;
}

BOOL AVI_Exit()
{
        AVIFileExit();

        return TRUE;
}

 

 

 

 

 

 

 


/* Here are the additional functions we need! */


PAVIFILE pfile = NULL;
PAVISTREAM ps = NULL;
PAVISTREAM psCompressed = NULL;
int count = 0;


// Initialization...
bool START_AVI(CString file_name)
{
    if(! AVI_Init())
 {
  //printf("Error - AVI_Init()\n");
  return false;
 }

    if(! AVI_FileOpenWrite(&pfile, file_name.GetBuffer(-1)))
 {
  //printf("Error - AVI_FileOpenWrite()\n");
  return false;
 }

 file_name.ReleaseBuffer(-1);
 return true;
}
 
//Now we can add frames
// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25);
bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, CString _compressor, int _frameRate)
{
 LPBITMAPINFOHEADER lpbi;
 if(count == 0)
 {
  lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib);
  if(! AVI_CreateStream(pfile, &ps, _frameRate,
   (unsigned long) lpbi->biSizeImage,
   (int) lpbi->biWidth,
   (int) lpbi->biHeight, _compressor))
  {
   //printf("Error - AVI_CreateStream()\n");
   GlobalUnlock(lpbi);
   return false;
  }

  if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor))
  {
   //printf("Error - AVI_SetOptions()\n");
   GlobalUnlock(lpbi);
   return false;
  }

  GlobalUnlock(lpbi);
 }

 lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib);
 if(! AVI_AddFrame(psCompressed, count * 1, lpbi))
 {
  //printf("Error - AVI_AddFrame()\n");
  GlobalUnlock(lpbi);
  return false;
 }

 GlobalUnlock(lpbi);
 count++;
 return true;
}

// The end...
bool STOP_AVI()
{
     if(! AVI_CloseStream(ps, psCompressed, NULL))
  {
   //printf("Error - AVI_CloseStream()\n");
   return false;
  }

     if(! AVI_CloseFile(pfile))
  {
  //printf("Error - AVI_CloseFile()\n");
  return false;
  }
 
     if(! AVI_Exit())
  {
  //printf("Error - AVI_Exit()\n");
  return false;
  }

  return true;
}

 

 

 

 

1AVIBuildFilter
2AVIClearClipboard
3AVIFileAddRef
4AVIFileCreateStream
5AVIFileEndRecord
6AVIFileExit
7AVIFileGetStream
8AVIFileInfo
9AVIFileInit
10AVIFileOpen
11AVIFileReadData
12AVIFileRelease
13AVIFileWriteData
14AVIGetFromClipboard
15AVIMakeCompressedStream
16AVIMakeFileFromStreams
17AVIMakeStreamFromClipboard
18AVIPutFileOnClipboard


19AVISave
20AVISaveOptions
21AVISaveOptionsFree
22AVISaveV


23AVIStreamAddRef
24AVIStreamBeginStreaming
25AVIStreamCreate
26AVIStreamEndStreaming
27AVIStreamFindSample
28AVIStreamGetFrame
29AVIStreamGetFrameClose
30AVIStreamGetFrameOpen
31AVIStreamInfo
32AVIStreamLength
33AVIStreamOpenFromFile
34AVIStreamRead
35AVIStreamReadData
36AVIStreamReadFormat
37AVIStreamRelease
38AVIStreamSampleToTime
39AVIStreamSetFormat
40AVIStreamStart
41AVIStreamTimeToSample
42AVIStreamWrite
43AVIStreamWriteData


44CreateEditableStream

45EditStreamClone
46EditStreamCopy
47EditStreamCut
48EditStreamPaste
49EditStreamSetInfo
50EditStreamSetName

总共50个函数,他们的用途主要有两类,一个是avi文件的操作,一类是数据流streams的操作。下面分别解析。

1文件操作

1.1打开和关闭文件

  AVIFileOpenAVIFileAddRef

  AVIFileRelease

1.2从文件中读取文件信息

通过AVIFileInfo可以获取avi文件的一些信息,这个函数返回一个AVIFILEINFO结构

通过AVIFileReadData可以用来获取AVIFileInfo函数得不到的信息。这些信息也许不包含在文件的头部,比如拥有file的公司和个人的名称。

1.3写入文件信息

可以通过AVIFileWriteData函数来写入文件的一些额外信息。

1.4使用粘贴板

  AVIPutFileOnClipboard函数可以将一个avi复制到粘贴板上

  AVIGetFromClipboard函数可以将粘贴板上的avi写入到内存或者硬盘中。

  AVIClearClipboard用来清除粘贴板

2数据流操作

2.1打开和关闭一个流

 打开一个数据流就跟打开文件一样,你可以通过 AVIFileGetStream函数来打开一个数据流,这个函数创建了一个流的接口,然后在该接口中保存了一个句柄。

 如果你想操作文件的某一个单独的流,你可以采用AVIStreamOpenFromFile函数,这个函数综合了AVIFileOpenAVIFileGetStream函数。

 如果你想操作文件中的多个数据流,你就要首先AVIFileOpen,然后AVIFileGetStream

 

 可以通过AVIStreamAddRef来增加stream接口的引用。

通过AVIStreamRelease函数来关闭数据流。这个函数用来减少streams的引用计数,当计数减少为0时,删除。

2.2从流中读取数据和信息

AVIStreamInfo函数可以获取数据的一些信息,该函数返回一个AVISTREAMINFO结构,该结构包含了数据的类型压缩方法,建议的buffersize,回放的rate,以及一些description

   如果数据流还有一些其它的额外的信息,你可以通过AVIStreamReadData函数来获取。应用程序分配一个内存,传递给这个函数,然后这个函数会通过这个内存返回数据流的信息,额外的信息可能包括数据流的压缩和解压缩的方法,你可以通过AVIStreamDataSize宏来回去需要申请内存块的大小。

   可以通过AVIStreamReadFormat函数获取数据流的格式信息。这个函数通过指定的内存返回数据流的格式信息,比如对于视频流,这个buffer包含了一个BIMAPINFO结构,对于音频流,内存块包含了WAVEFORMATEX或者PCMAVEFORMAT结构。你可以通过给AVIStreamReadFormat传递一个空buffer就可以获取buffer的大小。也可以通过AVIStreamFormatSize宏。

  可以通过AVIStreamRead函数来返回多媒体的数据。这个函数将数据复制到应用程序提供的内存中,对于视频流,这个函数返回图像祯,对于音频流,这个函数返回音频的sample数据。可以通过给AVIStreamRead传递一个NULLbuffer来获取需要的buffer的大小。也可以通过AVIStreamSampleSize宏来获取buffer的大小。

  有些AVI数据流句柄可能需要在启动数据流的前要做一下准备工作,此时,我们可以调用AVIStreamBeginStreaming函数来告知AVI数据流handle来申请分配它需要的一些资源。在完毕后,调用AVIStreamEndStreamming函数来释放资源。

2.3操作压缩的视频数据

  如果你要演示一祯或者几祯压缩视频图像时,你可以调用AVIStreamRead函数,将获取的数据传递给DrawDib函数来显示图像。这些函数可以显示压缩和未压缩的图像。

  AVIFile也提供了一个函数AVIStreamGetFrameOpen,来获取未压缩的视频祯,这个函数创建了内存来获取未压缩的数据。也可以通过AVIStreamGetFrame函数来解压缩一个单独的视频祯。这个函数可以解压缩某一祯图像,然后将数据以一个BIMAPINFOHEADER结构返回。当你调用完AVIStreamGetFrame函数后,要调用AVIStreamGetFrameClose函数释放上一个函数申请的资源。

2.4根据已存在的数据流创建文件

   创建一个包含多个数据流的文件的方法就是整合多个数据流,将其写入一个新文件。这些数据流可以是内存中的数据,也可以是存在于另一个文件中。

  我们可以用AVISave这个函数来build一个文件。这个函数可以创建一个文件,并且将指定的多个数据流按照指定的顺序写入文件,你也可以通过AVISaveV函数来创建一个新的文件,这个函数的功能和AVISave的功能一样,主要区别是AVISaveV采用的数据流数组,而AVISave是单个的数据流,多次保存。

  我们可以调用AVISaveOptions函数来显示一个对话框,可以让用户来选择压缩方式。

  我们可以在调用AVISaveAVISaveV函数时指定一个回调函数,用来显示avi文件的生成进度,可以让用户随时地取消生成avi文件。

  我们可以调用GetSaveFileNamePreview函数来显示保存的对话框让用户选择保存的文件名。

  通过AVIMakeFileFromStreams函数我们可以创建一个虚拟的文件句柄,其他的avi函数可以通过这个虚拟的文件句柄来操作文件中的数据流,操作完毕要记得调用AVIFileRelease释放。

2.5向文件写入一个数据流

 我们可以通过AVIFileCreateStream函数来在一个新文件或者已经存在的文件中创建一个数据流。这个函数根据AVISTREAMINFO结构定义了新的数据流,并为新的数据流创建一个接口,返回接口的指针。

  在写入新的数据前,一定要指定流的格式信息,通过AVIStreamSetFormat函数,当设置一个视频流的时候,一定要使用BIMAPINFO结构来设置,音频就用WAVEFORMAT

  然后我们就可以通过AVIStreamWrite函数将我们的多媒体数据写入数据流了。这个函数将应用程序提供的内存数据复制到指定的流。缺省的avi handler将数据写入流的最后。

  如果你有其他额外的信息需要写入流,你可以调用AVIFileWriteData或者AVIStreamWriteData

 最后记得在完成数据写入后,要调用AVIStreamRelease

2.6数据流中的祯的位置

 寻找起始祯:

  可以通过AVIStreamStart函数来获取第一祯包含的sample number。也可以通过AVIStreamInfo函数来获取这个信息,这个函数的AVISTREAMINFO结构中包含了dwStart,可以通过AVIStreamStartTime宏来获取第一个sample

  可以通过AVIStreamLength函数来获取流的长度。这个函数返回流中的sample的数目。也可以通过AVIStreamInfo函数来获取这些信息,可以通过AVIStreamLengthTime宏来获取流的长度,毫秒。

  在视频流中,一个sample对应着一祯图像,所以,有时这些sample中没有视频数据,如果你调用AVIStreamRead函数来数据,可能返回NULL,也可以通过AVIStreamFindSample通过指定FIND_ANY标志来查找指定的sample

查找关键祯

通过AVIStreamFindSample函数查找符合要寻找的sample,然后可以通过下面的宏判断是否关键祯。

timesample间互相切换

 AVIStreamSampleToTime这个函数可以将smaple转换成毫秒。对于视频,这个值代表的是这个祯开始播放的时间,

 AVIStreamTimeToSample

2.7 创建临时的streams

 我们可以通过AVIStreamCreate函数在内存中创建一个临时数据流,

 我们可以从一个未压缩的数据流创建一个压缩的数据流,采用AVIMakeCompressedStream函数,

 当我们使用完 avistreamcreate或者avimakecompressedstream创建的数据流,要一定使用AVIStreamRelease函数来关闭数据流。

2.8对数据流进行编辑

 我们可以通过CreateEditableStream函数来创建一个用于编辑的数据流。这个函数初始化了编辑流的环境,这些包含

 EditStreamCut

EditStreamCopy

EditStreamPaste

EditStreamClone

EditStreamSetInfo

EditStreamSetName

原创粉丝点击