青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

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

常用鏈接

留言簿(48)

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

搜索

  •  

積分與排名

  • 積分 - 402520
  • 排名 - 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)的流的類(lèi)型.在這個(gè)工程里,我們只對(duì)視頻流感興趣(streamtypeVIDEO).第四參數(shù)是0,這表示我們需要第一次讀到的視頻流(一個(gè)AVI文件里會(huì)有多個(gè)視頻流,我們要第一個(gè)).OF_READ表示以只讀方式打開(kāi)文件.最后一個(gè)參數(shù)是一個(gè)類(lèi)標(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ù)去做.
首先要做的是描述我們想要的圖像的類(lèi)型.于是我們要以所需參數(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之類(lèi)的).這樣給了你很大機(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è)試的類(lèi)型(小于或等于)
    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 閱讀(1566) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): OPENGL
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            玖玖精品视频| 国产精品va在线| 乱人伦精品视频在线观看| 亚洲激情国产| 欧美日韩一本到| 亚洲欧美在线高清| 麻豆精品精品国产自在97香蕉| 欧美经典一区二区| 亚洲手机视频| 噜噜噜91成人网| 在线亚洲精品| 激情av一区二区| 欧美日韩午夜激情| 久久精品人人| a4yy欧美一区二区三区| 久久久久久夜精品精品免费| 亚洲美女电影在线| 国产欧美一区二区三区国产幕精品| 另类春色校园亚洲| 亚洲一区中文字幕在线观看| 欧美国产激情| 久久激情五月婷婷| 在线视频你懂得一区| 激情av一区| 国产精品视频精品| 欧美精品一区在线发布| 欧美在线综合| 国产精品99久久久久久www| 欧美va天堂| 久久av红桃一区二区小说| 日韩小视频在线观看专区| 韩国三级电影久久久久久| 国产精品久久久久久久久免费| 欧美va亚洲va日韩∨a综合色| 午夜日韩在线观看| 99热免费精品| 最新中文字幕亚洲| 久久夜色精品亚洲噜噜国产mv| 亚洲视频久久| 亚洲人成人一区二区在线观看| 国产一区亚洲一区| 国产毛片久久| 国产精品女主播| 欧美日韩小视频| 欧美国产日韩一区二区| 久久人体大胆视频| 欧美在线看片a免费观看| 亚洲一区免费网站| 在线综合视频| 中国成人黄色视屏| 亚洲伦理在线观看| 亚洲国产成人午夜在线一区 | 国产日韩精品视频一区| 欧美日韩成人在线观看| 欧美成人tv| 免费观看在线综合| 麻豆国产精品va在线观看不卡 | 久久久综合精品| 亚洲欧美一区二区三区久久| 在线视频精品一| 一区二区三区黄色| 一本综合精品| 中文亚洲视频在线| 亚洲视频免费看| 99天天综合性| 在线视频日韩精品| 国产精品99久久不卡二区| 这里只有精品视频在线| 中文有码久久| 亚洲欧美日韩综合aⅴ视频| 亚洲在线免费观看| 性做久久久久久久久| 欧美在线3区| 久久久久久电影| 麻豆免费精品视频| 欧美电影免费观看大全| 欧美区视频在线观看| 欧美色另类天堂2015| 国产精品网站视频| 韩国自拍一区| 91久久午夜| 亚洲天堂成人在线视频| 亚洲欧美日韩视频二区| 久久av二区| 日韩一级免费观看| 在线综合亚洲欧美在线视频| 亚洲——在线| 久久久久久亚洲精品中文字幕| 美女黄毛**国产精品啪啪| 女同一区二区| 日韩一级视频免费观看在线| 亚洲视频免费观看| 欧美中文字幕在线播放| 久久综合色婷婷| 欧美日韩午夜视频在线观看| 国产欧美日韩综合精品二区| 在线观看中文字幕不卡| 99re亚洲国产精品| 欧美亚洲网站| 欧美高清日韩| 亚洲一级在线| 蜜臀99久久精品久久久久久软件| 欧美视频免费看| 狠狠88综合久久久久综合网| 日韩亚洲一区二区| 欧美一区二区三区另类| 欧美二区不卡| 亚洲一区久久| 蜜桃av一区| 国产精品久久久久婷婷| 雨宫琴音一区二区在线| 在线一区观看| 免费不卡在线视频| 这里是久久伊人| 欧美成人亚洲成人| 国产日韩精品一区二区三区| 亚洲精品欧美日韩| 久久精品女人的天堂av| 亚洲精品久久久久久久久久久久久| 亚洲欧美日韩另类| 欧美精品一区在线| 娇妻被交换粗又大又硬视频欧美| 亚洲午夜一二三区视频| 欧美高清在线观看| 久久xxxx精品视频| 国产精品激情| 亚洲美女电影在线| 麻豆av一区二区三区| 亚洲一区二区三区精品动漫| 欧美激情1区| 影音先锋日韩精品| 欧美主播一区二区三区| 亚洲另类黄色| 美女国内精品自产拍在线播放| 国产农村妇女毛片精品久久莱园子 | 亚洲成色777777在线观看影院| 亚洲综合久久久久| 欧美欧美午夜aⅴ在线观看| 亚洲国产成人精品久久久国产成人一区 | 欧美视频你懂的| 亚洲欧洲精品一区二区三区 | 久久人人97超碰国产公开结果 | 91久久国产精品91久久性色| 欧美一级电影久久| 夜夜爽99久久国产综合精品女不卡 | 欧美激情按摩在线| 136国产福利精品导航| 久久精品日产第一区二区| 亚洲香蕉成视频在线观看| 欧美精品大片| 亚洲精一区二区三区| 欧美国产精品日韩| 两个人的视频www国产精品| 精久久久久久| 久久免费国产| 久久九九精品99国产精品| 国产亚洲精品久久久久久| 极品少妇一区二区三区| 久久精品人人做人人爽| 午夜久久电影网| 国产欧美另类| 久久大逼视频| 欧美在线日韩| 黄色成人片子| 美女视频网站黄色亚洲| 久久国内精品自在自线400部| 国产亚洲视频在线| 久久精品国产久精国产一老狼| 亚洲欧美国产视频| 国产日韩一区二区三区| 久久久www成人免费无遮挡大片| 篠田优中文在线播放第一区| 国产日韩在线看片| 久久久夜精品| 久久这里有精品视频| 亚洲日本欧美| 日韩亚洲在线| 国产噜噜噜噜噜久久久久久久久| 欧美一区二区三区免费视频| 欧美在线|欧美| 亚洲国产清纯| 亚洲美女视频网| 国产精品免费看片| 久久九九国产| 久久综合色88| 亚洲一区二区三区高清不卡| 亚洲欧美日本另类| 在线免费精品视频| 亚洲精品中文字| 国产欧美日本一区二区三区| 久热精品视频在线| 欧美粗暴jizz性欧美20| 亚洲无线一线二线三线区别av| 亚洲女同同性videoxma| 极品少妇一区二区三区精品视频| 亚洲国产小视频| 国产目拍亚洲精品99久久精品 | 欧美成人网在线| 亚洲女女女同性video| 欧美伊人精品成人久久综合97|