<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    淺陋見解,僅供參考。拋磚引玉,多加指教!
    石正
    一個(gè)計(jì)算機(jī)技術(shù)愛好者! 雖然我擁有了系統(tǒng)分析師的證書,但我仍然是一個(gè)計(jì)算機(jī)技術(shù)愛好者!
    posts - 119,comments - 73,trackbacks - 0
    http://www.cat898.com/Infolook.asp?bclass=1&id=57162
    posted @ 2007-12-14 09:10 石正 閱讀(184) | 評(píng)論 (0)編輯 收藏
     // 畫實(shí)心橢圓形
     CBrush Brush;
     Brush.CreateSolidBrush( RGB( 111, 134, 233 ) );
     pDC->BeginPath();
     pDC->Ellipse( m_rcMark );
     pDC->EndPath();
     pDC->SelectObject(&Brush);
     pDC->FillPath();
    posted @ 2007-11-28 11:34 石正 閱讀(300) | 評(píng)論 (0)編輯 收藏
    有三種方法:  
      1   在CApp類內(nèi)設(shè)定其顏色值  
      2   OnCtrlColor  
      2   OnEraserBkColor  


    BOOL   CMy444Dlg::OnEraseBkgnd(CDC*   pDC)    
      {  
      //   TODO:   Add   your   message   handler   code   here   and/or   call   default  
       
      CBrush   brush   (RGB   (128   ,   0   ,   128)   );  
      CBrush*   pOldBrush   =   pDC->SelectObject   (&brush);  
      CRect   reClip   ;  
      pDC->GetClipBox   (&reClip);  
       
      pDC->   PatBlt   (reClip.left   ,   reClip.top   ,  
                      reClip.Width   (   )   ,   reClip.Height   (   )   ,   PATCOPY   );  
       
      pDC->SelectObject   (pOldBrush   );  
       
      return   TRUE;  
       
       
      }
    posted @ 2007-11-27 14:37 石正 閱讀(852) | 評(píng)論 (0)編輯 收藏
    需要用到以下API:GetWindowRect和GetClientRect。  
      首先用GetWindowRect得到窗體的寬度與高度,再用GetClientRect得到窗體客戶區(qū)的寬度與高度,用(窗體寬度-窗體客戶區(qū)寬度)/2得到窗體邊框?qū)挾龋笥么绑w高度-窗體客戶區(qū)高度-窗體邊框?qū)挾鹊玫?2得到標(biāo)題欄的高度。
    Windows XP 下窗口標(biāo)題條高度 = 26
    posted @ 2007-11-27 14:13 石正 閱讀(1124) | 評(píng)論 (1)編輯 收藏
    為了對(duì)avi進(jìn)行讀寫,微軟提供了一套API,總共50個(gè)函數(shù),他們的用途主要有兩類,一個(gè)是avi文件的操作,一類是數(shù)據(jù)流streams的操作。

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

      AVIFileOpen ,AVIFileAddRef, AVIFileRelease

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

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

      3、寫入文件信息

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      然后我們就可以通過AVIStreamWrite函數(shù)將我們的多媒體數(shù)據(jù)寫入數(shù)據(jù)流了。這個(gè)函數(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ù)來獲取這個(gè)信息,這個(gè)函數(shù)的AVISTREAMINFO結(jié)構(gòu)中包含了dwStart,可以通過AVIStreamStartTime宏來獲取第一個(gè)sample。

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

      在視頻流中,一個(gè)sample對(duì)應(yīng)著一禎圖像,所以,有時(shí)這些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這個(gè)函數(shù)可以將smaple轉(zhuǎn)換成毫秒。對(duì)于視頻,這個(gè)值代表的是這個(gè)禎開始播放的時(shí)間。

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

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

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

      示例程序界面如下:


      下面的函數(shù)演示了如何將一個(gè)文件夾下面的所有bmp文件都保存為一個(gè)avi文件,函數(shù)的第一個(gè)參數(shù)是要生成的AVI的文件名,第二個(gè)參數(shù)是存放bmp文件的文件夾名,這個(gè)函數(shù)會(huì)枚舉該文件夾下的所有bmp文件,合成一個(gè)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();
    }

      下面的這個(gè)函數(shù)演示了如何將AVI文件中的每一楨圖像單獨(dú)取出來,保存為bmp文件。函數(shù)的頭一個(gè)參數(shù)是avi文件名,第二個(gè)參數(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平臺(tái)調(diào)試通過。這兩個(gè)函數(shù)你可以直接在你的程序中使用,更詳細(xì)的代碼可以參見隨著本文附上的示例源碼。這里我要指出的是,這個(gè)AVI文件和bmp互相轉(zhuǎn)換過程中,avi中的視頻數(shù)據(jù)都是存放的是沒有壓縮的數(shù)據(jù),如果你要分解AVI文件是經(jīng)過壓縮編碼,比如,DVSD,MPEG4編碼,首先你要采用相應(yīng)的解碼器對(duì)視頻數(shù)據(jù)解碼,然后將解碼過的數(shù)據(jù)保存為bmp文件。好了,關(guān)于avi文件的介紹就到這里結(jié)束了。

    posted @ 2007-10-24 10:30 石正 閱讀(7539) | 評(píng)論 (16)編輯 收藏
    摘要:本文詳細(xì)的解析了AVI文件的存儲(chǔ)結(jié)構(gòu),介紹了微軟提供的用來操作AVI文件的一組API使用方法,并通過例子代碼,演示了如何將一組靜態(tài)Bmp圖片合成一個(gè)avi視頻文件以及如何將一個(gè)avi視頻文件解析保存為一系列的bmp圖像文件。
     
    關(guān)鍵詞:avi文件 bmp圖像 vc
     
    AVI是音頻視頻交錯(cuò)(Audio Video Interleaved)的英文縮寫,它是Microsoft公司開發(fā)的一種符合RIFF文件規(guī)范的數(shù)字音頻與視頻文件格式,原先用于Microsoft Video for Windows (簡(jiǎn)稱VFW)環(huán)境,現(xiàn)在已被Windows 95/98、OS/2等多數(shù)操作系統(tǒng)直接支持。AVI格式允許視頻和音頻交錯(cuò)在一起同步播放,支持256色和RLE壓縮,但AVI文件并未限定壓縮標(biāo)準(zhǔn),因此,AVI文件格式只是作為控制界面上的標(biāo)準(zhǔn),不具有兼容性,用不同壓縮算法生成的AVI文件,必須使用相應(yīng)的解壓縮算法才能播放出來。常用的AVI播放驅(qū)動(dòng)程序,主要是Microsoft Video for Windows或Windows 95/98中的Video 1,以及Intel公司的Indeo Video。
      在介紹AVI文件前,我們要先來看看RIFF文件結(jié)構(gòu)。AVI文件采用的是RIFF文件結(jié)構(gòu)方式,RIFF(Resource Interchange File Format,資源互換文件格式)是微軟公司定義的一種用于管理windows環(huán)境中多媒體數(shù)據(jù)的文件格式,波形音頻wave,MIDI和數(shù)字視頻AVI都采用這種格式存儲(chǔ)。構(gòu)造RIFF文件的基本單元叫做數(shù)據(jù)塊(Chunk),每個(gè)數(shù)據(jù)塊包含3個(gè)部分,
    1 4字節(jié)的數(shù)據(jù)塊標(biāo)記(或者叫做數(shù)據(jù)塊的ID)
    2 數(shù)據(jù)塊的大小
    3 數(shù)據(jù)
    整個(gè)RIFF文件可以看成一個(gè)數(shù)據(jù)塊,其數(shù)據(jù)塊ID為RIFF,稱為RIFF塊。一個(gè)RIFF文件中只允許存在一個(gè)RIFF塊。RIFF塊中包含一系列的子塊,其中有一種字塊的ID為“LIST”,稱為LIST,LIST塊中可以再包含一系列的子塊,但除了LIST塊外的其他所有的子塊都不能再包含子塊。
       RIFF和LIST塊分別比普通的數(shù)據(jù)塊多一個(gè)被稱為形式類型(Form Type)和列表類型(List Type)的數(shù)據(jù)域,其組成如下:
    1 4字節(jié)的數(shù)據(jù)塊標(biāo)記(Chunk ID)
    2 數(shù)據(jù)塊的大小
    3 4字節(jié)的形式類型或者列表類型
    4 數(shù)據(jù)
     
    下面我們看看AVI文件的結(jié)構(gòu)。AVI文件是目前使用的最復(fù)雜的RIFF文件,它能同時(shí)存儲(chǔ)同步表現(xiàn)的音頻視頻數(shù)據(jù)。AVI的RIFF塊的形式類型是AVI,它包含3個(gè)子塊,如下所述:
    1信息塊,一個(gè)ID為”hdrl”的LIST塊,定義AVI文件的數(shù)據(jù)格式。
    2數(shù)據(jù)塊,一個(gè)ID為 “movi”的LIST塊,包含AVI的音視頻序列數(shù)據(jù)
    3索引塊,ID為 “idxl”的子塊,定義 “movi”LIST塊的索引數(shù)據(jù),是可選塊。
    AVI文件的結(jié)構(gòu)如下圖所示,下面將具體介紹AVI文件的各子塊構(gòu)造。
    1信息塊,信息塊包含兩個(gè)子塊,即一個(gè)ID為 avih 的子塊和一個(gè)ID 為 strl 的LIST塊。
     
    “avih”子塊的內(nèi)容可由如下的結(jié)構(gòu)定義:
     
    typedef struct
    {
     DWORD dwMicroSecPerFrame ; //顯示每楨所需的時(shí)間ns,定義avi的顯示速率
     DWORD dwMaxBytesPerSec; //      最大的數(shù)據(jù)傳輸率
     DWORD dwPaddingGranularity;    //記錄塊的長度需為此值的倍數(shù),通常是2048
     DWORD dwFlages;                 //AVI文件的特殊屬性,如是否包含索引塊,音視頻數(shù)據(jù)是否交叉存儲(chǔ)
     DWORD dwTotalFrame;              //文件中的總楨數(shù)
     DWORD dwInitialFrames;           //說明在開始播放前需要多少楨
     DWORD dwStreams;                 //文件中包含的數(shù)據(jù)流種類
     DWORD dwSuggestedBufferSize; //建議使用的緩沖區(qū)的大小,
                                  //通常為存儲(chǔ)一楨圖像以及同步聲音所需要的數(shù)據(jù)之和
     DWORD dwWidth;                   //圖像寬
     DWORD dwHeight;                   //圖像高
     DWORD dwReserved[4];               //保留值
    }MainAVIHeader;
     
    “strl” LIST塊用于記錄AVI數(shù)據(jù)流,每一種數(shù)據(jù)流都在該LIST塊中占有3個(gè)子塊,他們的ID分別是”strh”,”strf”, “strd”;
    “strh”子塊由如下結(jié)構(gòu)定義,
    typedef struct
    {
           FOURCC   fccType;      //4字節(jié),表示數(shù)據(jù)流的種類 vids 表示視頻數(shù)據(jù)流
                                  //auds 音頻數(shù)據(jù)流
           FOURCC   fccHandler;//4字節(jié) ,表示數(shù)據(jù)流解壓縮的驅(qū)動(dòng)程序代號(hào)
           DWORD    dwFlags;      //數(shù)據(jù)流屬性
       WORD     wPriority;    //此數(shù)據(jù)流的播放優(yōu)先級(jí)
           WORD     wLanguage;    //音頻的語言代號(hào)
           DWORD    dwInitalFrames;//說明在開始播放前需要多少楨
           DWORD    dwScale;       //數(shù)據(jù)量,視頻每楨的大小或者音頻的采樣大小
           DWORD    dwRate;        //dwScale /dwRate = 每秒的采樣數(shù)
           DWORD    dwStart;       //數(shù)據(jù)流開始播放的位置,以dwScale為單位
           DWORD    dwLength;      //數(shù)據(jù)流的數(shù)據(jù)量,以dwScale為單位
           DWORD    dwSuggestedBufferSize; //建議緩沖區(qū)的大小
           DWORD    dwQuality;      //解壓縮質(zhì)量參數(shù),值越大,質(zhì)量越好
           DWORD    dwSampleSize;   //音頻的采樣大小
           RECT     rcFrame;        //視頻圖像所占的矩形
    }AVIStreamHeader;
    “strf”子塊緊跟在”strh”子塊之后,其結(jié)構(gòu)視”strh”子塊的類型而定,如下所述;
    如果 strh子塊是視頻數(shù)據(jù)流,則 strf子塊的內(nèi)容是一個(gè)與windows設(shè)備無關(guān)位圖的BIMAPINFO結(jié)構(gòu),如下
    typedef struct tagBITMAPINFO
    {
           BITMAPINFOHEADER     bmiHeader;
           RGBQUAD              bmiColors[1]; //顏色表
    }BITMAPINFO;
     
    typedef struct tagBITMAPINFOHEADER
    {
           DWORD biSize;
           LONG biWidth;
           LONG biHeight;
           WORD biPlanes;
           WORD biBitCount;
           DWORD biCompression;
           DWORD biSizeImage;
           LONG biXPelsPerMeter;
           LONG biYPelsPerMeter;
           DWORD biClrUsed;
           DWORD biClrImportant;
    }BITMAPINFOHEADER;
    如果 strh子塊是音頻數(shù)據(jù)流,則strf子塊的內(nèi)容是一個(gè)WAVEFORMAT結(jié)構(gòu),如下
    typedef struct
    {
            WORD   wFormatTag; 
            WORD   nChannels;   //聲道數(shù)
            DWORD nSamplesPerSec; //采樣率
            DWORD nAvgBytesPerSec; //WAVE聲音中每秒的數(shù)據(jù)量
            WORD   nBlockAlign;     //數(shù)據(jù)塊的對(duì)齊標(biāo)志
            WORD   biSize;          //此結(jié)構(gòu)的大小
    }WAVEFORMAT
    “strd”子塊緊跟在strf子塊后,存儲(chǔ)供壓縮驅(qū)動(dòng)程序使用的參數(shù),不一定存在,也沒有固定的結(jié)構(gòu)。
    “strl” LIST塊定義的AVI數(shù)據(jù)流依次將 “hdrl “ LIST 塊中的數(shù)據(jù)流頭結(jié)構(gòu)與”movi” LIST塊中的數(shù)據(jù)聯(lián)系在一起,第一個(gè)數(shù)據(jù)流頭結(jié)構(gòu)用于數(shù)據(jù)流0,第二個(gè)用于數(shù)據(jù)流1,依次類推。
    數(shù)據(jù)塊中存儲(chǔ)視頻和音頻數(shù)據(jù)流,數(shù)據(jù)可直接存于 “movi” LIST塊中。數(shù)據(jù)塊中音視頻數(shù)據(jù)按不同的字塊存放,其結(jié)構(gòu)如下所述,
    音頻字塊
     “##wb”
     Wave 數(shù)據(jù)流
    視頻子塊中存儲(chǔ)DIB數(shù)據(jù),又分為壓縮或者未壓縮DIB,
     “##db”
     RGB數(shù)據(jù)流
     
     “##dc”
     壓縮的圖像數(shù)據(jù)流
     
    看到了吧,avi文件的圖像數(shù)據(jù)可以是壓縮的,和非壓縮格式的。對(duì)于壓縮格式來說,也可采用不同的編碼,也許你曾經(jīng)遇到有些avi沒法識(shí)別,就是因?yàn)榫幋a方式不一樣,如果沒有相應(yīng)的解碼,你就沒法識(shí)別視頻數(shù)據(jù)。AVI的編碼方式有很多種,比較常見的有 mpeg2,mpeg4, divx等。
    索引塊,索引快包含數(shù)據(jù)塊在文件中的位置索引,能提高avi文件的讀寫速度,其中存放著一組AVIINDEXENTRY結(jié)構(gòu)數(shù)據(jù)。如下,這個(gè)塊并不是必需的,也許不存在。
    typedef struct
     {
           DWORD ckid;          //記錄數(shù)據(jù)塊中子塊的標(biāo)記
           DWORD dwFlags;        //表示chid所指子塊的屬性
           DWORD dwChunkOffset;   //子塊的相對(duì)位置
           DWORD dwChunkLength; //子塊長度
    };
    Ok,現(xiàn)在我相信你肯定會(huì)對(duì)AVI的文件結(jié)構(gòu)已經(jīng)很清楚了,在介紹完了AVI文件結(jié)構(gòu)后,我們就來看看如何對(duì)avi文件進(jìn)行讀寫了,為了對(duì)avi進(jìn)行讀寫,微軟提供了一套API,總共50個(gè)函數(shù),他們的用途主要有兩類,一個(gè)是avi文件的操作,一類是數(shù)據(jù)流streams的操作。
    1 打開和關(guān)閉文件
      AVIFileOpen ,AVIFileAddRef, AVIFileRelease
    2從文件中讀取文件信息
    通過AVIFileInfo可以獲取avi文件的一些信息,這個(gè)函數(shù)返回一個(gè)AVIFILEINFO結(jié)構(gòu)
    通過AVIFileReadData可以用來獲取AVIFileInfo函數(shù)得不到的信息。這些信息也許不包含在文件的頭部,比如擁有file的公司和個(gè)人的名稱。
    3寫入文件信息
    可以通過AVIFileWriteData函數(shù)來寫入文件的一些額外信息。
    4打開和關(guān)閉一個(gè)流
      打開一個(gè)數(shù)據(jù)流就跟打開文件一樣,你可以通過 AVIFileGetStream函數(shù)來打開一個(gè)數(shù)據(jù)流,這個(gè)函數(shù)創(chuàng)建了一個(gè)流的接口,然后在該接口中保存了一個(gè)句柄。
     如果你想操作文件的某一個(gè)單獨(dú)的流,你可以采用AVIStreamOpenFromFile函數(shù),這個(gè)函數(shù)綜合了AVIFileOpen和AVIFileGetStream函數(shù)。
     如果你想操作文件中的多個(gè)數(shù)據(jù)流,你就要首先AVIFileOpen,然后AVIFileGetStream。
     可以通過AVIStreamAddRef來增加stream接口的引用。
    通過AVIStreamRelease函數(shù)來關(guān)閉數(shù)據(jù)流。這個(gè)函數(shù)用來減少streams的引用計(jì)數(shù),當(dāng)計(jì)數(shù)減少為0時(shí),刪除。
    5從流中讀取數(shù)據(jù)和信息
    AVIStreamInfo函數(shù)可以獲取數(shù)據(jù)的一些信息,該函數(shù)返回一個(gè)AVISTREAMINFO結(jié)構(gòu),該結(jié)構(gòu)包含了數(shù)據(jù)的類型壓縮方法,建議的buffersize,回放的rate,以及一些description。
       如果數(shù)據(jù)流還有一些其它的額外的信息,你可以通過AVIStreamReadData函數(shù)來獲取。應(yīng)用程序分配一個(gè)內(nèi)存,傳遞給這個(gè)函數(shù),然后這個(gè)函數(shù)會(huì)通過這個(gè)內(nèi)存返回?cái)?shù)據(jù)流的信息,額外的信息可能包括數(shù)據(jù)流的壓縮和解壓縮的方法,你可以通過AVIStreamDataSize宏來回去需要申請(qǐng)內(nèi)存塊的大小。
       可以通過AVIStreamReadFormat函數(shù)獲取數(shù)據(jù)流的格式信息。這個(gè)函數(shù)通過指定的內(nèi)存返回?cái)?shù)據(jù)流的格式信息,比如對(duì)于視頻流,這個(gè)buffer包含了一個(gè)BIMAPINFO結(jié)構(gòu),對(duì)于音頻流,內(nèi)存塊包含了WAVEFORMATEX或者PCMAVEFORMAT結(jié)構(gòu)。你可以通過給AVIStreamReadFormat傳遞一個(gè)空buffer就可以獲取buffer的大小。也可以通過AVIStreamFormatSize宏。
      可以通過AVIStreamRead函數(shù)來返回多媒體的數(shù)據(jù)。這個(gè)函數(shù)將數(shù)據(jù)復(fù)制到應(yīng)用程序提供的內(nèi)存中,對(duì)于視頻流,這個(gè)函數(shù)返回圖像禎,對(duì)于音頻流,這個(gè)函數(shù)返回音頻的sample數(shù)據(jù)。可以通過給AVIStreamRead傳遞一個(gè)NULL的buffer來獲取需要的buffer的大小。也可以通過AVIStreamSampleSize宏來獲取buffer的大小。
      有些AVI數(shù)據(jù)流句柄可能需要在啟動(dòng)數(shù)據(jù)流的前要做一下準(zhǔn)備工作,此時(shí),我們可以調(diào)用AVIStreamBeginStreaming函數(shù)來告知AVI數(shù)據(jù)流handle來申請(qǐng)分配它需要的一些資源。在完畢后,調(diào)用AVIStreamEndStreamming函數(shù)來釋放資源。
    6操作壓縮的視頻數(shù)據(jù)
      如果你要演示一禎或者幾禎壓縮視頻圖像時(shí),你可以調(diào)用AVIStreamRead函數(shù),將獲取的數(shù)據(jù)傳遞給DrawDib函數(shù)來顯示圖像。這些函數(shù)可以顯示壓縮和未壓縮的圖像。
     AVIFile也提供了一個(gè)函數(shù)AVIStreamGetFrameOpen,來獲取未壓縮的視頻禎,這個(gè)函數(shù)創(chuàng)建了內(nèi)存來獲取未壓縮的數(shù)據(jù)。也可以通過AVIStreamGetFrame函數(shù)來解壓縮一個(gè)單獨(dú)的視頻禎。這個(gè)函數(shù)可以解壓縮某一禎圖像,然后將數(shù)據(jù)以一個(gè)BIMAPINFOHEADER結(jié)構(gòu)返回。當(dāng)你調(diào)用完AVIStreamGetFrame函數(shù)后,要調(diào)用AVIStreamGetFrameClose函數(shù)釋放上一個(gè)函數(shù)申請(qǐng)的資源。
    7根據(jù)已存在的數(shù)據(jù)流創(chuàng)建文件
       創(chuàng)建一個(gè)包含多個(gè)數(shù)據(jù)流的文件的方法就是整合多個(gè)數(shù)據(jù)流,將其寫入一個(gè)新文件。這些數(shù)據(jù)流可以是內(nèi)存中的數(shù)據(jù),也可以是存在于另一個(gè)文件中。
      我們可以用AVISave這個(gè)函數(shù)來build一個(gè)文件。這個(gè)函數(shù)可以創(chuàng)建一個(gè)文件,并且將指定的多個(gè)數(shù)據(jù)流按照指定的順序?qū)懭胛募阋部梢酝ㄟ^AVISaveV函數(shù)來創(chuàng)建一個(gè)新的文件,這個(gè)函數(shù)的功能和AVISave的功能一樣,主要區(qū)別是AVISaveV采用的數(shù)據(jù)流數(shù)組,而AVISave是單個(gè)的數(shù)據(jù)流,多次保存。
      我們可以調(diào)用AVISaveOptions函數(shù)來顯示一個(gè)對(duì)話框,可以讓用戶來選擇壓縮方式。
      我們可以在調(diào)用AVISave和AVISaveV函數(shù)時(shí)指定一個(gè)回調(diào)函數(shù),用來顯示avi文件的生成進(jìn)度,可以讓用戶隨時(shí)地取消生成avi文件。
      我們可以調(diào)用GetSaveFileNamePreview函數(shù)來顯示保存的對(duì)話框讓用戶選擇保存的文件名。
      通過AVIMakeFileFromStreams函數(shù)我們可以創(chuàng)建一個(gè)虛擬的文件句柄,其他的avi函數(shù)可以通過這個(gè)虛擬的文件句柄來操作文件中的數(shù)據(jù)流,操作完畢要記得調(diào)用AVIFileRelease釋放。
    8向文件寫入一個(gè)數(shù)據(jù)流
      我們可以通過AVIFileCreateStream函數(shù)來在一個(gè)新文件或者已經(jīng)存在的文件中創(chuàng)建一個(gè)數(shù)據(jù)流。這個(gè)函數(shù)根據(jù)AVISTREAMINFO結(jié)構(gòu)定義了新的數(shù)據(jù)流,并為新的數(shù)據(jù)流創(chuàng)建一個(gè)接口,返回接口的指針。
      在寫入新的數(shù)據(jù)前,一定要指定流的格式信息,通過AVIStreamSetFormat函數(shù),當(dāng)設(shè)置一個(gè)視頻流的時(shí)候,一定要使用BIMAPINFO結(jié)構(gòu)來設(shè)置,音頻就用WAVEFORMAT。
      然后我們就可以通過AVIStreamWrite函數(shù)將我們的多媒體數(shù)據(jù)寫入數(shù)據(jù)流了。這個(gè)函數(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ù)來獲取這個(gè)信息,這個(gè)函數(shù)的AVISTREAMINFO結(jié)構(gòu)中包含了dwStart,可以通過AVIStreamStartTime宏來獲取第一個(gè)sample。
      可以通過AVIStreamLength函數(shù)來獲取流的長度。這個(gè)函數(shù)返回流中的sample的數(shù)目。也可以通過AVIStreamInfo函數(shù)來獲取這些信息,可以通過AVIStreamLengthTime宏來獲取流的長度,毫秒。
      在視頻流中,一個(gè)sample對(duì)應(yīng)著一禎圖像,所以,有時(shí)這些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這個(gè)函數(shù)可以將smaple轉(zhuǎn)換成毫秒。對(duì)于視頻,這個(gè)值代表的是這個(gè)禎開始播放的時(shí)間。
     
    在了解了上面的知識(shí)后,我們對(duì)avi的文件結(jié)構(gòu)以及如何操作avi文件心里就明白了,下面我們可以開始我們的編程了。我們要做兩件事情,1如何將一組靜態(tài)的bmp位圖合成一個(gè)avi的視頻文件,2 如何將一個(gè)未壓縮的avi文件解析成一幅幅位圖。
     示例程序界面如下:
     
    下面的函數(shù)演示了如何將一個(gè)文件夾下面的所有bmp文件都保存為一個(gè)avi文件,函數(shù)的第一個(gè)參數(shù)是要生成的AVI的文件名,第二個(gè)參數(shù)是存放bmp文件的文件夾名,這個(gè)函數(shù)會(huì)枚舉該文件夾下的所有bmp文件,合成一個(gè)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();
    }
    下面的這個(gè)函數(shù)演示了如何將AVI文件中的每一楨圖像單獨(dú)取出來,保存為bmp文件。函數(shù)的頭一個(gè)參數(shù)是avi文件名,第二個(gè)參數(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平臺(tái)調(diào)試通過。這兩個(gè)函數(shù)你可以直接在你的程序中使用,更詳細(xì)的代碼可以參見隨著本文附上的示例源碼。這里我要指出的是,這個(gè)AVI文件和bmp互相轉(zhuǎn)換過程中,avi中的視頻數(shù)據(jù)都是存放的是沒有壓縮的數(shù)據(jù),如果你要分解AVI文件是經(jīng)過壓縮編碼,比如,DVSD,MPEG4編碼,首先你要采用相應(yīng)的解碼器對(duì)視頻數(shù)據(jù)解碼,然后將解碼過的數(shù)據(jù)保存為bmp文件。好了,關(guān)于avi文件的介紹就到這里結(jié)束了
    posted @ 2007-10-24 10:22 石正 閱讀(695) | 評(píng)論 (0)編輯 收藏
    VC++ 6.0
    方法1:
     CPen Pen( PS_SOLID, 1, RGB( 255, 0, 0 ) );
     
     CPen* pOldPen;
     pOldPen = pDC->SelectObject( &Pen );


    方法2:
     CPen Pen( PS_SOLID, 1, RGB( 255, 0, 255 ) );
     CPen* pOldPen;
     
     pOldPen = (CPen*)SelectObject( hDC, Pen.GetSafeHandle() );
    posted @ 2007-09-17 09:48 石正 閱讀(3788) | 評(píng)論 (2)編輯 收藏
    正確的格式應(yīng)該是:Copyright [dates] by [author/owner]

      通常可以代替Copyright, 但是不可以用(c)。 All Rights Reserved 在某些國家曾經(jīng)是必須的,但是現(xiàn)在在大多數(shù)國家,都不是法律上必須有的字樣。

    參見下面幾個(gè)正確的格式:

      1995-2004 Macromedia, Inc. All rights reserved.

     2004 Microsoft Corporation. All rights reserved.

    Copyright   2004 Adobe Systems Incorporated. All rights reserved.

      1995-2004 Eric A. and Kathryn S. Meyer. All Rights Reserved.

    請(qǐng)注意標(biāo)點(diǎn)符號(hào)和大小寫的用法,這也是專業(yè)精神的一種體現(xiàn)。

    現(xiàn)在流行some rights reserved:creativecommons.org

    some rights reserved 和copyright 本身并不矛盾,但是其中的界限更多是一個(gè)道德問題,真正的保留一部分權(quán)力,是指給瀏覽者fair use 的權(quán)利,fair use的界定也決不是隨便亂用,或者抄襲。
    posted @ 2007-09-10 16:15 石正 閱讀(851) | 評(píng)論 (0)編輯 收藏
    測(cè)試視頻時(shí)的笑話:
    HJ對(duì)LCY說:
    你能不能把頭發(fā)“豎(束)”起來。


    posted @ 2007-09-05 11:09 石正 閱讀(271) | 評(píng)論 (0)編輯 收藏
    使計(jì)算機(jī)具有感知到人是否存在的視覺功能,這項(xiàng)技術(shù)就是人臉檢測(cè)
    posted @ 2007-08-28 10:16 石正 閱讀(166) | 評(píng)論 (0)編輯 收藏
    僅列出標(biāo)題
    共12頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
    淺陋見解,僅供參考。拋磚引玉,多加指教!
    主站蜘蛛池模板: 亚洲中文字幕AV在天堂| 亚洲国产成人精品91久久久| 日本zzzzwww大片免费| 在线免费观看国产| 日韩精品免费视频| 51在线视频免费观看视频| 91av免费观看| 久久久久国色AV免费观看性色| 2021免费日韩视频网| 性做久久久久久免费观看| 成年女人毛片免费视频| 白白国产永久免费视频| 可以免费观看的一级毛片| 亚洲无码精品浪潮| 国产亚洲人成无码网在线观看| 色婷婷六月亚洲婷婷丁香| 亚洲国产成+人+综合| 亚洲色偷精品一区二区三区| 国产成人精品久久亚洲高清不卡 | 国产AV无码专区亚洲AV毛网站| 亚洲av无码国产精品夜色午夜| 亚洲国产老鸭窝一区二区三区| 亚洲福利视频网址| 亚洲永久网址在线观看| 老司机免费午夜精品视频| 国产精品成人免费观看| 亚洲精品免费视频| 成人毛片免费在线观看| 亚洲片国产一区一级在线观看 | 亚洲日韩aⅴ在线视频| 亚洲精彩视频在线观看| 亚洲色最新高清av网站| 一级特黄a免费大片| 污污网站免费观看| 免费黄色app网站| 在线观看午夜亚洲一区| 亚洲AV综合色区无码二区偷拍 | 亚洲成AV人片在WWW| 九九热久久免费视频| 亚洲高清视频免费| 免费国产一级特黄久久|