<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>
  • 網站首頁 > 物聯資訊 > 技術分享

    最簡單的視音頻播放示例7:SDL2播放RGB/YUV

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

    本文記錄SDL播放視頻的技術。在這里使用的版本是SDL2。實際上SDL本身并不提供視音頻播放的功能,它只是封裝了視音頻播放的底層API。在Windows平臺下,SDL封裝了Direct3D這類的API用于播放視頻;封裝了DirectSound這類的API用于播放音頻。因為SDL的編寫目的就是簡化視音頻播放的開發難度,所以使用SDL播放視頻(YUV/RGB)和音頻(PCM)數據非常的容易。下文記錄一下使用SDL播放視頻數據的技術。

    RFID設備管理軟件

     

    SDL簡介


    SDL(Simple DirectMedia Layer)是一套開放源代碼的跨平臺多媒體開發庫,使用C語言寫成。SDL提供了數種控制圖像、聲音、輸出入的函數,讓開發者只要用相同或是相似的代碼就可以開發出跨多個平臺(Linux、Windows、Mac OS X等)的應用軟件。目前SDL多用于開發游戲、模擬器、媒體播放器等多媒體應用領域。用下面這張圖可以很明確地說明SDL的位置。

    RFID設備管理軟件


    SDL實際上并不限于視音頻的播放,它將功能分成下列數個子系統(subsystem):

    Video(圖像):圖像控制以及線程(thread)和事件管理(event)。
    Audio(聲音):聲音控制
    Joystick(搖桿):游戲搖桿控制
    CD-ROM(光盤驅動器):光盤媒體控制
    Window Management(視窗管理):與視窗程序設計集成
    Event(事件驅動):處理事件驅動

     

    在Windows下,SDL與DirectX的對應關系如下。

     

    SDL

    DirectX

    SDL_Video、SDL_Image

    DirectDraw、Direct3D

    SDL_Audio、SDL_Mixer

    DirectSound

    SDL_Joystick、SDL_Base

    DirectInput

    SDL_Net

    DirectPlay

     

     

    SDL播放視頻的流程

    SDL播放視頻的技術在此前做的FFmpeg的示例程序中已經多次用到。在這里重新總結一下流程。
     
    1.       初始化

    1)         初始化SDL
    2)         創建窗口(Window)
    3)         基于窗口創建渲染器(Render)
    4)         創建紋理(Texture)

    2.       循環顯示畫面

    1)       設置紋理的數據
    2)       紋理復制給渲染目標
    3)       顯示

     
    下面詳細分析一下上文的流程。

    1.       初始化

    1)         初始化SDL

    使用SDL_Init()初始化SDL。該函數可以確定希望激活的子系統。SDL_Init()函數原型如下:

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. int SDLCALL SDL_Init(Uint32 flags)  


    其中,flags可以取下列值:

    SDL_INIT_TIMER:定時器
    SDL_INIT_AUDIO:音頻
    SDL_INIT_VIDEO:視頻
    SDL_INIT_JOYSTICK:搖桿
    SDL_INIT_HAPTIC:觸摸屏
    SDL_INIT_GAMECONTROLLER:游戲控制器
    SDL_INIT_EVENTS:事件
    SDL_INIT_NOPARACHUTE:不捕獲關鍵信號(這個沒研究過)
    SDL_INIT_EVERYTHING:包含上述所有選項

     

    有關SDL_Init()有一點需要注意:初始化的時候盡量做到“夠用就好”,而不要用SDL_INIT_EVERYTHING。因為有些情況下使用SDL_INIT_EVERYTHING會出現一些不可預知的問題。例如,在MFC應用程序中播放純音頻,如果初始化SDL的時候使用SDL_INIT_EVERYTHING,那么就會出現聽不到聲音的情況。后來發現,去掉了SDL_INIT_VIDEO之后,問題才得以解決。

     
    2)         創建窗口(Window)
    使用SDL_CreateWindow()創建一個用于視頻播放的窗口。SDL_CreateWindow()的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. SDL_Window * SDLCALL SDL_CreateWindow(const char *title,  
    2.                                                       int x, int y, int w,  
    3.                                                       int h, Uint32 flags);  


    參數含義如下。
    title  :窗口標題
    x       :窗口位置x坐標。也可以設置為SDL_WINDOWPOS_CENTERED或SDL_WINDOWPOS_UNDEFINED。
    y       :窗口位置y坐標。同上。
    w      :窗口的寬
    h       :窗口的高
    flags :支持下列標識。包括了窗口的是否最大化、最小化,能否調整邊界等等屬性。
           ::SDL_WINDOW_FULLSCREEN,    ::SDL_WINDOW_OPENGL,
           ::SDL_WINDOW_HIDDEN,        ::SDL_WINDOW_BORDERLESS,
           ::SDL_WINDOW_RESIZABLE,     ::SDL_WINDOW_MAXIMIZED,
           ::SDL_WINDOW_MINIMIZED,     ::SDL_WINDOW_INPUT_GRABBED,
           ::SDL_WINDOW_ALLOW_HIGHDPI.
     返回創建完成的窗口的ID。如果創建失敗則返回0。
     
     
    3)         基于窗口創建渲染器(Render)
    使用SDL_CreateRenderer()基于窗口創建渲染器。SDL_CreateRenderer()原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window,  
    2.                                                int index, Uint32 flags);  


    參數含義如下。
    window    : 渲染的目標窗口。
    index         :打算初始化的渲染設備的索引。設置“-1”則初始化默認的渲染設備。
    flags          :支持以下值(位于SDL_RendererFlags定義中)

        SDL_RENDERER_SOFTWARE :使用軟件渲染
        SDL_RENDERER_ACCELERATED :使用硬件加速
        SDL_RENDERER_PRESENTVSYNC:和顯示器的刷新率同步
        SDL_RENDERER_TARGETTEXTURE :不太懂

    返回創建完成的渲染器的ID。如果創建失敗則返回NULL。
     
    4)         創建紋理(Texture)
    使用SDL_CreateTexture()基于渲染器創建一個紋理。SDL_CreateTexture()的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer,  
    2.                                                         Uint32 format,  
    3.                                                         int access, int w,  
    4.                                                         int h);  


    參數的含義如下。
    renderer:目標渲染器。
    format      :紋理的格式。后面會詳述。
    access      :可以取以下值(定義位于SDL_TextureAccess中)

        SDL_TEXTUREACCESS_STATIC         :變化極少
        SDL_TEXTUREACCESS_STREAMING        :變化頻繁
        SDL_TEXTUREACCESS_TARGET       :暫時沒有理解

    w               :紋理的寬
    h                :紋理的高
    創建成功則返回紋理的ID,失敗返回0。
     
    在紋理的創建過程中,需要指定紋理的格式(即第二個參數)。SDL的中的格式很多,如下所列。
     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. SDL_PIXELFORMAT_UNKNOWN,  
    2. SDL_PIXELFORMAT_INDEX1LSB =  
    3.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_4321, 0,  
    4.                            1, 0),  
    5. SDL_PIXELFORMAT_INDEX1MSB =  
    6.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_1234, 0,  
    7.                            1, 0),  
    8. SDL_PIXELFORMAT_INDEX4LSB =  
    9.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_4321, 0,  
    10.                            4, 0),  
    11. SDL_PIXELFORMAT_INDEX4MSB =  
    12.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_1234, 0,  
    13.                            4, 0),  
    14. SDL_PIXELFORMAT_INDEX8 =  
    15.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX8, 0, 0, 8, 1),  
    16. SDL_PIXELFORMAT_RGB332 =  
    17.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED8, SDL_PACKEDORDER_XRGB,  
    18.                            SDL_PACKEDLAYOUT_332, 8, 1),  
    19. SDL_PIXELFORMAT_RGB444 =  
    20.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB,  
    21.                            SDL_PACKEDLAYOUT_4444, 12, 2),  
    22. SDL_PIXELFORMAT_RGB555 =  
    23.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB,  
    24.                            SDL_PACKEDLAYOUT_1555, 15, 2),  
    25. SDL_PIXELFORMAT_BGR555 =  
    26.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XBGR,  
    27.                            SDL_PACKEDLAYOUT_1555, 15, 2),  
    28. SDL_PIXELFORMAT_ARGB4444 =  
    29.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ARGB,  
    30.                            SDL_PACKEDLAYOUT_4444, 16, 2),  
    31. SDL_PIXELFORMAT_RGBA4444 =  
    32.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_RGBA,  
    33.                            SDL_PACKEDLAYOUT_4444, 16, 2),  
    34. SDL_PIXELFORMAT_ABGR4444 =  
    35.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ABGR,  
    36.                            SDL_PACKEDLAYOUT_4444, 16, 2),  
    37. SDL_PIXELFORMAT_BGRA4444 =  
    38.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_BGRA,  
    39.                            SDL_PACKEDLAYOUT_4444, 16, 2),  
    40. SDL_PIXELFORMAT_ARGB1555 =  
    41.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ARGB,  
    42.                            SDL_PACKEDLAYOUT_1555, 16, 2),  
    43. SDL_PIXELFORMAT_RGBA5551 =  
    44.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_RGBA,  
    45.                            SDL_PACKEDLAYOUT_5551, 16, 2),  
    46. SDL_PIXELFORMAT_ABGR1555 =  
    47.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ABGR,  
    48.                            SDL_PACKEDLAYOUT_1555, 16, 2),  
    49. SDL_PIXELFORMAT_BGRA5551 =  
    50.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_BGRA,  
    51.                            SDL_PACKEDLAYOUT_5551, 16, 2),  
    52. SDL_PIXELFORMAT_RGB565 =  
    53.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB,  
    54.                            SDL_PACKEDLAYOUT_565, 16, 2),  
    55. SDL_PIXELFORMAT_BGR565 =  
    56.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XBGR,  
    57.                            SDL_PACKEDLAYOUT_565, 16, 2),  
    58. SDL_PIXELFORMAT_RGB24 =  
    59.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_ARRAYU8, SDL_ARRAYORDER_RGB, 0,  
    60.                            24, 3),  
    61. SDL_PIXELFORMAT_BGR24 =  
    62.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_ARRAYU8, SDL_ARRAYORDER_BGR, 0,  
    63.                            24, 3),  
    64. SDL_PIXELFORMAT_RGB888 =  
    65.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XRGB,  
    66.                            SDL_PACKEDLAYOUT_8888, 24, 4),  
    67. SDL_PIXELFORMAT_RGBX8888 =  
    68.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_RGBX,  
    69.                            SDL_PACKEDLAYOUT_8888, 24, 4),  
    70. SDL_PIXELFORMAT_BGR888 =  
    71.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XBGR,  
    72.                            SDL_PACKEDLAYOUT_8888, 24, 4),  
    73. SDL_PIXELFORMAT_BGRX8888 =  
    74.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_BGRX,  
    75.                            SDL_PACKEDLAYOUT_8888, 24, 4),  
    76. SDL_PIXELFORMAT_ARGB8888 =  
    77.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB,  
    78.                            SDL_PACKEDLAYOUT_8888, 32, 4),  
    79. SDL_PIXELFORMAT_RGBA8888 =  
    80.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_RGBA,  
    81.                            SDL_PACKEDLAYOUT_8888, 32, 4),  
    82. SDL_PIXELFORMAT_ABGR8888 =  
    83.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ABGR,  
    84.                            SDL_PACKEDLAYOUT_8888, 32, 4),  
    85. SDL_PIXELFORMAT_BGRA8888 =  
    86.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_BGRA,  
    87.                            SDL_PACKEDLAYOUT_8888, 32, 4),  
    88. SDL_PIXELFORMAT_ARGB2101010 =  
    89.     SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB,  
    90.                            SDL_PACKEDLAYOUT_2101010, 32, 4),  
    91.   
    92. SDL_PIXELFORMAT_YV12 =      /**< Planar mode: Y + V + U  (3 planes) */  
    93.     SDL_DEFINE_PIXELFOURCC('Y', 'V', '1', '2'),  
    94. SDL_PIXELFORMAT_IYUV =      /**< Planar mode: Y + U + V  (3 planes) */  
    95.     SDL_DEFINE_PIXELFOURCC('I', 'Y', 'U', 'V'),  
    96. SDL_PIXELFORMAT_YUY2 =      /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */  
    97.     SDL_DEFINE_PIXELFOURCC('Y', 'U', 'Y', '2'),  
    98. SDL_PIXELFORMAT_UYVY =      /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */  
    99.     SDL_DEFINE_PIXELFOURCC('U', 'Y', 'V', 'Y'),  
    100. SDL_PIXELFORMAT_YVYU =      /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */  
    101.     SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U')  


    這一看確實給人一種“眼花繚亂”的感覺。簡單分析一下其中的定義吧。例如ARGB8888的定義如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. SDL_PIXELFORMAT_ARGB8888 =  
    2.         SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB,  
    3.                                SDL_PACKEDLAYOUT_8888, 32, 4),  


    其中用了一個宏SDL_DEFINE_PIXELFORMAT用于將幾種屬性合并到一個格式中。下面我們看看一個格式都包含哪些屬性:
    SDL_PIXELTYPE_PACKED32:代表了像素分量的存儲方式。PACKED代表了像素的幾個分量是一起存儲的,內存中存儲方式如下:R1|G1|B1,R2|G2|B2…;ARRAY則代表了像素的幾個分量是分開存儲的,內存中存儲方式如下:R1|R2|R3…,G1|G2|G3…,B1|B2|B3…
    SDL_PACKEDORDER_ARGB:代表了PACKED存儲方式下像素分量的順序。注意,這里所說的順序涉及到了一個“大端”和“小端”的問題。這個問題在《最簡單的視音頻播放示例2:GDI播放YUV, RGB》中已經敘述,不再重復記錄。對于Windows這樣的“小端”系統,“ARGB”格式在內存中的存儲順序是B|G|R|A。
    SDL_PACKEDLAYOUT_8888:說明了每個分量占據的比特數。例如ARGB格式每個分量分別占據了8bit。
    32:每個像素占用的比特數。例如ARGB格式占用了32bit(每個分量占據8bit)。
    4:每個像素占用的字節數。例如ARGB格式占用了4Byte(每個分量占據1Byte)。
     

    2.       循環顯示畫面

    1)       設置紋理的數據

    使用SDL_UpdateTexture()設置紋理的像素數據。SDL_UpdateTexture()的原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,  
    2.                                               const SDL_Rect * rect,  
    3.                                               const void *pixels, int pitch);  


    參數的含義如下。
    texture:目標紋理。
    rect:更新像素的矩形區域。設置為NULL的時候更新整個區域。
    pixels:像素數據。
    pitch:一行像素數據的字節數。
    成功的話返回0,失敗的話返回-1。
     
    2)       紋理復制給渲染目標
    使用SDL_RenderCopy()將紋理數據復制給渲染目標。在使用SDL_RenderCopy()之前,可以使用SDL_RenderClear()先使用清空渲染目標。實際上視頻播放的時候不使用SDL_RenderClear()也是可以的,因為視頻的后一幀會完全覆蓋前一幀。
    SDL_RenderClear()原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. int SDLCALL SDL_RenderClear(SDL_Renderer * renderer);  


    參數renderer用于指定渲染目標。
    SDL_RenderCopy()原型如下。

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer,  
    2.                                            SDL_Texture * texture,  
    3.                                            const SDL_Rect * srcrect,  
    4.                                            const SDL_Rect * dstrect);  


    參數的含義如下。
    renderer:渲染目標。
    texture:輸入紋理。
    srcrect:選擇輸入紋理的一塊矩形區域作為輸入。設置為NULL的時候整個紋理作為輸入。
    dstrect:選擇渲染目標的一塊矩形區域作為輸出。設置為NULL的時候整個渲染目標作為輸出。
    成功的話返回0,失敗的話返回-1。
     
    3)       顯示
    使用SDL_RenderPresent()顯示畫面。SDL_RenderPresent()原型如下。

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


     參數renderer用于指定渲染目標。

    流程總結


    在《最簡單的基于FFMPEG+SDL的視頻播放器 ver2(采用SDL2.0)》中總結過SDL2播放視頻的流程,在這里簡單復制過來。
    使用SDL播放視頻的流程可以概括為下圖。

    RFID設備管理軟件


    SDL中幾個關鍵的結構體之間的關系可以用下圖概述。

    RFID設備管理軟件


    簡單解釋一下各變量的作用:
    SDL_Window就是使用SDL的時候彈出的那個窗口。在SDL1.x版本中,只可以創建一個一個窗口。在SDL2.0版本中,可以創建多個窗口。
    SDL_Texture用于顯示YUV數據。一個SDL_Texture對應一幀YUV數據。
    SDL_Renderer用于渲染SDL_Texture至SDL_Window。
    SDL_Rect用于確定SDL_Texture顯示的位置。

     

    代碼

    貼出源代碼。

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. /** 
    2.  * 最簡單的SDL2播放視頻的例子(SDL2播放RGB/YUV) 
    3.  * Simplest Video Play SDL2 (SDL2 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.  * 本程序使用SDL2播放RGB/YUV視頻像素數據。SDL實際上是對底層繪圖 
    12.  * API(Direct3D,OpenGL)的封裝,使用起來明顯簡單于直接調用底層 
    13.  * API。 
    14.  * 
    15.  * 函數調用步驟如下:  
    16.  * 
    17.  * [初始化] 
    18.  * SDL_Init(): 初始化SDL。 
    19.  * SDL_CreateWindow(): 創建窗口(Window)。 
    20.  * SDL_CreateRenderer(): 基于窗口創建渲染器(Render)。 
    21.  * SDL_CreateTexture(): 創建紋理(Texture)。 
    22.  * 
    23.  * [循環渲染數據] 
    24.  * SDL_UpdateTexture(): 設置紋理的數據。 
    25.  * SDL_RenderCopy(): 紋理復制給渲染器。 
    26.  * SDL_RenderPresent(): 顯示。 
    27.  * 
    28.  * This software plays RGB/YUV raw video data using SDL2. 
    29.  * SDL is a wrapper of low-level API (Direct3D, OpenGL). 
    30.  * Use SDL is much easier than directly call these low-level API.   
    31.  * 
    32.  * The process is shown as follows: 
    33.  * 
    34.  * [Init] 
    35.  * SDL_Init(): Init SDL. 
    36.  * SDL_CreateWindow(): Create a Window. 
    37.  * SDL_CreateRenderer(): Create a Render. 
    38.  * SDL_CreateTexture(): Create a Texture. 
    39.  * 
    40.  * [Loop to Render data] 
    41.  * SDL_UpdateTexture(): Set Texture's data. 
    42.  * SDL_RenderCopy(): Copy Texture to Render. 
    43.  * SDL_RenderPresent(): Show. 
    44.  */  
    45.   
    46. #include <stdio.h>  
    47.   
    48. extern "C"  
    49. {  
    50. #include "sdl/SDL.h"  
    51. };  
    52.   
    53. //set '1' to choose a type of file to play  
    54. #define LOAD_BGRA    1  
    55. #define LOAD_RGB24   0  
    56. #define LOAD_BGR24   0  
    57. #define LOAD_YUV420P 0  
    58.   
    59. //Bit per Pixel  
    60. #if LOAD_BGRA  
    61. const int bpp=32;  
    62. #elif LOAD_RGB24|LOAD_BGR24  
    63. const int bpp=24;  
    64. #elif LOAD_YUV420P  
    65. const int bpp=12;  
    66. #endif  
    67.   
    68. int screen_w=500,screen_h=500;  
    69. const int pixel_w=320,pixel_h=180;  
    70.   
    71. unsigned char buffer[pixel_w*pixel_h*bpp/8];  
    72. //BPP=32  
    73. unsigned char buffer_convert[pixel_w*pixel_h*4];  
    74.   
    75. //Convert RGB24/BGR24 to RGB32/BGR32  
    76. //And change Endian if needed  
    77. void CONVERT_24to32(unsigned char *image_in,unsigned char *image_out,int w,int h){  
    78.     for(int i =0;i<h;i++)  
    79.         for(int j=0;j<w;j++){  
    80.             //Big Endian or Small Endian?  
    81.             //"ARGB" order:high bit -> low bit.  
    82.             //ARGB Format Big Endian (low address save high MSB, here is A) in memory : A|R|G|B  
    83.             //ARGB Format Little Endian (low address save low MSB, here is B) in memory : B|G|R|A  
    84.             if(SDL_BYTEORDER==SDL_LIL_ENDIAN){  
    85.                 //Little Endian (x86): R|G|B --> B|G|R|A  
    86.                 image_out[(i*w+j)*4+0]=image_in[(i*w+j)*3+2];  
    87.                 image_out[(i*w+j)*4+1]=image_in[(i*w+j)*3+1];  
    88.                 image_out[(i*w+j)*4+2]=image_in[(i*w+j)*3];  
    89.                 image_out[(i*w+j)*4+3]='0';  
    90.             }else{  
    91.                 //Big Endian: R|G|B --> A|R|G|B  
    92.                 image_out[(i*w+j)*4]='0';  
    93.                 memcpy(image_out+(i*w+j)*4+1,image_in+(i*w+j)*3,3);  
    94.             }  
    95.         }  
    96. }  
    97.   
    98.   
    99. //Refresh Event  
    100. #define REFRESH_EVENT  (SDL_USEREVENT + 1)  
    101.   
    102. int thread_exit=0;  
    103.   
    104. int refresh_video(void *opaque){  
    105.     while (thread_exit==0) {  
    106.         SDL_Event event;  
    107.         event.type = REFRESH_EVENT;  
    108.         SDL_PushEvent(&event);  
    109.         SDL_Delay(40);  
    110.     }  
    111.     return 0;  
    112. }  
    113.   
    114. int main(int argc, char* argv[])  
    115. {  
    116.     if(SDL_Init(SDL_INIT_VIDEO)) {    
    117.         printf( "Could not initialize SDL - %s\n", SDL_GetError());   
    118.         return -1;  
    119.     }   
    120.   
    121.     SDL_Window *screen;   
    122.     //SDL 2.0 Support for multiple windows  
    123.     screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,  
    124.         screen_w, screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);  
    125.     if(!screen) {    
    126.         printf("SDL: could not create window - exiting:%s\n",SDL_GetError());    
    127.         return -1;  
    128.     }  
    129.     SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);    
    130.   
    131.     Uint32 pixformat=0;  
    132. #if LOAD_BGRA  
    133.     //Note: ARGB8888 in "Little Endian" system stores as B|G|R|A  
    134.     pixformat= SDL_PIXELFORMAT_ARGB8888;    
    135. #elif LOAD_RGB24  
    136.     pixformat= SDL_PIXELFORMAT_RGB888;    
    137. #elif LOAD_BGR24  
    138.     pixformat= SDL_PIXELFORMAT_BGR888;    
    139. #elif LOAD_YUV420P  
    140.     //IYUV: Y + U + V  (3 planes)  
    141.     //YV12: Y + V + U  (3 planes)  
    142.     pixformat= SDL_PIXELFORMAT_IYUV;    
    143. #endif  
    144.   
    145.     SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);  
    146.   
    147.   
    148.   
    149.     FILE *fp=NULL;  
    150. #if LOAD_BGRA  
    151.     fp=fopen("../test_bgra_320x180.rgb","rb+");  
    152. #elif LOAD_RGB24  
    153.     fp=fopen("../test_rgb24_320x180.rgb","rb+");  
    154. #elif LOAD_BGR24  
    155.     fp=fopen("../test_bgr24_320x180.rgb","rb+");  
    156. #elif LOAD_YUV420P  
    157.     fp=fopen("../test_yuv420p_320x180.yuv","rb+");  
    158. #endif  
    159.     if(fp==NULL){  
    160.         printf("cannot open this file\n");  
    161.         return -1;  
    162.     }  
    163.   
    164.     SDL_Rect sdlRect;    
    165.   
    166.     SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video,NULL,NULL);  
    167.     SDL_Event event;  
    168.     while(1){  
    169.         //Wait  
    170.         SDL_WaitEvent(&event);  
    171.         if(event.type==REFRESH_EVENT){  
    172.             if (fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp) != pixel_w*pixel_h*bpp/8){  
    173.                 // Loop  
    174.                 fseek(fp, 0, SEEK_SET);  
    175.                 fread(buffer, 1, pixel_w*pixel_h*bpp/8, fp);  
    176.             }  
    177.   
    178. #if LOAD_BGRA  
    179.             //We don't need to change Endian  
    180.             //Because input BGRA pixel data(B|G|R|A) is same as ARGB8888 in Little Endian (B|G|R|A)  
    181.             SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w*4);    
    182. #elif LOAD_RGB24|LOAD_BGR24  
    183.             //change 24bit to 32 bit  
    184.             //and in Windows we need to change Endian  
    185.             CONVERT_24to32(buffer,buffer_convert,pixel_w,pixel_h);  
    186.             SDL_UpdateTexture( sdlTexture, NULL, buffer_convert, pixel_w*4);    
    187. #elif LOAD_YUV420P  
    188.             SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w);    
    189. #endif  
    190.             //FIX: If window is resize  
    191.             sdlRect.x = 0;    
    192.             sdlRect.y = 0;    
    193.             sdlRect.w = screen_w;    
    194.             sdlRect.h = screen_h;    
    195.               
    196.             SDL_RenderClear( sdlRenderer );     
    197.             SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, &sdlRect);    
    198.             SDL_RenderPresent( sdlRenderer );    
    199.             //Delay 40ms  
    200.             SDL_Delay(40);  
    201.               
    202.         }else if(event.type==SDL_WINDOWEVENT){  
    203.             //If Resize  
    204.             SDL_GetWindowSize(screen,&screen_w,&screen_h);  
    205.         }else if(event.type==SDL_QUIT){  
    206.             break;  
    207.         }  
    208.     }  
    209.   
    210.     return 0;  
    211. }  



     

    運行結果

    程序的運行結果如下圖所示。

    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/40525591

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