小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

vc++實現(xiàn)avi文件的操作

 昵稱219589 2009-08-13
為了對avi進(jìn)行讀寫,微軟提供了一套API,總共50個函數(shù),他們的用途主要有兩類,一個是avi文件的操作,一類是數(shù)據(jù)流streams的操作。

  1、打開和關(guān)閉文件

  AVIFileOpen ,AVIFileAddRef, AVIFileRelease

  2、從文件中讀取文件信息

  通過AVIFileInfo可以獲取avi文件的一些信息,這個函數(shù)返回一個AVIFILEINFO結(jié)構(gòu),通過AVIFileReadData可以用來獲取AVIFileInfo函數(shù)得不到的信息。這些信息也許不包含在文件的頭部,比如擁有file的公司和個人的名稱。

  3、寫入文件信息

  可以通過AVIFileWriteData函數(shù)來寫入文件的一些額外信息。

  4、打開和關(guān)閉一個流

  打開一個數(shù)據(jù)流就跟打開文件一樣,你可以通過 AVIFileGetStream函數(shù)來打開一個數(shù)據(jù)流,這個函數(shù)創(chuàng)建了一個流的接口,然后在該接口中保存了一個句柄。

  如果你想操作文件的某一個單獨(dú)的流,你可以采用AVIStreamOpenFromFile函數(shù),這個函數(shù)綜合了AVIFileOpen和AVIFileGetStream函數(shù)。

  如果你想操作文件中的多個數(shù)據(jù)流,你就要首先AVIFileOpen,然后AVIFileGetStream。

  可以通過AVIStreamAddRef來增加stream接口的引用。

  通過AVIStreamRelease函數(shù)來關(guān)閉數(shù)據(jù)流。這個函數(shù)用來減少streams的引用計數(shù),當(dāng)計數(shù)減少為0時,刪除。

  5、從流中讀取數(shù)據(jù)和信息

  AVIStreamInfo函數(shù)可以獲取數(shù)據(jù)的一些信息,該函數(shù)返回一個AVISTREAMINFO結(jié)構(gòu),該結(jié)構(gòu)包含了數(shù)據(jù)的類型壓縮方法,建議的buffersize,回放的rate,以及一些description。

  如果數(shù)據(jù)流還有一些其它的額外的信息,你可以通過AVIStreamReadData函數(shù)來獲取。應(yīng)用程序分配一個內(nèi)存,傳遞給這個函數(shù),然后這個函數(shù)會通過這個內(nèi)存返回數(shù)據(jù)流的信息,額外的信息可能包括數(shù)據(jù)流的壓縮和解壓縮的方法,你可以通過AVIStreamDataSize宏來回去需要申請內(nèi)存塊的大小。

  可以通過AVIStreamReadFormat函數(shù)獲取數(shù)據(jù)流的格式信息。這個函數(shù)通過指定的內(nèi)存返回數(shù)據(jù)流的格式信息,比如對于視頻流,這個buffer包含了一個BIMAPINFO結(jié)構(gòu),對于音頻流,內(nèi)存塊包含了WAVEFORMATEX或者PCMAVEFORMAT結(jié)構(gòu)。你可以通過給AVIStreamReadFormat傳遞一個空buffer就可以獲取buffer的大小。也可以通過AVIStreamFormatSize宏。

  可以通過AVIStreamRead函數(shù)來返回多媒體的數(shù)據(jù)。這個函數(shù)將數(shù)據(jù)復(fù)制到應(yīng)用程序提供的內(nèi)存中,對于視頻流,這個函數(shù)返回圖像禎,對于音頻流,這個函數(shù)返回音頻的sample數(shù)據(jù)??梢酝ㄟ^給AVIStreamRead傳遞一個NULL的buffer來獲取需要的buffer的大小。也可以通過AVIStreamSampleSize宏來獲取buffer的大小。

  有些AVI數(shù)據(jù)流句柄可能需要在啟動數(shù)據(jù)流的前要做一下準(zhǔn)備工作,此時,我們可以調(diào)用AVIStreamBeginStreaming函數(shù)來告知AVI數(shù)據(jù)流handle來申請分配它需要的一些資源。在完畢后,調(diào)用AVIStreamEndStreamming函數(shù)來釋放資源。

  6、操作壓縮的視頻數(shù)據(jù)

  如果你要演示一禎或者幾禎壓縮視頻圖像時,你可以調(diào)用AVIStreamRead函數(shù),將獲取的數(shù)據(jù)傳遞給DrawDib函數(shù)來顯示圖像。這些函數(shù)可以顯示壓縮和未壓縮的圖像。

  AVIFile也提供了一個函數(shù)AVIStreamGetFrameOpen,來獲取未壓縮的視頻禎,這個函數(shù)創(chuàng)建了內(nèi)存來獲取未壓縮的數(shù)據(jù)。也可以通過AVIStreamGetFrame函數(shù)來解壓縮一個單獨(dú)的視頻禎。這個函數(shù)可以解壓縮某一禎圖像,然后將數(shù)據(jù)以一個BIMAPINFOHEADER結(jié)構(gòu)返回。當(dāng)你調(diào)用完AVIStreamGetFrame函數(shù)后,要調(diào)用AVIStreamGetFrameClose函數(shù)釋放上一個函數(shù)申請的資源。

  7、根據(jù)已存在的數(shù)據(jù)流創(chuàng)建文件

  創(chuàng)建一個包含多個數(shù)據(jù)流的文件的方法就是整合多個數(shù)據(jù)流,將其寫入一個新文件。這些數(shù)據(jù)流可以是內(nèi)存中的數(shù)據(jù),也可以是存在于另一個文件中。

  我們可以用AVISave這個函數(shù)來build一個文件。這個函數(shù)可以創(chuàng)建一個文件,并且將指定的多個數(shù)據(jù)流按照指定的順序?qū)懭胛募?,你也可以通過AVISaveV函數(shù)來創(chuàng)建一個新的文件,這個函數(shù)的功能和AVISave的功能一樣,主要區(qū)別是AVISaveV采用的數(shù)據(jù)流數(shù)組,而AVISave是單個的數(shù)據(jù)流,多次保存。

  我們可以調(diào)用AVISaveOptions函數(shù)來顯示一個對話框,可以讓用戶來選擇壓縮方式。

  我們可以在調(diào)用AVISave和AVISaveV函數(shù)時指定一個回調(diào)函數(shù),用來顯示avi文件的生成進(jìn)度,可以讓用戶隨時地取消生成avi文件。

  我們可以調(diào)用GetSaveFileNamePreview函數(shù)來顯示保存的對話框讓用戶選擇保存的文件名。

  通過AVIMakeFileFromStreams函數(shù)我們可以創(chuàng)建一個虛擬的文件句柄,其他的avi函數(shù)可以通過這個虛擬的文件句柄來操作文件中的數(shù)據(jù)流,操作完畢要記得調(diào)用AVIFileRelease釋放。

8、向文件寫入一個數(shù)據(jù)流

  我們可以通過AVIFileCreateStream函數(shù)來在一個新文件或者已經(jīng)存在的文件中創(chuàng)建一個數(shù)據(jù)流。這個函數(shù)根據(jù)AVISTREAMINFO結(jié)構(gòu)定義了新的數(shù)據(jù)流,并為新的數(shù)據(jù)流創(chuàng)建一個接口,返回接口的指針。

  在寫入新的數(shù)據(jù)前,一定要指定流的格式信息,通過AVIStreamSetFormat函數(shù),當(dāng)設(shè)置一個視頻流的時候,一定要使用BIMAPINFO結(jié)構(gòu)來設(shè)置,音頻就用WAVEFORMAT。

  然后我們就可以通過AVIStreamWrite函數(shù)將我們的多媒體數(shù)據(jù)寫入數(shù)據(jù)流了。這個函數(shù)將應(yīng)用程序提供的內(nèi)存數(shù)據(jù)復(fù)制到指定的流。缺省的avi handler將數(shù)據(jù)寫入流的最后。

  如果你有其他額外的信息需要寫入流,你可以調(diào)用AVIFileWriteData或者AVIStreamWriteData,最后記得在完成數(shù)據(jù)寫入后,要調(diào)用AVIStreamRelease。

  9、數(shù)據(jù)流中的禎的位置

  尋找起始禎:

  可以通過AVIStreamStart函數(shù)來獲取第一禎包含的sample number。也可以通過AVIStreamInfo函數(shù)來獲取這個信息,這個函數(shù)的AVISTREAMINFO結(jié)構(gòu)中包含了dwStart,可以通過AVIStreamStartTime宏來獲取第一個sample。

  可以通過AVIStreamLength函數(shù)來獲取流的長度。這個函數(shù)返回流中的sample的數(shù)目。也可以通過AVIStreamInfo函數(shù)來獲取這些信息,可以通過AVIStreamLengthTime宏來獲取流的長度,毫秒。

  在視頻流中,一個sample對應(yīng)著一禎圖像,所以,有時這些sample中沒有視頻數(shù)據(jù),如果你調(diào)用AVIStreamRead函數(shù)來數(shù)據(jù),可能返回NULL,也可以通過AVIStreamFindSample通過指定FIND_ANY標(biāo)志來查找指定的sample。

  查找關(guān)鍵禎

  通過AVIStreamFindSample函數(shù)查找符合要尋找的sample,然后可以通過下面的宏判斷是否關(guān)鍵禎。

  在time和sample間互相切換。

  AVIStreamSampleToTime這個函數(shù)可以將smaple轉(zhuǎn)換成毫秒。對于視頻,這個值代表的是這個禎開始播放的時間。

  在了解了上面的知識后,我們對avi的文件結(jié)構(gòu)以及如何操作avi文件心里就明白了,下面我們可以開始我們的編程了。我們要做兩件事情:

  1、如何將一組靜態(tài)的bmp位圖合成一個avi的視頻文件;

  2、如何將一個未壓縮的avi文件解析成一幅幅位圖。

  示例程序界面如下:


  下面的函數(shù)演示了如何將一個文件夾下面的所有bmp文件都保存為一個avi文件,函數(shù)的第一個參數(shù)是要生成的AVI的文件名,第二個參數(shù)是存放bmp文件的文件夾名,這個函數(shù)會枚舉該文件夾下的所有bmp文件,合成一個AVI文件。


void Cbmp2aviDlg::AVItoBmp(CString strAVIFileName, CString strBmpDir)
{
 // TODO: 在此添加控件通知處理程序代碼
 AVIFileInit();
 PAVIFILE avi;
 int res=AVIFileOpen(&avi, strAVIFileName, OF_READ, NULL);
 int n = GetLastError();
 if (res!=AVIERR_OK)
 {
  //an error occures
  if (avi!=NULL)
   AVIFileRelease(avi);
  return ;
 }
 AVIFILEINFO avi_info;
 AVIFileInfo(avi, &avi_info, sizeof(AVIFILEINFO));
 PAVISTREAM pStream;
 res=AVIFileGetStream(avi, &pStream, streamtypeVIDEO /*video stream*/,
   0 /*first stream*/);
 if (res!=AVIERR_OK)
 {
  if (pStream!=NULL)
   AVIStreamRelease(pStream);
   AVIFileExit();
  return ;
 }

 //do some task with the stream
 int iNumFrames;
 int iFirstFrame;
 iFirstFrame=AVIStreamStart(pStream);
 if (iFirstFrame==-1)
 {
  //Error getteing the frame inside the stream
  if (pStream!=NULL)
   AVIStreamRelease(pStream);
  AVIFileExit();
  return ;
 }
 iNumFrames=AVIStreamLength(pStream);
 if (iNumFrames==-1)
 {
  //Error getteing the number of frames inside the stream
  if (pStream!=NULL)
   AVIStreamRelease(pStream);
  AVIFileExit();
  return ;
 }

 //getting bitmap from frame
 BITMAPINFOHEADER bih;
 ZeroMemory(&bih, sizeof(BITMAPINFOHEADER));

 bih.biBitCount=24; //24 bit per pixel
 bih.biClrImportant=0;
 bih.biClrUsed = 0;
 bih.biCompression = BI_RGB;
 bih.biPlanes = 1;
 bih.biSize = 40;
 bih.biXPelsPerMeter = 0;
 bih.biYPelsPerMeter = 0;
 //calculate total size of RGBQUAD scanlines (DWORD aligned)
 bih.biSizeImage = (((bih.biWidth * 3) + 3) & 0xFFFC) * bih.biHeight ;

 PGETFRAME pFrame;
 pFrame=AVIStreamGetFrameOpen(pStream, NULL );

 AVISTREAMINFO streaminfo;
 AVIStreamInfo(pStream,&streaminfo,sizeof(AVISTREAMINFO));

 //Get the first frame
 BITMAPINFOHEADER bih2;
 long lsize = sizeof(bih2);
 int index=0;
 for (int i=iFirstFrame; i<iNumFrames; i++)
 {
  index= i-iFirstFrame;
  BYTE* pDIB = (BYTE*) AVIStreamGetFrame(pFrame, index); //
  AVIStreamReadFormat(pStream,index,&bih2,&lsize);
  BITMAPFILEHEADER stFileHdr;

  BYTE* Bits=new BYTE[bih2.biSizeImage];
  AVIStreamRead(pStream,index,1,Bits,bih2.biSizeImage,NULL,NULL);
  //RtlMoveMemory(Bits, pDIB + sizeof(BITMAPINFOHEADER), bih2.biSizeImage);

  bih2.biClrUsed =0;
  stFileHdr.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
  stFileHdr.bfSize=sizeof(BITMAPFILEHEADER);
  stFileHdr.bfType=0x4d42;

  CString FileName;
  FileName.Format("Frame-%05d.bmp", index);
  CString strtemp = strBmpDir;
  strtemp += "\\";
  strtemp += FileName;
  FILE* fp=_tfopen(strtemp ,_T("wb"));
  fwrite(&stFileHdr,1,sizeof(BITMAPFILEHEADER),fp);
  fwrite(&bih2,1,sizeof(BITMAPINFOHEADER),fp);
  int ff = fwrite(Bits,1,bih2.biSizeImage,fp);
  int e = GetLastError();
  fclose(fp);
  /////
  delete Bits;
  //CreateFromPackedDIBPointer(pDIB, index);
 }

 AVIStreamGetFrameClose(pFrame);

 //close the stream after finishing the task
 if (pStream!=NULL)
  AVIStreamRelease(pStream);
 AVIFileExit();
}

  下面的這個函數(shù)演示了如何將AVI文件中的每一楨圖像單獨(dú)取出來,保存為bmp文件。函數(shù)的頭一個參數(shù)是avi文件名,第二個參數(shù)是存放bmp文件的文件夾。

//生成avi
void Cbmp2aviDlg::BMPtoAVI(CString szAVIName, CString strBmpDir)
{
 CFileFind finder;
 strBmpDir += _T("\\*.*");
 AVIFileInit();
 AVISTREAMINFO strhdr;
 PAVIFILE pfile;
 PAVISTREAM ps;
 int nFrames =0;
 HRESULT hr;

 BOOL bFind = finder.FindFile(strBmpDir);
 while(bFind)
 {
  bFind = finder.FindNextFile();
  if(!finder.IsDots() && !finder.IsDirectory())
  {
   CString str = finder.GetFilePath();
   FILE *fp = fopen(str,"rb");
   BITMAPFILEHEADER bmpFileHdr;
   BITMAPINFOHEADER bmpInfoHdr;
   fseek( fp,0,SEEK_SET);
   fread(&bmpFileHdr,sizeof(BITMAPFILEHEADER),1, fp);
   fread(&bmpInfoHdr,sizeof(BITMAPINFOHEADER),1, fp);

   BYTE *tmp_buf = NULL;
   if(nFrames ==0 )
   {
    AVIFileOpen(&pfile,szAviName,OF_WRITE | OF_CREATE,NULL);
    _fmemset(&strhdr, 0, sizeof(strhdr));
    strhdr.fccType = streamtypeVIDEO;// stream type
    strhdr.fccHandler = 0;
    strhdr.dwScale = 1;
    strhdr.dwRate = 15; // 15 fps
    strhdr.dwSuggestedBufferSize = bmpInfoHdr.biSizeImage ;
    SetRect(&strhdr.rcFrame, 0, 0, bmpInfoHdr.biWidth, bmpInfoHdr.biHeight);

    // And create the stream;
    hr = AVIFileCreateStream(pfile,&ps,&strhdr);
    // hr = AVIStreamSetFormat(ps,nFrames,&bmpInfoHdr,sizeof(bmpInfoHdr));
   }
   tmp_buf = new BYTE[bmpInfoHdr.biWidth * bmpInfoHdr.biHeight * 3];
   fread(tmp_buf, 1, bmpInfoHdr.biWidth * bmpInfoHdr.biHeight * 3, fp);
   hr = AVIStreamSetFormat(ps,nFrames,&bmpInfoHdr,sizeof(bmpInfoHdr));
   hr = AVIStreamWrite(ps, // stream pointer
      nFrames , // time of this frame
      1, // number to write
      (LPBYTE) tmp_buf,
      bmpInfoHdr.biSizeImage , // size of this frame
      AVIIF_KEYFRAME, // flags....
      NULL,
      NULL);

   nFrames ++;
   fclose(fp);
  }
 }

 AVIStreamClose(ps);

 if(pfile != NULL)
  AVIFileRelease(pfile);
 AVIFileExit();
}

  結(jié)束語:

  以上代碼在 vc 6.0 和windows xp平臺調(diào)試通過。這兩個函數(shù)你可以直接在你的程序中使用,更詳細(xì)的代碼可以參見隨著本文附上的示例源碼。這里我要指出的是,這個AVI文件和bmp互相轉(zhuǎn)換過程中,avi中的視頻數(shù)據(jù)都是存放的是沒有壓縮的數(shù)據(jù),如果你要分解AVI文件是經(jīng)過壓縮編碼,比如,DVSD,MPEG4編碼,首先你要采用相應(yīng)的解碼器對視頻數(shù)據(jù)解碼,然后將解碼過的數(shù)據(jù)保存為bmp文件。好了,關(guān)于avi文件的介紹就到這里結(jié)束了。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多