<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    最簡單的視音頻播放示例5:OpenGL播放RGB/YUV

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    本文記錄OpenGL播放視頻的技術。OpenGL是一個和Direct3D同一層面的技術。相比于Direct3D,OpenGL具有跨平臺的優勢。盡管在游戲領域,DirectX的影響力已漸漸超越OpenGL并被大多數PC游戲開發商所采用,但在專業高端繪圖領域,OpenGL因為色彩準確,仍然是不能被取代的主角。

    RFID設備管理軟件

    OpenGL簡介



    從網上搜集了一些有關OpenGL簡介方面的知識,在這里列出來。
    開放圖形庫(英語:Open Graphics Library,縮寫為OpenGL)是個定義了一個跨編程語言、跨平臺的應用程序接口(API)的規范,它用于生成二維、三維圖像。
    OpenGL規范由1992年成立的OpenGL架構評審委員會(ARB)維護。ARB由一些對創建一個統一的、普遍可用的API特別感興趣的公司組成。根據OpenGL官方網站,2002年6月的ARB投票成員包括3Dlabs、Apple Computer、ATI Technologies、Dell Computer、Evans & Sutherland、Hewlett-Packard、IBM、Intel、Matrox、NVIDIA、SGI和Sun Microsystems,Microsoft曾是創立成員之一,但已于2003年3月退出。
    OpenGL仍然是唯一能夠取代微軟對3D圖形技術的完全控制的API。它仍然具有一定的生命力,但是Silicon Graphics已經不再以任何讓微軟不悅的方式推廣OpenGL,因而它存在較高的風險。在高端的圖形設備和專業應用方面OpenGL占據著統治地位(Direct3D目前還不支持)。開放源碼社區(尤其是Mesa項目)一直致力于提供OpenGL支持。
     

    OpenGL渲染管線

    下文也是網上看的,搞懂了一部分,但是由于3D方面基礎不牢固有些方面還沒有完全弄懂。

    OpenGL渲染管線(OpenGL Pipeline)按照特定的順序對圖形信息進行處理,這些圖形信息可以分為兩個部分:頂點信息(坐標、法向量等)和像素信息(圖像、紋理等)。圖形信息最終被寫入幀緩存中,存儲在幀緩存中的數據(圖像),可以被應用程序獲得(用于保存結果,或作為應用程序的輸入等,見下圖中灰色虛線)。

    RFID設備管理軟件


    Display List(顯示列表)
    顯示列表是一組OpenGL命令,被存儲(編譯)起來用于后續的執行。所有數據,幾何(頂點)數據和像素數據都可以存入顯示列表。數據和命令緩存到顯示列表中可以提高性能。
    Vertex Operation(頂點處理)
    頂點坐標和法線坐標經過模式視圖矩陣從物體坐標系(object coordinates)轉換為觀察坐標系(eye coordinates)。若啟用了光照,對轉換后的定點和法線坐標執行光照計算。光照計算更新了頂點的顏色值。

    RFID設備管理軟件


    Primitive Assembly(圖元裝配)

    頂點處理之后,基本圖元(點、線、多邊形)經過投影矩陣變換,再被視見體裁剪平面裁剪,從觀察坐標系轉換為裁剪坐標系。之后,進行透視除法(除以w)和視口變換(viewport transform),將3d場景投影到窗口坐標系。

    Pixel Transfer Operation(像素操作)

    像素從客戶內存中解包出來之后,要經過縮放、偏移、映射、箝拉(clamping)。這些處理即為像素轉換操作。轉換的數據存在紋理內存或直接經過光柵化轉為片段(fragment)。

    Texture Memory(紋理內存)

    紋理圖像載入到紋理內存中,然后應用到幾何對象上。 

    Raterization(光柵化)

    光柵化就是把幾何(頂點坐標等)和像素數據轉換為片段(fragment)的過程,每個片段對應于幀緩沖區中的一個像素,該像素對應屏幕上一點的顏色和不透明度信息。片段是一個矩形數組,包含了顏色、深度、線寬、點的大小等信息(反鋸齒計算等)。如果渲染模式被設置為GL_FILL,多邊形內部的像素信息在這個階段會被填充。

    RFID設備管理軟件


    如上圖中的三角形,輸入三角形的三個頂點坐標以及其顏色,頂點操作會對三角形的頂點坐標以及法向量進行變換,顏色信息不需要經過變換,但光照計算會影響頂點的顏色信息。經過光柵化后,三角形被離散為一個個點,不在是三個坐標表示,而是由一系列的點組成,每個點存儲了相應的顏色、深度和不透明度等信息。
     
    Fragment Operation(片段操作)
    這是將片段轉為幀緩沖區中的像素要進行的最后處理。首先是紋理單元(texel)生成。一個紋理單元由紋理內存中的數據生成,然后應用到每個片段上。之后進行霧計算。 霧計算完成后,還要按序進行若干片段測試,依次為蒙板(scissor)測試,alpha測試,模版(stencil)測試,深度測試。最后,執行混合,抖動,邏輯操作和遮蔽操作,最終的像素存入framebuffer。
     

    OpenGL與Direct3D的對比


    有關視頻顯示的技術在《Direct3D》文章中已經有過敘述,在這里不再重復。在網上看了一下有關于他們不同點的文章,寫得簡單明了,在這里引用一下:
    OpenGL與Direct3D的一點點對比
    OGL比D3D好的地方:
    OGL是業界標準,許多非Windows操作系統下還找不到D3D
    OGL的色彩比D3D的要好,表面更光滑
    OGL的函數很有規律,不像D3D的,都是指針method,函數名太長了!!
    OGL是右手坐標系,這是數學里用慣了的.D3D雖然也可以改變成右手坐標系,但是需要d3dx9_36.dll的支持
    OGL的常用Matrix,如WorldMatrix都封裝好了,D3D要自己寫。
    OGL的繪圖方式很靈活,而D3D的則要事先定義好FVF,要等所有信息寫進Stream中才繪制。這就使它產生了VertexBuffer和IndexBuffer.好象微軟嫌D3D的Buffer不夠多?搞的多不好學??看人家OGL,哪里要這個東西?
    D3D有好多版本,要是顯卡不支持就廢柴一垛了。而OGL從幾年前就一直沒變過,所以大部分顯卡都支持。
    還有,我發現D3D的半透明功能有很大的問題!!就是兩個半透明的物體前后順序的問題——前面的會被后面的擋住。
     
    但是D3D也有比OGL好的地方:
    D3D支持許多格式的圖片文件,而OGL載入jpg都得自己寫代碼。
    因為D3D是指針調用模式,所以做D3D的鉤子有難度,從而增加了外掛的制作難度。
    D3D是DirectX的成員。程序員要實現聲音播放可以用DirectMusic,配套用總是好的,而OGL則只能畫畫
    D3D是被微軟大力推廣的連接庫。相反,微軟則大力壓制OGL(都是Microsoft參與研制出來的產品,待遇怎這么大?)
    正因為此,D3D已成為中國大型游戲界的主流(我覺得他們是盲目跟風。其實國外很多游戲都是用OGL)
     

    OpenGL視頻顯示的流程

    使用OpenGL播放視頻最簡單的情況下需要如下步驟:
    1.       初始化

    1)         初始化
    2)         創建窗口
    3)         設置繪圖函數
    4)         設置定時器
    5)         進入消息循環

    2.       循環顯示畫面

    1)       調整顯示位置,圖像大小
    2)       畫圖
    3)       顯示

    在這里有一點需要說明。即OpenGL不需要使用Direct3D那種使用WinMain()作為主函數的程序初始化窗口。在Direct3D中是必須要這樣做的,即使用Win32的窗口程序并且調用CreateWindow()創建一個對話框,然后才可以在對話框上繪圖。OpenGL只需要使用普通的控制臺程序即可(入口函數為main())。當然,OpenGL也可以像Direct3D那樣把圖像繪制在Win32程序的窗口中。
     
    下面結合OpenGL播放YUV/RGB的示例代碼,詳細分析一下上文的流程。
    在詳述播放流程之前,再說一點自己學習OpenGL時候的一個明顯的感覺:OpenGL的函數好多啊。OpenGL的函數的特點是數量多,但是每個函數的參數少。而Direct3D的特點和它正好反過來,函數少,但是每個函數的參數多。

    1.       初始化

    1)         初始化
    glutInit()用于初始化glut庫。它原型如下:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void glutInit(int *argcp, char **argv);  


    它包含兩個參數:argcp和argv。一般情況下,直接把main()函數中的argc,argv傳遞給它即可。
    在這里簡單介紹OpenGL中的3個庫:glu,glut,glew
    glu是實用庫,包含有43個函數,函數名的前綴為glu。Glu 為了減輕繁重的編程工作,封裝了OpenGL函數,Glu函數通過調用核心庫的函數,為開發者提供相對簡單的用法,實現一些較為復雜的操作。
      glut是實用工具庫,基本上是用于做窗口界面的,并且是跨平臺的。

            glew是一個跨平臺的擴展庫。不是必需的。它能自動識別當前平臺所支持的全部OpenGL高級擴展函數。還沒有深入研究。

    glutInitDisplayMode()用于設置初始顯示模式。它的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void glutInitDisplayMode(unsigned int mode)  


    其中mode可以選擇以下值或組合:

    GLUT_RGB: 指定 RGB 顏色模式的窗口
    GLUT_RGBA: 指定 RGBA 顏色模式的窗口
    GLUT_INDEX: 指定顏色索引模式的窗口
    GLUT_SINGLE: 指定單緩存窗口
    GLUT_DOUBLE: 指定雙緩存窗口
    GLUT_ACCUM: 窗口使用累加緩存
    GLUT_ALPHA: 窗口的顏色分量包含 alpha 值
    GLUT_DEPTH: 窗口使用深度緩存
    GLUT_STENCIL: 窗口使用模板緩存
    GLUT_MULTISAMPLE: 指定支持多樣本功能的窗口
    GLUT_STEREO: 指定立體窗口
    GLUT_LUMINANCE: 窗口使用亮度顏色模型

    需要注意的是,如果使用雙緩沖(GLUT_DOUBLE),則需要用glutSwapBuffers ()繪圖。如果使用單緩沖(GLUT_SINGLE),則需要用glFlush()繪圖。
    在使用OpenGL播放視頻的時候,我們可以使用下述代碼:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB );  

     
    2)         創建窗口
    glutInitWindowPosition()用于設置窗口的位置。可以指定x,y坐標。
    glutInitWindowSize()用于設置窗口的大小。可以設置窗口的寬,高。
    glutCreateWindow()創建一個窗口。可以指定窗口的標題。
    上述幾個函數十分基礎,不再詳細敘述。直接貼出一段示例代碼:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. glutInitWindowPosition(100, 100);  
    2. glutInitWindowSize(500, 500);  
    3. glutCreateWindow("Simplest Video Play OpenGL");        

     
    3)         設置繪圖函數
    glutDisplayFunc()用于設置繪圖函數。操作系統在必要時刻就會調用該函數對窗體進行重新繪制操作。類似于windows程序設計中處理WM_PAINT消息。例如,當把窗口移動到屏幕邊上,然后又移動回來的時候,就會調用該函數對窗口進行重繪。它的原型如下。

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void glutDisplayFunc(void (*func)(void));  

     

    其中(*func)用于指定重繪函數。

    例如在視頻播放的時候,指定display()函數用于重繪:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. glutDisplayFunc(&display);  


    4)         設置定時器
    播放視頻的時候,每秒需要播放一定的畫面(一般是25幀),因此使用定時器每間隔一段時間調用一下繪圖函數繪制圖形。定時器函數glutTimerFunc()的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void glutTimerFunc(unsigned int millis, void (*func)(int value), int value);  

    它的參數含義如下:
    millis:定時的時間,單位是毫秒。1秒=1000毫秒。
    (*func)(int value):用于指定定時器調用的函數。
    value:給回調函數傳參。比較高端,沒有接觸過。
    如果只在主函數中寫一個glutTimerFunc()函數的話,會發現只會調用該函數一次。因此需要在回調函數中再寫一個glutTimerFunc()函數,并調用回調函數自己。只有這樣才能實現反反復復循環調用回調函數。
    例如在視頻播放的時候,指定每40毫秒調用一次timeFunc ()函數:
    主函數中:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. glutTimerFunc(40, timeFunc, 0);  


    而后在timeFunc()函數中如下設置。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void timeFunc(int value){  
    2.     display();  
    3.     // Present frame every 40 ms  
    4.     glutTimerFunc(40, timeFunc, 0);  
    5. }  


    這樣就實現了每40ms調用一次display()。
     
    5)         進入消息循環
    glutMainLoop()將會進入GLUT事件處理循環。一旦被調用,這個程序將永遠不會返回。視頻播放的時候,調用該函數之后即開始播放視頻。
     

    2.       循環顯示畫面

    1)       調整顯示位置,圖像大小
    這一步主要是調整一下圖像的大小和位置。如果不做這一步而直接使用glDrawPixels()進行繪圖的話,會發現圖像位于窗口的左下角,而且是上下顛倒的(當然,如果窗口和圖像一樣大的話,就不存在圖像位于角落的問題)。效果如下圖所示。

    RFID設備管理軟件


    為了解決上述問題,需要調用有關的函數對圖像進行變換。變換用到了兩個函數:glRasterPos3f()和glPixelZoom()。
    glRasterPos3f()可以平移圖像。它的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void glRasterPos3f (GLfloat x, GLfloat y, GLfloat z);  


    其中x用于指定x坐標;y用于指定y坐標。Z這里還沒有用到。
    在這里介紹一下OpenGL的坐標。原點位于屏幕的中心。屏幕的邊上對應的值是1.0。和數學中的坐標系基本上是一樣的。屏幕的左下角是(-1,-1),左上角是(-1,1)。

    RFID設備管理軟件

    例如我們使用glRasterPos3f(-1.0f,0.0f,0),圖像就會移動至(-1,0),如下圖所示。

    RFID設備管理軟件


    glPixelZoom()可以放大、縮小和翻轉圖像。它的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void glPixelZoom (GLfloat xfactor, GLfloat yfactor);  


    其中xfactor、yfactor用于指定在x軸,y軸上放大的倍數(如果數值小于1則是縮小)。如果指定負值,則可以實現翻轉。上文已經說過,使用OpenGL直接顯示像素數據的話,會發現圖像是倒著的。因此需要在Y軸方向對圖像進行翻轉。

    例如:像素數據的寬高分別為pixel_w ,pixel_h ;窗口大小為screen_w,screen_h的話,使用下述代碼可以將圖像拉伸至窗口大小,并且翻轉:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. glPixelZoom((float)screen_w/(float)pixel_w, -(float)screen_h/pixel_h);  


    結合上述兩個函數,即“平移+翻轉+拉伸之后”,就可以得到全屏的圖像了,如下圖所示。

    RFID設備管理軟件

     

    PS:這個方法屬于比較笨的方法,應該還有更好的方法吧。不過再沒有進行深入研究了。

     

    2)       畫圖
    使用glDrawPixels()可以繪制指定內存中的像素數據。該函數的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. void glDrawPixels (  
    2. GLsizei width, GLsizei height,  
    3. GLenum format,  
    4. GLenum type,  
    5. const GLvoid *pixels);  


    該函數的參數的含義如下所示:
    Width:像素數據的寬。
    Height:像素數據的高。
    Format:像素數據的格式,例如GL_RGB,GL_BGR,GL_BGRA等。
    Type:像素數據在內存中的格式。
    Pixels:指針,指向存儲像素數據的內存。
    例如繪制RGB24格式的數據,寬為pixel_w,高為pixel_h,像素數據存儲在buffer中。可以使用如下代碼。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. glDrawPixels(pixel_w, pixel_h,GL_RGB, GL_UNSIGNED_BYTE, buffer);  

     
    3)       顯示
    使用雙緩沖的時候,調用函數glutSwapBuffers()進行顯示。
    使用單緩沖的時候,調用函數glFlush()進行顯示。
     
     

    視頻顯示的流程總結

    視頻顯示的函數調用結構可以總結為下圖

    RFID設備管理軟件

     

    代碼


    貼上源代碼。

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. /** 
    2.  * 最簡單的OpenGL播放視頻的例子(OpenGL播放RGB/YUV) 
    3.  * Simplest Video Play OpenGL (OpenGL play RGB/YUV)  
    4.  * 
    5.  * 雷霄驊 Lei Xiaohua 
    6.  * leixiaohua1020@126.com 
    7.  * 中國傳媒大學/數字電視技術 
    8.  * Communication University of China / Digital TV Technology 
    9.  * http://blog.csdn.net/leixiaohua1020 
    10.  * 
    11.  * 本程序使用OpenGL播放RGB/YUV視頻像素數據。本程序實際上只能 
    12.  * 播放RGB(RGB24,BGR24,BGRA)數據。如果輸入數據為YUV420P 
    13.  * 數據的話,需要先轉換為RGB數據之后再進行播放。 
    14.  * 本程序是最簡單的使用OpenGL播放像素數據的例子,適合OpenGL新手學習。 
    15.  * 
    16.  * 函數調用步驟如下:  
    17.  * 
    18.  * [初始化] 
    19.  * glutInit(): 初始化glut庫。 
    20.  * glutInitDisplayMode(): 設置顯示模式。 
    21.  * glutCreateWindow(): 創建一個窗口。 
    22.  * glutDisplayFunc(): 設置繪圖函數(重繪的時候調用)。 
    23.  * glutTimerFunc(): 設置定時器。 
    24.  * glutMainLoop(): 進入消息循環。 
    25.  * 
    26.  * [循環渲染數據] 
    27.  * glRasterPos3f(),glPixelZoom(): 調整顯示位置,圖像大小。 
    28.  * glDrawPixels(): 繪制。 
    29.  * glutSwapBuffers(): 顯示。 
    30.  * 
    31.  * This software plays RGB/YUV raw video data using OpenGL. This 
    32.  * software support show RGB (RGB24, BGR24, BGRA) data on the screen. 
    33.  * If the input data is YUV420P, it need to be convert to RGB first. 
    34.  * This program is the simplest example about play raw video data 
    35.  * using OpenGL, Suitable for the beginner of OpenGL. 
    36.  * 
    37.  * The process is shown as follows: 
    38.  * 
    39.  * [Init] 
    40.  * glutInit(): Init glut library. 
    41.  * glutInitDisplayMode(): Set display mode. 
    42.  * glutCreateWindow(): Create a window. 
    43.  * glutDisplayFunc(): Set the display callback. 
    44.  * glutTimerFunc(): Set timer. 
    45.  * glutMainLoop(): Start message loop. 
    46.  * 
    47.  * [Loop to Render data] 
    48.  * glRasterPos3f(),glPixelZoom(): Change picture's size and position. 
    49.  * glDrawPixels(): draw. 
    50.  * glutSwapBuffers(): show. 
    51.  */  
    52.   
    53. #include <stdio.h>  
    54.   
    55. #include "glew.h"  
    56. #include "glut.h"  
    57.   
    58. #include <stdlib.h>  
    59. #include <malloc.h>  
    60. #include <string.h>  
    61.   
    62. //set '1' to choose a type of file to play  
    63. #define LOAD_RGB24   1  
    64. #define LOAD_BGR24   0  
    65. #define LOAD_BGRA    0  
    66. #define LOAD_YUV420P 0  
    67.   
    68. int screen_w=500,screen_h=500;  
    69. const int pixel_w = 320, pixel_h = 180;  
    70. //Bit per Pixel  
    71. #if LOAD_BGRA  
    72. const int bpp=32;  
    73. #elif LOAD_RGB24|LOAD_BGR24  
    74. const int bpp=24;  
    75. #elif LOAD_YUV420P  
    76. const int bpp=12;  
    77. #endif  
    78. //YUV file  
    79. FILE *fp = NULL;  
    80. unsigned char buffer[pixel_w*pixel_h*bpp/8];  
    81. unsigned char buffer_convert[pixel_w*pixel_h*3];  
    82.   
    83. inline unsigned char CONVERT_ADJUST(double tmp)  
    84. {  
    85.     return (unsigned char)((tmp >= 0 && tmp <= 255)?tmp:(tmp < 0 ? 0 : 255));  
    86. }  
    87. //YUV420P to RGB24  
    88. void CONVERT_YUV420PtoRGB24(unsigned char* yuv_src,unsigned char* rgb_dst,int nWidth,int nHeight)  
    89. {  
    90.     unsigned char *tmpbuf=(unsigned char *)malloc(nWidth*nHeight*3);  
    91.     unsigned char Y,U,V,R,G,B;  
    92.     unsigned char* y_planar,*u_planar,*v_planar;  
    93.     int rgb_width , u_width;  
    94.     rgb_width = nWidth * 3;  
    95.     u_width = (nWidth >> 1);  
    96.     int ypSize = nWidth * nHeight;  
    97.     int upSize = (ypSize>>2);  
    98.     int offSet = 0;  
    99.   
    100.     y_planar = yuv_src;  
    101.     u_planar = yuv_src + ypSize;  
    102.     v_planar = u_planar + upSize;  
    103.   
    104.     for(int i = 0; i < nHeight; i++)  
    105.     {  
    106.         for(int j = 0; j < nWidth; j ++)  
    107.         {  
    108.             // Get the Y value from the y planar  
    109.             Y = *(y_planar + nWidth * i + j);  
    110.             // Get the V value from the u planar  
    111.             offSet = (i>>1) * (u_width) + (j>>1);  
    112.             V = *(u_planar + offSet);  
    113.             // Get the U value from the v planar  
    114.             U = *(v_planar + offSet);  
    115.   
    116.             // Cacular the R,G,B values  
    117.             // Method 1  
    118.             R = CONVERT_ADJUST((Y + (1.4075 * (V - 128))));  
    119.             G = CONVERT_ADJUST((Y - (0.3455 * (U - 128) - 0.7169 * (V - 128))));  
    120.             B = CONVERT_ADJUST((Y + (1.7790 * (U - 128))));  
    121.             /* 
    122.             // The following formulas are from MicroSoft' MSDN 
    123.             int C,D,E; 
    124.             // Method 2 
    125.             C = Y - 16; 
    126.             D = U - 128; 
    127.             E = V - 128; 
    128.             R = CONVERT_ADJUST(( 298 * C + 409 * E + 128) >> 8); 
    129.             G = CONVERT_ADJUST(( 298 * C - 100 * D - 208 * E + 128) >> 8); 
    130.             B = CONVERT_ADJUST(( 298 * C + 516 * D + 128) >> 8); 
    131.             R = ((R - 128) * .6 + 128 )>255?255:(R - 128) * .6 + 128;  
    132.             G = ((G - 128) * .6 + 128 )>255?255:(G - 128) * .6 + 128;  
    133.             B = ((B - 128) * .6 + 128 )>255?255:(B - 128) * .6 + 128;  
    134.             */  
    135.             offSet = rgb_width * i + j * 3;  
    136.   
    137.             rgb_dst[offSet] = B;  
    138.             rgb_dst[offSet + 1] = G;  
    139.             rgb_dst[offSet + 2] = R;  
    140.         }  
    141.     }  
    142.     free(tmpbuf);  
    143. }  
    144.   
    145. void display(void){  
    146.     if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8){  
    147.         // Loop  
    148.         fseek(fp, 0, SEEK_SET);  
    149.         fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);  
    150.     }  
    151.   
    152.     //Make picture full of window  
    153.     //Move to(-1.0,1.0)  
    154.     glRasterPos3f(-1.0f,1.0f,0);  
    155.     //Zoom, Flip  
    156.     glPixelZoom((float)screen_w/(float)pixel_w, -(float)screen_h/(float)pixel_h);  
    157.       
    158.   
    159.   
    160. #if LOAD_BGRA  
    161.     glDrawPixels(pixel_w, pixel_h,GL_BGRA, GL_UNSIGNED_BYTE, buffer);  
    162. #elif LOAD_RGB24  
    163.     glDrawPixels(pixel_w, pixel_h,GL_RGB, GL_UNSIGNED_BYTE, buffer);  
    164. #elif LOAD_BGR24  
    165.     glDrawPixels(pixel_w, pixel_h,GL_BGR_EXT, GL_UNSIGNED_BYTE, buffer);  
    166. #elif LOAD_YUV420P  
    167.     CONVERT_YUV420PtoRGB24(buffer,buffer_convert,pixel_w,pixel_h);  
    168.     glDrawPixels(pixel_w, pixel_h,GL_RGB, GL_UNSIGNED_BYTE, buffer_convert);  
    169. #endif  
    170.     //GLUT_DOUBLE  
    171.     glutSwapBuffers();  
    172.   
    173.     //GLUT_SINGLE  
    174.     //glFlush();  
    175. }  
    176.   
    177. void timeFunc(int value){  
    178.     display();  
    179.     // Present frame every 40 ms  
    180.     glutTimerFunc(40, timeFunc, 0);  
    181. }  
    182.   
    183.   
    184.   
    185. int main(int argc, char* argv[])  
    186. {  
    187. #if LOAD_BGRA  
    188.     fp=fopen("../test_bgra_320x180.rgb","rb+");  
    189. #elif LOAD_RGB24  
    190.     fp=fopen("../test_rgb24_320x180.rgb","rb+");  
    191. #elif LOAD_BGR24  
    192.     fp=fopen("../test_bgr24_320x180.rgb","rb+");  
    193. #elif LOAD_YUV420P  
    194.     fp=fopen("../test_yuv420p_320x180.yuv","rb+");  
    195. #endif  
    196.     if(fp==NULL){  
    197.         printf("Cannot open this file.\n");  
    198.         return -1;  
    199.     }  
    200.   
    201.     // GLUT init  
    202.     glutInit(&argc, argv);    
    203.     //Double, Use glutSwapBuffers() to show  
    204.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB );  
    205.     //Single, Use glFlush() to show  
    206.     //glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB );  
    207.   
    208.     glutInitWindowPosition(100, 100);  
    209.     glutInitWindowSize(screen_w, screen_h);  
    210.     glutCreateWindow("Simplest Video Play OpenGL");  
    211.     printf("Simplest Video Play OpenGL\n");  
    212.     printf("Lei Xiaohua\n");  
    213.     printf("http://blog.csdn.net/leixiaohua1020\n");  
    214.     printf("OpenGL Version: %s\n", glGetString(GL_VERSION));  
    215.   
    216.     glutDisplayFunc(&display);  
    217.     glutTimerFunc(40, timeFunc, 0);   
    218.       
    219.     // Start!  
    220.     glutMainLoop();  
    221.   
    222.     return 0;  
    223. }  

     

     

     

     

    代碼注意事項

    1.       可以通過設置定義在文件開始出的宏,決定讀取哪個格式的像素數據(bgra,rgb24,bgr24,yuv420p)。
     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. //set '1' to choose a type of file to play  
    2. #define LOAD_RGB24   1  
    3. #define LOAD_BGR24   0  
    4. #define LOAD_BGRA    0  
    5. #define LOAD_YUV420P 0  

     
    2.       窗口的寬高為screen_w,screen_h。像素數據的寬高為pixel_w,pixel_h。它們的定義如下。
     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. //Width, Height  
    2. const int screen_w=500,screen_h=500;  
    3. const int pixel_w=320,pixel_h=180;  


    3.       注意顯示方式的不同
    BGRA,BGR24,RGB24這3種格式可以直接在glDrawPixels()中設置像素格式顯示出來。而YUV420P是不能直接顯示出來的。本文示例采用的方式是先將YUV420P轉換成RGB24,然后進行顯示。

    運行結果

    無論選擇加載哪個文件,運行結果都是一樣的,如下圖所示。

    RFID設備管理軟件

     

    下載

    代碼位于“Simplest Media Play”中
     
     

    SourceForge項目地址:https://sourceforge.net/projects/simplestmediaplay/

    CSDN下載地址:http://download.csdn.net/detail/leixiaohua1020/8054395

     
     

    上述工程包含了使用各種API(Direct3D,OpenGL,GDI,DirectSound,SDL2)播放多媒體例子。其中音頻輸入為PCM采樣數據。輸出至系統的聲卡播放出來。視頻輸入為YUV/RGB像素數據。輸出至顯示器上的一個窗口播放出來。

    通過本工程的代碼初學者可以快速學習使用這幾個API播放視頻和音頻的技術。

    一共包括了如下幾個子工程:

    simplest_audio_play_directsound:         使用DirectSound播放PCM音頻采樣數據。
    simplest_audio_play_sdl2:                       使用SDL2播放PCM音頻采樣數據。
    simplest_video_play_direct3d:                使用Direct3D的Surface播放RGB/YUV視頻像素數據。
    simplest_video_play_direct3d_texture:使用Direct3D的Texture播放RGB視頻像素數據。
    simplest_video_play_gdi:                          使用GDI播放RGB/YUV視頻像素數據。
    simplest_video_play_opengl:                   使用OpenGL播放RGB/YUV視頻像素數據。
    simplest_video_play_opengl_texture:    使用OpenGL的Texture播放YUV視頻像素數據。
    simplest_video_play_sdl2:                        使用SDL2播放RGB/YUV視頻像素數據。
     

     

    from:http://blog.csdn.net/leixiaohua1020/article/details/40333583

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全