• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

              C++博客 :: 首頁(yè) :: 聯(lián)系 ::  :: 管理
              163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(48)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            積分與排名

            • 積分 - 399102
            • 排名 - 59

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            首先我得說(shuō)我非常喜歡這一章節(jié).Jonathan de Blok使我產(chǎn)生了用OpenGL編寫(xiě)AVI播放器的想法,可那時(shí),我跟本不知如何打開(kāi)AVI文件,更不必說(shuō)去寫(xiě)一個(gè)播放器了.于是我瀏覽了搜藏的編程書(shū)籍,沒(méi)有一本講到AVI文件的.我又閱讀了MSDN上和AVI文件格式有關(guān)的一切內(nèi)容,上面有很多有用的信息,但我需要更多的.
            花了幾小時(shí)在網(wǎng)上搜到AVI范例,只找到兩個(gè)網(wǎng)站.我的搜索技巧不能說(shuō)很棒吧,但99.9%的情況,我能找到我要尋找的東西.了解到AVI范例竟如此之少時(shí),我完全震驚了.大多數(shù)范例并不能編譯通過(guò)...有一些則用了太復(fù)雜的的方法(至少對(duì)我如此),剩下的不錯(cuò),可是用VB,Delphi等寫(xiě)的(不是用vc++).

            找到的第一個(gè)網(wǎng)頁(yè)是Jonathan Nix寫(xiě)的題為"AVI 文件"的文章.網(wǎng)址是http://www.gamedev.net/reference/programming/features/avifile.感謝Jonathan寫(xiě)了這片關(guān)于AVI格式的好文章.雖然我用不同的做法,但他的代碼片斷和清晰的注解讓人學(xué)得很輕松!第二個(gè)網(wǎng)站標(biāo)題為"AVI 總體觀"(John F. McGowan, Ph.D寫(xiě)的)..我可以大肆贊美John的網(wǎng)葉有多么驚奇,但你最好自己去看看.他的網(wǎng)址是http://www.jmcgowan.com/avi.html.這個(gè)網(wǎng)站講到了和AVI格式有關(guān)的幾乎所有內(nèi)容.感謝John做了一個(gè)這么有用的網(wǎng)站.

            最后要提到是我沒(méi)有借鑒任何代碼,沒(méi)有抄襲任何代碼.我的代碼是花了三天時(shí)間了解到上述網(wǎng)站和文章的信息后才寫(xiě)成的.我是想說(shuō)我的代碼也許不是播放AVI文件的最好代碼,他也許不是放AVI文件的正確代碼,但他管用而且使用方便.如果你不喜歡這些代碼和我的編程風(fēng)格,或者覺(jué)得我的言論傷害到整個(gè)編程界,你有以下選擇:1)在網(wǎng)上找到替換的資源2)寫(xiě)自己的AVI播放器3)寫(xiě)一篇更好的文章.任何訪問(wèn)本網(wǎng)站的人現(xiàn)在應(yīng)該知道我只是一名中級(jí)程序員(這一點(diǎn)我在網(wǎng)站里很多文章的開(kāi)頭都提到過(guò))!我編寫(xiě)代碼自樂(lè)而已.本網(wǎng)站的目的在于讓非精英程序員更輕松的開(kāi)始OpenGl編程.這些文章只是關(guān)于我實(shí)現(xiàn)的幾個(gè)特殊的效果...沒(méi)有其他的.

            開(kāi)始講代碼首先你要注意的是我們要包括和連接到視頻頭文件和庫(kù)文件.非常感謝微軟(窩不敢相信我說(shuō)了什么).庫(kù)文件使打開(kāi),播放AVI文件都很簡(jiǎn)便.現(xiàn)在你要知道的是必須包括頭文件vfw.h而且要連接到vfw32.lib庫(kù)文件如果想編譯你的代碼的話:)

             
              

            #include <vfw.h>                            // Video For Windows頭文件
            #include "NeHeGL.h"                        // NeHeGL頭文件

            #pragma comment( lib, "opengl32.lib" )               
            #pragma comment( lib, "glu32.lib" )               
            #pragma comment( lib, "vfw32.lib" )                    // 鏈接到VFW32.lib


            GL_Window*    g_window;
            Keys*        g_keys;

              
             現(xiàn)在定義變量.angle是用來(lái)根據(jù)時(shí)間來(lái)旋轉(zhuǎn)物體的.為簡(jiǎn)單起見(jiàn)我們用angle來(lái)控制所有的旋轉(zhuǎn).
            接下來(lái)是一個(gè)整型變量是用來(lái)計(jì)算經(jīng)過(guò)的時(shí)間(以毫秒計(jì)).它使幀速保持一個(gè)速度.
            后面細(xì)講!
            frame是動(dòng)畫(huà)要顯示的當(dāng)前幀,初始值為0(第一幀).我想如果成功打開(kāi)AVI,他至少有一幀吧,這樣假定比較安全:)
            effect是當(dāng)前屏幕上的效果(有:立方體,球體,圓柱體).env是布爾值.若它為true則環(huán)境映射啟動(dòng),若為假,則物體沒(méi)有環(huán)境映射.若bg為true,你會(huì)看到物體后有全屏的動(dòng)畫(huà);若為假,你只會(huì)看到物體(沒(méi)有背景).
            sp,ep和bp用來(lái)確定使用者沒(méi)有按著鍵不放. 
              

            float        angle;                            // 旋轉(zhuǎn)用
            int        next;                            // 動(dòng)畫(huà)用
            int        frame=0;                            // 幀計(jì)數(shù)器
            int        effect;                            // 當(dāng)前效果
            bool        sp;                            // 空格鍵按下?
            bool        env=TRUE;                            // 環(huán)境映射(默認(rèn)開(kāi))
            bool        ep;                            //’E’ 按下?
            bool        bg=TRUE;                            // 背景(默認(rèn)開(kāi))
            bool        bp;                            // ’B’ 按下?

              
             psi結(jié)構(gòu)體包含AVI文件信息.pavi緩沖的指針,緩沖用來(lái)接受AVI文件打開(kāi)時(shí)的流句柄.pgf是指向GetFrame對(duì)象的指針.bmih在后面的代碼中將被用來(lái)把動(dòng)畫(huà)的每一幀轉(zhuǎn)換為我們需要的格式(保存位圖的頭信息).lastframe保存AVI動(dòng)畫(huà)最后一幀的序號(hào).width和height保存AVI流的維信息,最后...pdata是圖象數(shù)據(jù)的指針(每次在從AVI中獲得一幀后返回).mpf用來(lái)計(jì)算每幀需要多少毫秒.后面細(xì)談這個(gè)變量. 
              

            AVISTREAMINFO        psi;                        // 包含流信息的結(jié)構(gòu)體的指針
            PAVISTREAM        pavi;                        // 流句柄
            PGETFRAME        pgf;                            // GetFrame對(duì)象的指針
            BITMAPINFOHEADER    bmih;                            // 頭信息 For DrawDibDraw
            long            lastframe;                    // 流中最后一幀
            int            width;                        // 視頻寬
            int            height;                        // 視頻高
            char            *pdata;                        // 紋理數(shù)據(jù)指針
            int            mpf;                        // 控制每幀顯示時(shí)間

              
             在本章中我們用GLU庫(kù)創(chuàng)建兩個(gè)二次曲面(球體和圓柱體).quadratic是曲面對(duì)象的指針.
            hdd是DrawDib設(shè)備上下文的句柄.hdc是設(shè)備上下文的句柄.
            hBitmap是設(shè)備無(wú)關(guān)位圖的句柄(在后面位圖轉(zhuǎn)換時(shí)用到).
            data是最后指向轉(zhuǎn)換后位圖的圖象數(shù)據(jù)的指針,在后面的代碼中會(huì)有意義,往下讀:) 
              

            GLUquadricObj *quadratic;                        // 存儲(chǔ)二次曲面對(duì)象

            HDRAWDIB hdd;                            // Dib句柄
            HBITMAP hBitmap;                            // 設(shè)備無(wú)關(guān)位圖的句柄
            HDC hdc = CreateCompatibleDC(0);                    // 創(chuàng)建一個(gè)兼容的設(shè)備上下文
            unsigned char* data = 0;                        // 調(diào)整后的圖象數(shù)據(jù)指針

              
             下面使用到匯編語(yǔ)言.那些從來(lái)沒(méi)有用過(guò)匯編的不要被嚇倒了.他看起來(lái)神秘,實(shí)際上非常簡(jiǎn)單!
            在寫(xiě)本章是我發(fā)現(xiàn)了十分奇怪的事.第一次做出來(lái)的可以播放,但色彩混亂了.本來(lái)是紅色的變成藍(lán)色的了,本來(lái)是藍(lán)色的變成紅色的了.我簡(jiǎn)直要發(fā)狂了!我相信我的代碼某處有問(wèn)題.看了一邊代碼還是找不到bug于是又讀了MSDN.為什么紅色與藍(lán)色互換了!?!MSDN明明說(shuō)24比特位圖是RGB啊!又讀了一些東西,我找到了答案.在WINDOWS圖形系統(tǒng)中,RGB數(shù)據(jù)是倒著存儲(chǔ)的(BGR).而在OpenGL中,要用的RGB數(shù)據(jù)就是RGB的順序!

            在抱怨了微軟之后:)我決定加一條注解!我不因?yàn)镽GB數(shù)據(jù)倒過(guò)來(lái)存放而打算罵微軟.只是覺(jué)得很奇怪--他叫做RGB實(shí)際上在文件中是按BGR存的!

            另:這一點(diǎn)和"little endian"和"big endian"有關(guān).Intel以及Intel兼容產(chǎn)品用little endian--LSB(數(shù)據(jù)最低位)首先存.OpenGL是產(chǎn)生于Silicon Graphics的機(jī)器的,用的是big endian,所以標(biāo)準(zhǔn)的OpenGL要位圖格式是big endian格式.這是我的理解.

            棒極了!所以說(shuō)這第一個(gè)播放器就是一個(gè)垃圾!我的解決方法是用一個(gè)循環(huán)把數(shù)據(jù)交換過(guò)來(lái).這能行,但太慢.我又在紋理生成代碼中用GL_BGR_EXT代替了GL_RGB,速度暴升,色彩顯示也對(duì)了!問(wèn)題解決了...原來(lái)我是這樣想!后來(lái)發(fā)現(xiàn)一些OpenGL驅(qū)動(dòng)不支持GL_BGR... :(

            與好友Maxwell Sayles討論后,他推薦我用匯編代碼來(lái)交換數(shù)據(jù).一分鐘后,他用icq發(fā)來(lái)下面的代碼!也許不是最優(yōu)化的,但他很快也很有效!

            動(dòng)畫(huà)的每一幀存在一個(gè)緩沖里.圖象256像素寬,256像素高,每個(gè)色彩一字節(jié)(一像素3字節(jié)).下面的代碼會(huì)掃描整個(gè)緩沖并交換紅與藍(lán)的字節(jié).紅存在ebx+0,藍(lán)存在ebx+2.我們一次向前走3字節(jié)(因?yàn)橐粋€(gè)像素3字節(jié)).不斷掃描直到所有數(shù)據(jù)交換過(guò)來(lái).

            你們有些人不喜歡用匯編代碼,所以我想有必要在本章里解釋一下.本來(lái)計(jì)劃用GL_BGR_EXT,他管用,但不是所有的顯卡都支持!我又用異或交換法,這在所有機(jī)器上都是有效的,但不十分快.用了匯編后速度相當(dāng)快.考慮到我們?cè)谔幚韺?shí)時(shí)視頻,你需要最快的交換方法.權(quán)衡了以上選擇,匯編是最好的!如果你有更好的辦法,就用你自己的吧!我并不是告訴你必須如何去做,只是告訴你我的做法.我也會(huì)細(xì)致的解釋代碼.如果你要用更好的代碼來(lái)作替換,你要清楚這些代碼是來(lái)干什么的,自己寫(xiě)代碼時(shí),要為日后的優(yōu)化提供方便.

             
              

            void flipIt(void* buffer)                        // 交換紅藍(lán)數(shù)據(jù)(256x256)
            {
                void* b = buffer;                        // 緩沖指針
                __asm                            // 匯編代碼
                {
                    mov ecx, 256*256                    // 設(shè)置計(jì)數(shù)器
                    mov ebx, b                    // ebx存數(shù)據(jù)指針
                    label:                        // 循環(huán)標(biāo)記
                        mov al,[ebx+0]                // 把ebx位置的值賦予al
                        mov ah,[ebx+2]                // 把ebx+2位置的值賦予ah
                        mov [ebx+2],al                // 把a(bǔ)l的值存到ebx+2的位置
                        mov [ebx+0],ah                // 把a(bǔ)h的值存到ebx+0的位置

                        add ebx,3                    // 向前走3個(gè)字節(jié)
                        dec ecx                    // 循環(huán)計(jì)數(shù)器減1
                        jnz label                    // ecx非0則跳至label
                }
            }

              
             下面的代碼以只讀方式打開(kāi)AVI文件.szFile是打開(kāi)文件的名字.title[100]用來(lái)修改window標(biāo)題(顯示AVI文件信息).
            首先調(diào)用AVIFileInit().他初始化AVI文件庫(kù)(使東西能用?鵠?).

            打開(kāi)AVI文件有很多方法.我采用AVIStreamOpenFromFile(...).他能打開(kāi)AVI文件中單獨(dú)一個(gè)流(AVI文件可以包含多個(gè)流).它的參數(shù)如下:pavi是接收流句柄的緩沖的指針,szFile是打開(kāi)文件的名字(包括路徑).第三參數(shù)是打開(kāi)的流的類型.在這個(gè)工程里,我們只對(duì)視頻流感興趣(streamtypeVIDEO).第四參數(shù)是0,這表示我們需要第一次讀到的視頻流(一個(gè)AVI文件里會(huì)有多個(gè)視頻流,我們要第一個(gè)).OF_READ表示以只讀方式打開(kāi)文件.最后一個(gè)參數(shù)是一個(gè)類標(biāo)識(shí)句柄的指針.說(shuō)實(shí)話,我也不清楚他是干嗎的.我讓windows自己設(shè)定,于是把NULL傳過(guò)去.

             
              

            void OpenAVI(LPCSTR szFile)                        // 打開(kāi)AVI文件szFile
            {
                TCHAR    title[100];                    // 包含修改了的window標(biāo)題

                AVIFileInit();                        // 打開(kāi)AVI文件庫(kù)

                // 打開(kāi)AVI流
                if (AVIStreamOpenFromFile(&pavi, szFile, streamtypeVIDEO, 0, OF_READ, NULL) !=0)
                {
                    // 打開(kāi)流時(shí)的出錯(cuò)處理
                    MessageBox (HWND_DESKTOP, "打開(kāi)AVI流失敗", "錯(cuò)誤", MB_OK | MB_ICONEXCLAMATION);
                }

              
             到目前為止,我們假定文件被正確打開(kāi),流被正確定位!然后用AVIStreamInfo(...)從AVI文件里抓取一些信息.
            先前我們創(chuàng)建了叫psi的結(jié)構(gòu)體來(lái)保存AVI流的信息.下面第一行,我們把AVI信息填入該結(jié)構(gòu)體.從流的寬度(以像素計(jì))到動(dòng)畫(huà)的幀速等所有的信息都會(huì)存到psi中.那些想要精確控制播放速度的要記住我剛才說(shuō)的.更多的信息參閱MSDN.

            我們通過(guò)右邊位置減左邊位置算出幀寬.這個(gè)結(jié)果是以像素記的精確的幀寬.至于高度,可以用底邊位置減頂邊位置得到.這樣得到高度的像素值.

            然后用AVIStreamLength(...)得到AVI文件最后一幀的序號(hào).AVIStreamLength(...)返回動(dòng)畫(huà)最后一幀的序號(hào).結(jié)果存在lastframe里.

            計(jì)算幀速很簡(jiǎn)單.每秒幀速(fps)= psi.dwRate/psi,dwScale.返回的值應(yīng)該匹配顯示幀的速度(你在AVI動(dòng)畫(huà)中右擊鼠標(biāo)可以看到).你會(huì)問(wèn)那么這和mpf有什么關(guān)系呢?第一次寫(xiě)這個(gè)代碼時(shí),我試著用fps來(lái)選擇動(dòng)畫(huà)了正確的幀面.我遇到一個(gè)問(wèn)題...視頻放的太快!于是我看了一下視頻屬性.face2.avi文件有3.36秒長(zhǎng).幀速是29.974fps.視頻動(dòng)畫(huà)共有91幀.而3.36*29.974 = 100.71.非常奇怪!!

            所以我采用一些不同的方法.不是計(jì)算幀速,我計(jì)算每一幀播放所需時(shí)間.AVIStreamSampleToTime()把在動(dòng)畫(huà)中的位置轉(zhuǎn)換位你到達(dá)該位置所需的時(shí)間(毫秒計(jì)).所以通過(guò)計(jì)算到達(dá)最后一幀的時(shí)間就得到整個(gè)動(dòng)畫(huà)的播放時(shí)間.再拿這個(gè)結(jié)果除以動(dòng)畫(huà)總幀數(shù)(lastframe).這樣就給出了每幀的顯示時(shí)間(毫秒計(jì)).結(jié)果存在mpf(milliseconds per frame)里.你也能通過(guò)獲取動(dòng)畫(huà)中一幀的時(shí)間來(lái)算每幀的毫秒數(shù),代碼為:AVIStreamSampleToTime(pavi,1).兩種方法都不錯(cuò)!非常感謝Albert Chaulk提供思路!

            我說(shuō)每幀的毫秒數(shù)不精確是因?yàn)閙pf是一個(gè)整型值,所以所有的浮點(diǎn)數(shù)都會(huì)被取整.

             
              

                AVIStreamInfo(pavi, &psi, sizeof(psi));            // 把流信息讀進(jìn)psi
                width=psi.rcFrame.right-psi.rcFrame.left;            // 寬度為右邊減左邊
                height=psi.rcFrame.bottom-psi.rcFrame.top;            // 高為底邊減頂邊

                lastframe=AVIStreamLength(pavi);                // 最后一幀的序號(hào)

                mpf=AVIStreamSampleToTime(pavi,lastframe)/lastframe;        // mpf的不精確值

              
             因?yàn)镺penGL需要紋理數(shù)據(jù)是2的冪,而大多視頻是160*120,320*240等等,所以需要一種把視頻格式重調(diào)整為能用作紋理的格式.我們可利用Windows Dib函數(shù)去做.
            首先要做的是描述我們想要的圖像的類型.于是我們要以所需參數(shù)填好bmih這個(gè)BitmapInfoHeader結(jié)構(gòu).
            首先設(shè)定該結(jié)構(gòu)體的大小.再把位平面數(shù)設(shè)為1.3字節(jié)的數(shù)據(jù)有24比特(RGB).要使圖像位256像素寬,256像素高,最后要讓數(shù)據(jù)返回為UNCOMPRESSED(非壓縮)的RGB數(shù)據(jù)(BI_RGB).

            CreateDIBSection創(chuàng)建一個(gè)可直接寫(xiě)的設(shè)備無(wú)關(guān)位圖(dib).如果一切順利,hBitmap會(huì)指向該dib的比特值.hdc是設(shè)備上下文(DC)的句柄第二參數(shù)是BitmapInfo結(jié)構(gòu)體的指針.該結(jié)構(gòu)體包含了上述dib文件的信息.第三參數(shù)(DIB_RGB_COLORS)設(shè)定數(shù)據(jù)是RGB值.data是指向DIB比特值位置的指針的指針(嗚,真繞口).第五參數(shù)設(shè)為NULL,我們的DIB已被分配好內(nèi)存.末了,最后一個(gè)參數(shù)可忽略(設(shè)為NULL).

            引自MSDN:SelecObject函數(shù)選一個(gè)對(duì)象進(jìn)入設(shè)備上下文(DC).

            現(xiàn)在我們建好一個(gè)能直接寫(xiě)的DIB,yeah:)

             
              

                bmih.biSize        = sizeof (BITMAPINFOHEADER);        // BitmapInfoHeader的大小
                bmih.biPlanes        = 1;                    // 位平面
                bmih.biBitCount        = 24;                    //比特格式(24 Bit, 3 Bytes)
                bmih.biWidth        = 256;                    // 寬度(256 Pixels)
                bmih.biHeight        = 256;                    // 高度 (256 Pixels)
                bmih.biCompression    = BI_RGB;                        // 申請(qǐng)的模式 = RGB

                hBitmap = CreateDIBSection (hdc, (BITMAPINFO*)(&bmih), DIB_RGB_COLORS, (void**)(&data), NULL, NULL);
                SelectObject (hdc, hBitmap);                    // 選hBitmap進(jìn)入設(shè)備上下文(hdc)

              
             在從AVI中讀取幀面前還有幾件事要做.接下來(lái)使程序做好從AVI文件中解出幀面的準(zhǔn)備.用AVIStreamGetFrameOpen(...)函數(shù)做這一點(diǎn).
            你能給這個(gè)函數(shù)傳一個(gè)結(jié)構(gòu)體作為第二參數(shù)(它會(huì)返回一個(gè)特定的視頻格式).糟糕的是,你能改變的唯一數(shù)據(jù)是返回的圖像的寬度和高度.MSDN也提到能傳AVIGETFRAMEF_BESTDISPLAYFMT為參數(shù)來(lái)選擇一個(gè)最佳顯示格式.奇怪的是,我的編譯器沒(méi)有定義這玩藝兒.

            如果一切順利,一個(gè)GETFRAME對(duì)象被返回(用來(lái)讀幀數(shù)據(jù)).有問(wèn)題的話,提示框會(huì)出現(xiàn)在屏幕上告訴你有錯(cuò)誤!

             
              

                pgf=AVIStreamGetFrameOpen(pavi, NULL);                // 用要求的模式建PGETFRAME
                if (pgf==NULL)
                {
                    // 解幀出錯(cuò)
                    MessageBox (HWND_DESKTOP, "不能打開(kāi)AVI幀", "錯(cuò)誤", MB_OK | MB_ICONEXCLAMATION);
                }

              
             下面的代碼把視頻寬,高和幀數(shù)傳給window標(biāo)題.用函數(shù)SetWindowText(...)在window頂部顯示標(biāo)題.以窗口模式運(yùn)行程序看看以下代碼的作用. 
              

                // bt標(biāo)題欄信息(寬 / 高/ 幀數(shù))
                wsprintf (title, "NeHe's AVI Player: Width: %d, Height: %d, Frames: %d", width, height, lastframe);
                SetWindowText(g_window->hWnd, title);                // 修改標(biāo)題欄
            }

              
             下面是有趣的東西...從AVI中抓取一幀,把它轉(zhuǎn)為大小和色深可用的圖象.lpbi包含一幀的BitmapInfoHeader信息.我們?cè)谙旅娴诙型瓿闪藥准?先是抓了動(dòng)畫(huà)的一幀...我們需要的幀面由這些幀確定.這會(huì)讓動(dòng)畫(huà)走掉這一幀,lpbi會(huì)指向這一幀的頭信息.
            下面是有趣的東西...我們要指向圖像數(shù)據(jù)了.要跳過(guò)頭信息(lpbi->biSize).一件事直到寫(xiě)本文時(shí)我才意識(shí)到:也要跳過(guò)任何的色彩信息.所以要跳過(guò)biClrUsed*sizeof(RGBQUAD)(譯者:我想他是說(shuō)要跳過(guò)調(diào)色板信息).做完這一切,我們就得到圖像數(shù)據(jù)的指針了(pdata).

            也要把動(dòng)畫(huà)的每一幀的大小轉(zhuǎn)為紋理能用的大小,還要把數(shù)據(jù)轉(zhuǎn)為RGB數(shù)據(jù).這用到DrawDibDraw(...).

            一個(gè)大概的解釋.我們能直接寫(xiě)設(shè)定的DIB圖像.那就是DrawDibDraw(...)所做的.第一參數(shù)是DrawDib DC的句柄.第二參數(shù)是DC的句柄.接下來(lái)用左上角(0,0)和右下角(256,256)構(gòu)成目標(biāo)矩形.

            lpbi指向剛讀的幀的bitmapinfoheader信息.pdata是剛讀的幀的圖像數(shù)據(jù)指針.

            再把源圖象(剛讀的幀)的左上角設(shè)為(0,0),右下角設(shè)為(幀寬,幀高).最后的參數(shù)應(yīng)設(shè)為0.

            這個(gè)方法可把任何大小、色深的圖像轉(zhuǎn)為256*256*24bit的圖像.

             
              

            void GrabAVIFrame(int frame)                        // 從流中抓取一幀
            {
                LPBITMAPINFOHEADER lpbi;                        // 存位圖的頭信息
                lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(pgf, frame);        // 從AVI流中得到數(shù)據(jù)
                pdata=(char *)lpbi+lpbi->biSize+lpbi->biClrUsed * sizeof(RGBQUAD);    // 數(shù)據(jù)指針,由AVIStreamGetFrame返回(跳過(guò)頭
            //信息和色彩信息)
            // 把數(shù)據(jù)轉(zhuǎn)為所需格式
                DrawDibDraw (hdd, hdc, 0, 0, 256, 256, lpbi, pdata, 0, 0, width, height, 0);

              
             我們得到動(dòng)畫(huà)的每幀數(shù)據(jù)(紅藍(lán)數(shù)據(jù)顛倒的).為解決這個(gè)問(wèn)題,我們的高速代碼flipIt(...).記住,data是指向DIB比特值位置的指針的指針變量.這意味著調(diào)用DrawDibDraw后,data指向一個(gè)調(diào)整過(guò)大小(256*256),修改過(guò)色深(24bits)的位圖數(shù)據(jù).
            原來(lái)我通過(guò)重建動(dòng)畫(huà)的每一幀來(lái)更新紋理.我收到幾封email建議我用glTexSubImage2D().翻閱了OpenGL紅寶書(shū)后,我磕磕絆絆的寫(xiě)出下面注釋:"創(chuàng)建紋理的計(jì)算消耗比修改紋理要大.在OpenGL1.1版本中,有幾條調(diào)用能更新全部或部分紋理圖像信息.這對(duì)某些應(yīng)用程序有用,比如實(shí)時(shí)的抓取視頻圖像作紋理.對(duì)于這些程序,用glTexSubImage2D()根據(jù)新視頻圖像來(lái)創(chuàng)建單個(gè)紋理以代替舊的紋理數(shù)據(jù)是行得通的."

            在我個(gè)人并沒(méi)有發(fā)現(xiàn)速度明顯加快,也許在低端顯卡上才會(huì).glTexSubImage2D()的參數(shù)是:目標(biāo)是一個(gè)二維紋理(GL_TEXTURE_2D).細(xì)節(jié)級(jí)別(0),mipmapping用.x(0),y(0)告訴OpenGL開(kāi)始拷貝的位置(0,0是紋理的左下角).然后是圖像的寬度,我們要拷貝的圖像是256像素寬,256像素高.GL_RGB是我們的數(shù)據(jù)格式.我們?cè)诳截悷o(wú)符號(hào)byte.最后...圖像數(shù)據(jù)指針----data.非常簡(jiǎn)單!

            Kevin Rogers 另加:我想指出使用glTexSubImage2D()另一個(gè)重要原因.不僅因?yàn)樵谠S多OpenGL實(shí)現(xiàn)中它很快,還因?yàn)槟繕?biāo)區(qū)不必是2的冪.這對(duì)視頻重放很方便,因?yàn)橐粠木S通常不是2的冪(而是像320*200之類的).這樣給了你很大機(jī)動(dòng)性,你可以按視頻流原本的樣子播放,而不是扭曲或剪切每一幀來(lái)適應(yīng)紋理的維.

            重要的是你不能更新一個(gè)紋理如果你第一次沒(méi)有創(chuàng)建他!我們?cè)贗nitialize()中創(chuàng)建紋理.

            還要提到的是...如果你計(jì)劃在工程里使用多個(gè)紋理,務(wù)必綁住你要更新的紋理.否則,更新出來(lái)的紋理也許不是你想要的!

             
              

                flipIt(data);                            // 交換紅藍(lán)數(shù)據(jù)

                // 更新紋理
                glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 256, 256, GL_RGB, GL_UNSIGNED_BYTE, data);
            }

              
             接下來(lái)的部分當(dāng)程序退出時(shí)調(diào)用,我們關(guān)掉DrawDib DC,釋放占用的資源.然后釋放AVI GetFrame資源.最后釋放AVI流和文件. 
              

            void CloseAVI(void)                            // 關(guān)掉AVI資源
            {
                DeleteObject(hBitmap);                        //釋放設(shè)備無(wú)關(guān)位圖信息
                DrawDibClose(hdd);                            // 關(guān)掉DrawDib DC
                AVIStreamGetFrameClose(pgf);                    // 釋放AVI GetFrame資源
                AVIStreamRelease(pavi);                        // 釋放AVI流
                AVIFileExit();                            // 釋放AVI文件
            }

              
             初始化很簡(jiǎn)明.設(shè)初始的angle為0.再打開(kāi)DrawDib庫(kù)(得到一個(gè)DC).一切順利的話,hdd會(huì)是新創(chuàng)建的dc的句柄.
            以黑色清屏,開(kāi)啟深度測(cè)試,等等.

            然后建一個(gè)新的二次曲面.quadratic是這個(gè)新對(duì)象的指針.設(shè)置光滑的法線,允許紋理坐標(biāo)的生成.

             
              

            BOOL Initialize (GL_Window* window, Keys* keys)
            {
                g_window    = window;
                g_keys        = keys;

                // 開(kāi)始用戶的初始
                angle = 0.0f;                            // angle為0先
                hdd = DrawDibOpen();                        // 得到Dib的DC
                glClearColor (0.0f, 0.0f, 0.0f, 0.5f);                // 黑色背景
                glClearDepth (1.0f);                        // 深度緩沖初始
                glDepthFunc (GL_LEQUAL);                        // 深度測(cè)試的類型(小于或等于)
                glEnable(GL_DEPTH_TEST);                        // 開(kāi)啟深度測(cè)試
                glShadeModel (GL_SMOOTH);                        // 平滑效果
                glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);            // 透視圖計(jì)算設(shè)為 //最高精度

                quadratic=gluNewQuadric();                        // 建二次曲面的指針
                gluQuadricNormals(quadratic, GLU_SMOOTH);                // 設(shè)置光滑的法線
                gluQuadricTexture(quadratic, GL_TRUE);                // 創(chuàng)建紋理坐標(biāo)

              
             下面的代碼中,我們開(kāi)啟2D紋理映射,紋理濾鏡設(shè)為GLNEAREST(最快,但看起來(lái)很糙),建立球面映射(為了實(shí)現(xiàn)環(huán)境映射效果).試試其它濾鏡,如果你有條件,可以試試GLLINEAR得到一個(gè)平滑的動(dòng)畫(huà)效果.
            設(shè)完紋理和球面映射,我們打開(kāi).AVI文件.我盡量使事情簡(jiǎn)單化...你能看出來(lái)么:)我們要打開(kāi)的文件叫作facec2.avi

             
              

                glEnable(GL_TEXTURE_2D);                    // 開(kāi)啟2D紋理映射
                glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);// 設(shè)置紋理濾鏡
                glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

                glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);        // 設(shè)紋理坐標(biāo)生成模式為s
                glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);        // 設(shè)紋理坐標(biāo)生成模式為t

                OpenAVI("data/face2.avi");                    // 打開(kāi)AVI文件

                // 創(chuàng)建紋理
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

                return TRUE;                        // 初始化成功返回TRUE
            }

              
             關(guān)閉時(shí)調(diào)用CloseAVI().他正確的關(guān)閉AVI文件,并釋放所有占用資源. 
              

            void Deinitialize (void)                        // 做所有的釋放工作
            {
                CloseAVI();                        // 關(guān)閉AVI文件
            }

              
             到了檢查按鍵和更新旋轉(zhuǎn)角度的地方了.我知道再?zèng)]有必要詳細(xì)解釋這些代碼了.我們檢查空格鍵是否按下,若是,則增加effect值.有3種效果(立方,球,圓柱)第四個(gè)效果被選時(shí)(effect = 3)不畫(huà)任何對(duì)象...僅顯示背景!如果選了第四效果,空格又按下了,就重設(shè)為第一個(gè)效果(effect = 0).Yeah,我本該叫他對(duì)象:)
            然后檢查’b’鍵是否按下,若是,則改變背景(bg從ON到OFF或從OFF到ON).

            環(huán)境映射的鍵設(shè)置也一樣.檢查’E’是否按下,若是則改變env從TRUE到FALSE或從FALSE到TRUE.僅僅是關(guān)閉或開(kāi)啟環(huán)境映射!

            每次調(diào)用Updata()時(shí)angle都加上一個(gè)小分?jǐn)?shù).我用經(jīng)過(guò)的時(shí)間除以60.0f使速度降一點(diǎn).

             
              

            void Update (DWORD milliseconds)                    // 動(dòng)畫(huà)更新
            {
                if (g_keys->keyDown [VK_ESCAPE] == TRUE)            //ESC按下?
                {
                    TerminateApplication (g_window);            // 關(guān)閉程序
                }

                if (g_keys->keyDown [VK_F1] == TRUE)                // F1按下?
                {
                    ToggleFullscreen (g_window);            // 改變顯示模式
                }

                if ((g_keys->keyDown [' ']) && !sp)                // 空格按下并已松開(kāi)
                {
                    sp=TRUE;                        // 設(shè)sp為T(mén)rue
                    effect++;                        // 增加effect
                    if (effect>3)                    // 超出界限?
                        effect=0;                    // 重設(shè)為0
                }

                if (!g_keys->keyDown[' '])                    // 空格沒(méi)按下?
                    sp=FALSE;                        // 設(shè)sp為False

                if ((g_keys->keyDown ['B']) && !bp)                // ’B’按下并已松開(kāi)
                {
                    bp=TRUE;                        // 設(shè)bp為T(mén)rue
                    bg=!bg;                        // 改變背景 Off/On
                }

                if (!g_keys->keyDown['B'])                    // ’B’沒(méi)按下?
                    bp=FALSE;                        // 設(shè)bp為False

                if ((g_keys->keyDown ['E']) && !ep)                //  ’E’按下并已松開(kāi)
                {
                    ep=TRUE;                        // 設(shè)ep為T(mén)rue
                    env=!env;                        // 改變環(huán)境映射 Off/On
                }

                if (!g_keys->keyDown['E'])                    //’E’沒(méi)按下
                    ep=FALSE;                        // 設(shè)ep為False

                angle += (float)(milliseconds) / 60.0f;            // 根據(jù)時(shí)間更新angle

              
             在原來(lái)的文章里,所有的AVI文件都以相同的速度播放.于是,我重寫(xiě)了本文讓視頻以正常的速度播放.next增加經(jīng)過(guò)的毫秒數(shù).如果你記得文章的前面,我們算出了顯示每幀的毫秒數(shù)(mpf).為了計(jì)算當(dāng)前幀,我們拿經(jīng)過(guò)的時(shí)間除以顯示每幀的毫秒數(shù)(mpf).
            還要檢查確定當(dāng)前幀沒(méi)有超過(guò)視頻的最后幀.若超過(guò)了,則將frame設(shè)為0,動(dòng)畫(huà)計(jì)時(shí)器設(shè)為0,于是動(dòng)畫(huà)從頭開(kāi)始.

            下面的代碼會(huì)丟掉一些幀,若果你的計(jì)算機(jī)太慢的話,
            或者另一個(gè)程序占用了CPU.如果想顯示每一幀而不管計(jì)算機(jī)有多慢的話,你要檢查next是否比mpf大,若是,你要把next設(shè)為0,frame增1.兩種方法都行,雖然下面的代碼更有利于跑的快的機(jī)器.

            如果你有干勁,試著加上循環(huán),快速播放,暫停或倒放等功能.

             
              

                next+= milliseconds;                        // 根據(jù)時(shí)間增加next
                frame=next/mpf;                            // 計(jì)算當(dāng)前幀號(hào)

                if (frame>=lastframe)                        // 超過(guò)最后一幀?
                {
                    frame=0;                            // Frame設(shè)為0
                    next=0;                            // 重設(shè)動(dòng)畫(huà)計(jì)時(shí)器
                }
            }

              
             下面是畫(huà)屏代碼:)我們清屏和深度緩沖.再抓取動(dòng)畫(huà)的一幀.我將使這更簡(jiǎn)單!把你想要的幀數(shù)傳給GrabAVIFrame().非常簡(jiǎn)單!當(dāng)然,如果是多個(gè)AVI,你要傳一個(gè)紋理標(biāo)號(hào).(你要做更多的事) 
              

            void Draw (void)                            // 繪制我們的屏幕
            {
                glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // 清屏和深度緩沖

                GrabAVIFrame(frame);                    // 抓取動(dòng)畫(huà)的一幀

              
             下面檢查我們是否想畫(huà)一個(gè)背景圖.若bg是TRUE,重設(shè)模型視角矩陣,畫(huà)一個(gè)單紋理映射的能蓋住整個(gè)屏幕的矩形(紋理是從AVI從得到的一幀).矩形距離屏面向里20個(gè)單位,這樣它看起來(lái)在對(duì)象之后(距離更遠(yuǎn)). 
              

                if (bg)                            // 背景可見(jiàn)?
                {
                    glLoadIdentity();                    // 重設(shè)模型視角矩陣
                    glBegin(GL_QUADS);                    // 開(kāi)始畫(huà)背景(一個(gè)矩形)
                        // 正面
                        glTexCoord2f(1.0f, 1.0f); glVertex3f( 11.0f,  8.3f, -20.0f);
                        glTexCoord2f(0.0f, 1.0f); glVertex3f(-11.0f,  8.3f, -20.0f);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f(-11.0f, -8.3f, -20.0f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f( 11.0f, -8.3f, -20.0f);
                    glEnd();                       
                }

              
             畫(huà)完背景(或沒(méi)有),重設(shè)模型視角矩陣(使視角中心回到屏幕中央).視角中心再向屏內(nèi)移進(jìn)10個(gè)單位.然后檢查env是否為T(mén)RUE.若是,開(kāi)啟球面映射來(lái)實(shí)現(xiàn)環(huán)境映射效果.
             
              

                glLoadIdentity ();                        // 重設(shè)模型視角矩陣
                glTranslatef (0.0f, 0.0f, -10.0f);                // 視角中心再向屏內(nèi)移進(jìn)10個(gè)單位

                if (env)                            // 環(huán)境映射開(kāi)啟?
                {
                    glEnable(GL_TEXTURE_GEN_S);                // 開(kāi)啟紋理坐標(biāo)生成S坐標(biāo)
                    glEnable(GL_TEXTURE_GEN_T);                // 開(kāi)啟紋理坐標(biāo)生成T坐標(biāo)
                }

              
             在最后關(guān)頭我加了以下代碼.他繞X軸和Y軸旋轉(zhuǎn)(根據(jù)angle的值)然后在Z軸方向移動(dòng)2單位.這使我們離開(kāi)了屏幕中心.如果刪掉下面三行,對(duì)象會(huì)在屏幕中心打轉(zhuǎn).有了下面三行,對(duì)象旋轉(zhuǎn)時(shí)看起來(lái)離我們遠(yuǎn)一些:)
            如果你不懂旋轉(zhuǎn)和平移...你就不該讀這一章:)

             
              

                glRotatef(angle*2.3f,1.0f,0.0f,0.0f);                // 加旋轉(zhuǎn)讓東西動(dòng)起來(lái)
                glRotatef(angle*1.8f,0.0f,1.0f,0.0f);                // 加旋轉(zhuǎn)讓東西動(dòng)起來(lái)
                glTranslatef(0.0f,0.0f,2.0f);                    // 旋轉(zhuǎn)后平移到新位置

              
             下面的代碼檢查我們要畫(huà)哪一個(gè)對(duì)象.若effect為0,我們做一些旋轉(zhuǎn)在畫(huà)一個(gè)立方體.這個(gè)旋轉(zhuǎn)使立方體繞X,Y,Z軸旋轉(zhuǎn).現(xiàn)在你腦中該烙下建一個(gè)立方體的方法了吧:) 
              

                switch (effect)                            // 哪個(gè)效果?
                {
                case 0:                                // 效果 0 - 立方體
                    glRotatef (angle*1.3f, 1.0f, 0.0f, 0.0f);       
                    glRotatef (angle*1.1f, 0.0f, 1.0f, 0.0f);       
                    glRotatef (angle*1.2f, 0.0f, 0.0f, 1.0f);       
                    glBegin(GL_QUADS);               
                        glNormal3f( 0.0f, 0.0f, 0.5f);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
                        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
                        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
                       
                        glNormal3f( 0.0f, 0.0f,-0.5f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
                        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
                        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
                   
                        glNormal3f( 0.0f, 0.5f, 0.0f);
                        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
                        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
                       
                        glNormal3f( 0.0f,-0.5f, 0.0f);
                        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
                        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
                   
                        glNormal3f( 0.5f, 0.0f, 0.0f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
                        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
                        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
                   
                        glNormal3f(-0.5f, 0.0f, 0.0f);
                        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
                        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
                        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
                        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
                    glEnd();                       
                    break;                       
              
             下面是畫(huà)球體的地方.開(kāi)始先繞X,Y,Z軸旋轉(zhuǎn),再畫(huà)球體.球體半徑為1.3f,20經(jīng)線,20緯線.我用20是因?yàn)槲覜](méi)打算讓球體非常光滑.少用些經(jīng)緯數(shù),使球看起來(lái)不那么光滑,這樣球轉(zhuǎn)起來(lái)時(shí)就能看到球面映射的效果(當(dāng)然球面映射必須開(kāi)啟).試著嘗試其它值!要知道,使用更多的經(jīng)緯數(shù)需要更強(qiáng)的計(jì)算能力! 
              

                case 1:                                // 效果1,球體
                    glRotatef (angle*1.3f, 1.0f, 0.0f, 0.0f);       
                    glRotatef (angle*1.1f, 0.0f, 1.0f, 0.0f);       
                    glRotatef (angle*1.2f, 0.0f, 0.0f, 1.0f);       
                    gluSphere(quadratic,1.3f,20,20);           
                    break;                           
              
             下面畫(huà)圓柱.開(kāi)始先繞X,Y,Z軸旋轉(zhuǎn),圓柱頂和底的半徑都為1.0f.高3.0f,32經(jīng)線,32緯線.若減少經(jīng)緯數(shù),圓柱的組成多邊形會(huì)減少,他看起來(lái)就沒(méi)那么圓. 
              

                case 2:                                // 效果2,圓柱
                    glRotatef (angle*1.3f, 1.0f, 0.0f, 0.0f);       
                    glRotatef (angle*1.1f, 0.0f, 1.0f, 0.0f);       
                    glRotatef (angle*1.2f, 0.0f, 0.0f, 1.0f);       
                    glTranslatef(0.0f,0.0f,-1.5f);               
                    gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);       
                    break;                           
                }

              
             下面檢查env是否為T(mén)RUE,若是,關(guān)閉球面映射.調(diào)用glFlush()清空渲染流水線(使在下一幀開(kāi)始前一切都渲染了). 
              

                if (env)                                // 是否開(kāi)啟了環(huán)境渲染
                {
                    glDisable(GL_TEXTURE_GEN_S);                // 關(guān)閉紋理坐標(biāo)S
                    glDisable(GL_TEXTURE_GEN_T);                // 關(guān)閉紋理坐標(biāo)T
                }

                glFlush ();                            // 清空渲染流水線
            }

              
             希望你們喜歡這一章.現(xiàn)在已經(jīng)凌晨?jī)牲c(diǎn)了(譯者oak:譯到這時(shí)剛好也是2:00am!)...寫(xiě)這章花了我6小時(shí)了.聽(tīng)起來(lái)不可思議,可要把東西寫(xiě)通不是件容易的事.本文我讀了三邊,我力圖使文章好懂.不管你信還是不信,對(duì)我最重要的是你們能明白代碼是怎樣運(yùn)作的,它為什么能行.那就是我喋喋不休并且加了過(guò)量注解的原因.
            無(wú)論如何,我都想聽(tīng)到本文的反饋.如果你找到文章的錯(cuò)誤,并想幫我做一些改進(jìn),請(qǐng)聯(lián)系我.就像我說(shuō)的那樣,這是我第一次寫(xiě)和AVI有關(guān)的代碼.通常我不會(huì)寫(xiě)一個(gè)我才接觸到的主題,但我太興奮了,并且考慮到關(guān)于這方面的文章太少了.我所希望的是,我打開(kāi)了編寫(xiě)高質(zhì)量AVI demo和代碼的一扇門(mén)!也許成功,也許沒(méi)有.不管怎樣,你可以任意處理我的代碼.

            非常感謝 Fredster提供face AVI文件.Face是他發(fā)來(lái)的六個(gè)AVI動(dòng)畫(huà)中的一個(gè).他沒(méi)提出任何問(wèn)題和條件.他以他的方式幫助了我,謝謝他!

            更要感謝Jonathan de Blok,要沒(méi)要她,本文就不會(huì)有.他給我發(fā)來(lái)他的AVI播放器的代碼,這使我對(duì)AVI格式產(chǎn)生了興趣.他也回答了我問(wèn)的關(guān)于他的代碼的問(wèn)題.但重要的是我并沒(méi)有借鑒或抄襲他的代碼,他的代碼只是幫助我理解AVI播放器的運(yùn)行機(jī)制.我的播放器的打開(kāi),解幀和播放AVI文件用的是不同的代碼!

            感謝給予幫助的所有人,包括所有參觀者!若沒(méi)有你們,我的網(wǎng)站不值一文!!!

             
             
            posted on 2007-12-24 16:18 sdfasdf 閱讀(1550) 評(píng)論(0)  編輯 收藏 引用 所屬分類: OPENGL
            激情综合色综合久久综合| 91久久国产视频| 久久久久无码中| 丁香五月综合久久激情| 久久久91精品国产一区二区三区| 日本久久久久亚洲中字幕| 99久久99久久精品国产片果冻 | 欧美精品国产综合久久| 久久成人18免费网站| 久久黄视频| 欧美久久综合九色综合| 日日狠狠久久偷偷色综合免费| 久久99久久成人免费播放| 久久人人爽人人爽AV片| 久久这里有精品视频| 亚洲精品视频久久久| 色妞色综合久久夜夜| 亚洲va中文字幕无码久久不卡| 久久综合香蕉国产蜜臀AV| 国内精品久久久久久久97牛牛| 久久精品国产久精国产| 国产精品热久久无码av| 精品久久久久久无码中文野结衣| 日日狠狠久久偷偷色综合96蜜桃| 久久久亚洲欧洲日产国码是AV| 少妇高潮惨叫久久久久久| 狠色狠色狠狠色综合久久| 国产精品99久久不卡| 久久综合成人网| 7777精品久久久大香线蕉| 国产成人久久精品一区二区三区| 91精品久久久久久无码| 久久久久亚洲AV片无码下载蜜桃 | 久久久国产99久久国产一| 无遮挡粉嫩小泬久久久久久久| aaa级精品久久久国产片| 久久99精品免费一区二区| 久久精品一本到99热免费| 亚洲国产二区三区久久| 久久婷婷五月综合97色直播| 日本免费久久久久久久网站|