日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最简单的视音频播放示例7:SDL2播放RGB/YUV

發布時間:2025/3/8 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最简单的视音频播放示例7:SDL2播放RGB/YUV 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最簡單的視音頻播放示例系列文章列表:

最簡單的視音頻播放示例1:總述

最簡單的視音頻播放示例2:GDI播放YUV, RGB

最簡單的視音頻播放示例3:Direct3D播放YUV,RGB(通過Surface)

最簡單的視音頻播放示例4:Direct3D播放RGB(通過Texture)

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

最簡單的視音頻播放示例6:OpenGL播放YUV420P(通過Texture,使用Shader)

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

最簡單的視音頻播放示例8:DirectSound播放PCM

最簡單的視音頻播放示例9:SDL2播放PCM

=====================================================

?

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

?

SDL簡介


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


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
  • 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
  • SDL_Window?*?SDLCALL?SDL_CreateWindow(const?char?*title,??
  • ??????????????????????????????????????????????????????int?x,?int?y,?int?w,??
  • ??????????????????????????????????????????????????????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
  • SDL_Renderer?*?SDLCALL?SDL_CreateRenderer(SDL_Window?*?window,??
  • ???????????????????????????????????????????????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
  • SDL_Texture?*?SDLCALL?SDL_CreateTexture(SDL_Renderer?*?renderer,??
  • ????????????????????????????????????????????????????????Uint32?format,??
  • ????????????????????????????????????????????????????????int?access,?int?w,??
  • ????????????????????????????????????????????????????????int?h);??

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

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

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

    [cpp] view plaincopy
  • SDL_PIXELFORMAT_UNKNOWN,??
  • SDL_PIXELFORMAT_INDEX1LSB?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1,?SDL_BITMAPORDER_4321,?0,??
  • ???????????????????????????1,?0),??
  • SDL_PIXELFORMAT_INDEX1MSB?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1,?SDL_BITMAPORDER_1234,?0,??
  • ???????????????????????????1,?0),??
  • SDL_PIXELFORMAT_INDEX4LSB?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4,?SDL_BITMAPORDER_4321,?0,??
  • ???????????????????????????4,?0),??
  • SDL_PIXELFORMAT_INDEX4MSB?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4,?SDL_BITMAPORDER_1234,?0,??
  • ???????????????????????????4,?0),??
  • SDL_PIXELFORMAT_INDEX8?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX8,?0,?0,?8,?1),??
  • SDL_PIXELFORMAT_RGB332?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED8,?SDL_PACKEDORDER_XRGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_332,?8,?1),??
  • SDL_PIXELFORMAT_RGB444?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_XRGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_4444,?12,?2),??
  • SDL_PIXELFORMAT_RGB555?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_XRGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_1555,?15,?2),??
  • SDL_PIXELFORMAT_BGR555?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_XBGR,??
  • ???????????????????????????SDL_PACKEDLAYOUT_1555,?15,?2),??
  • SDL_PIXELFORMAT_ARGB4444?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_ARGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_4444,?16,?2),??
  • SDL_PIXELFORMAT_RGBA4444?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_RGBA,??
  • ???????????????????????????SDL_PACKEDLAYOUT_4444,?16,?2),??
  • SDL_PIXELFORMAT_ABGR4444?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_ABGR,??
  • ???????????????????????????SDL_PACKEDLAYOUT_4444,?16,?2),??
  • SDL_PIXELFORMAT_BGRA4444?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_BGRA,??
  • ???????????????????????????SDL_PACKEDLAYOUT_4444,?16,?2),??
  • SDL_PIXELFORMAT_ARGB1555?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_ARGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_1555,?16,?2),??
  • SDL_PIXELFORMAT_RGBA5551?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_RGBA,??
  • ???????????????????????????SDL_PACKEDLAYOUT_5551,?16,?2),??
  • SDL_PIXELFORMAT_ABGR1555?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_ABGR,??
  • ???????????????????????????SDL_PACKEDLAYOUT_1555,?16,?2),??
  • SDL_PIXELFORMAT_BGRA5551?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_BGRA,??
  • ???????????????????????????SDL_PACKEDLAYOUT_5551,?16,?2),??
  • SDL_PIXELFORMAT_RGB565?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_XRGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_565,?16,?2),??
  • SDL_PIXELFORMAT_BGR565?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED16,?SDL_PACKEDORDER_XBGR,??
  • ???????????????????????????SDL_PACKEDLAYOUT_565,?16,?2),??
  • SDL_PIXELFORMAT_RGB24?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_ARRAYU8,?SDL_ARRAYORDER_RGB,?0,??
  • ???????????????????????????24,?3),??
  • SDL_PIXELFORMAT_BGR24?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_ARRAYU8,?SDL_ARRAYORDER_BGR,?0,??
  • ???????????????????????????24,?3),??
  • SDL_PIXELFORMAT_RGB888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_XRGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?24,?4),??
  • SDL_PIXELFORMAT_RGBX8888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_RGBX,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?24,?4),??
  • SDL_PIXELFORMAT_BGR888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_XBGR,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?24,?4),??
  • SDL_PIXELFORMAT_BGRX8888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_BGRX,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?24,?4),??
  • SDL_PIXELFORMAT_ARGB8888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_ARGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?32,?4),??
  • SDL_PIXELFORMAT_RGBA8888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_RGBA,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?32,?4),??
  • SDL_PIXELFORMAT_ABGR8888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_ABGR,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?32,?4),??
  • SDL_PIXELFORMAT_BGRA8888?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_BGRA,??
  • ???????????????????????????SDL_PACKEDLAYOUT_8888,?32,?4),??
  • SDL_PIXELFORMAT_ARGB2101010?=??
  • ????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_ARGB,??
  • ???????????????????????????SDL_PACKEDLAYOUT_2101010,?32,?4),??
  • ??
  • SDL_PIXELFORMAT_YV12?=??????/**<?Planar?mode:?Y?+?V?+?U??(3?planes)?*/??
  • ????SDL_DEFINE_PIXELFOURCC('Y',?'V',?'1',?'2'),??
  • SDL_PIXELFORMAT_IYUV?=??????/**<?Planar?mode:?Y?+?U?+?V??(3?planes)?*/??
  • ????SDL_DEFINE_PIXELFOURCC('I',?'Y',?'U',?'V'),??
  • SDL_PIXELFORMAT_YUY2?=??????/**<?Packed?mode:?Y0+U0+Y1+V0?(1?plane)?*/??
  • ????SDL_DEFINE_PIXELFOURCC('Y',?'U',?'Y',?'2'),??
  • SDL_PIXELFORMAT_UYVY?=??????/**<?Packed?mode:?U0+Y0+V0+Y1?(1?plane)?*/??
  • ????SDL_DEFINE_PIXELFOURCC('U',?'Y',?'V',?'Y'),??
  • SDL_PIXELFORMAT_YVYU?=??????/**<?Packed?mode:?Y0+V0+Y1+U0?(1?plane)?*/??
  • ????SDL_DEFINE_PIXELFOURCC('Y',?'V',?'Y',?'U')??

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

    [cpp] view plaincopy
  • SDL_PIXELFORMAT_ARGB8888?=??
  • ????????SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32,?SDL_PACKEDORDER_ARGB,??
  • ???????????????????????????????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
  • int?SDLCALL?SDL_UpdateTexture(SDL_Texture?*?texture,??
  • ??????????????????????????????????????????????const?SDL_Rect?*?rect,??
  • ??????????????????????????????????????????????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
  • int?SDLCALL?SDL_RenderClear(SDL_Renderer?*?renderer);??

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

    [cpp] view plaincopy
  • int?SDLCALL?SDL_RenderCopy(SDL_Renderer?*?renderer,??
  • ???????????????????????????????????????????SDL_Texture?*?texture,??
  • ???????????????????????????????????????????const?SDL_Rect?*?srcrect,??
  • ???????????????????????????????????????????const?SDL_Rect?*?dstrect);??

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

    [cpp] view plaincopy
  • void?SDLCALL?SDL_RenderPresent(SDL_Renderer?*?renderer);??

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

    流程總結


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


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


    簡單解釋一下各變量的作用:
    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
  • /**?
  • ?*?最簡單的SDL2播放視頻的例子(SDL2播放RGB/YUV)?
  • ?*?Simplest?Video?Play?SDL2?(SDL2?play?RGB/YUV)??
  • ?*?
  • ?*?雷霄驊?Lei?Xiaohua?
  • ?*?leixiaohua1020@126.com?
  • ?*?中國傳媒大學/數字電視技術?
  • ?*?Communication?University?of?China?/?Digital?TV?Technology?
  • ?*?http://blog.csdn.net/leixiaohua1020?
  • ?*?
  • ?*?本程序使用SDL2播放RGB/YUV視頻像素數據。SDL實際上是對底層繪圖?
  • ?*?API(Direct3D,OpenGL)的封裝,使用起來明顯簡單于直接調用底層?
  • ?*?API。?
  • ?*?
  • ?*?函數調用步驟如下:??
  • ?*?
  • ?*?[初始化]?
  • ?*?SDL_Init():?初始化SDL。?
  • ?*?SDL_CreateWindow():?創建窗口(Window)。?
  • ?*?SDL_CreateRenderer():?基于窗口創建渲染器(Render)。?
  • ?*?SDL_CreateTexture():?創建紋理(Texture)。?
  • ?*?
  • ?*?[循環渲染數據]?
  • ?*?SDL_UpdateTexture():?設置紋理的數據。?
  • ?*?SDL_RenderCopy():?紋理復制給渲染器。?
  • ?*?SDL_RenderPresent():?顯示。?
  • ?*?
  • ?*?This?software?plays?RGB/YUV?raw?video?data?using?SDL2.?
  • ?*?SDL?is?a?wrapper?of?low-level?API?(Direct3D,?OpenGL).?
  • ?*?Use?SDL?is?much?easier?than?directly?call?these?low-level?API.???
  • ?*?
  • ?*?The?process?is?shown?as?follows:?
  • ?*?
  • ?*?[Init]?
  • ?*?SDL_Init():?Init?SDL.?
  • ?*?SDL_CreateWindow():?Create?a?Window.?
  • ?*?SDL_CreateRenderer():?Create?a?Render.?
  • ?*?SDL_CreateTexture():?Create?a?Texture.?
  • ?*?
  • ?*?[Loop?to?Render?data]?
  • ?*?SDL_UpdateTexture():?Set?Texture's?data.?
  • ?*?SDL_RenderCopy():?Copy?Texture?to?Render.?
  • ?*?SDL_RenderPresent():?Show.?
  • ?*/??
  • ??
  • #include?<stdio.h>??
  • ??
  • extern?"C"??
  • {??
  • #include?"sdl/SDL.h"??
  • };??
  • ??
  • //set?'1'?to?choose?a?type?of?file?to?play??
  • #define?LOAD_BGRA????1??
  • #define?LOAD_RGB24???0??
  • #define?LOAD_BGR24???0??
  • #define?LOAD_YUV420P?0??
  • ??
  • //Bit?per?Pixel??
  • #if?LOAD_BGRA??
  • const?int?bpp=32;??
  • #elif?LOAD_RGB24|LOAD_BGR24??
  • const?int?bpp=24;??
  • #elif?LOAD_YUV420P??
  • const?int?bpp=12;??
  • #endif??
  • ??
  • int?screen_w=500,screen_h=500;??
  • const?int?pixel_w=320,pixel_h=180;??
  • ??
  • unsigned?char?buffer[pixel_w*pixel_h*bpp/8];??
  • //BPP=32??
  • unsigned?char?buffer_convert[pixel_w*pixel_h*4];??
  • ??
  • //Convert?RGB24/BGR24?to?RGB32/BGR32??
  • //And?change?Endian?if?needed??
  • void?CONVERT_24to32(unsigned?char?*image_in,unsigned?char?*image_out,int?w,int?h){??
  • ????for(int?i?=0;i<h;i++)??
  • ????????for(int?j=0;j<w;j++){??
  • ????????????//Big?Endian?or?Small?Endian???
  • ????????????//"ARGB"?order:high?bit?->?low?bit.??
  • ????????????//ARGB?Format?Big?Endian?(low?address?save?high?MSB,?here?is?A)?in?memory?:?A|R|G|B??
  • ????????????//ARGB?Format?Little?Endian?(low?address?save?low?MSB,?here?is?B)?in?memory?:?B|G|R|A??
  • ????????????if(SDL_BYTEORDER==SDL_LIL_ENDIAN){??
  • ????????????????//Little?Endian?(x86):?R|G|B?-->?B|G|R|A??
  • ????????????????image_out[(i*w+j)*4+0]=image_in[(i*w+j)*3+2];??
  • ????????????????image_out[(i*w+j)*4+1]=image_in[(i*w+j)*3+1];??
  • ????????????????image_out[(i*w+j)*4+2]=image_in[(i*w+j)*3];??
  • ????????????????image_out[(i*w+j)*4+3]='0';??
  • ????????????}else{??
  • ????????????????//Big?Endian:?R|G|B?-->?A|R|G|B??
  • ????????????????image_out[(i*w+j)*4]='0';??
  • ????????????????memcpy(image_out+(i*w+j)*4+1,image_in+(i*w+j)*3,3);??
  • ????????????}??
  • ????????}??
  • }??
  • ??
  • ??
  • //Refresh?Event??
  • #define?REFRESH_EVENT??(SDL_USEREVENT?+?1)??
  • ??
  • int?thread_exit=0;??
  • ??
  • int?refresh_video(void?*opaque){??
  • ????while?(thread_exit==0)?{??
  • ????????SDL_Event?event;??
  • ????????event.type?=?REFRESH_EVENT;??
  • ????????SDL_PushEvent(&event);??
  • ????????SDL_Delay(40);??
  • ????}??
  • ????return?0;??
  • }??
  • ??
  • int?main(int?argc,?char*?argv[])??
  • {??
  • ????if(SDL_Init(SDL_INIT_VIDEO))?{????
  • ????????printf(?"Could?not?initialize?SDL?-?%s\n",?SDL_GetError());???
  • ????????return?-1;??
  • ????}???
  • ??
  • ????SDL_Window?*screen;???
  • ????//SDL?2.0?Support?for?multiple?windows??
  • ????screen?=?SDL_CreateWindow("Simplest?Video?Play?SDL2",?SDL_WINDOWPOS_UNDEFINED,?SDL_WINDOWPOS_UNDEFINED,??
  • ????????screen_w,?screen_h,SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);??
  • ????if(!screen)?{????
  • ????????printf("SDL:?could?not?create?window?-?exiting:%s\n",SDL_GetError());????
  • ????????return?-1;??
  • ????}??
  • ????SDL_Renderer*?sdlRenderer?=?SDL_CreateRenderer(screen,?-1,?0);????
  • ??
  • ????Uint32?pixformat=0;??
  • #if?LOAD_BGRA??
  • ????//Note:?ARGB8888?in?"Little?Endian"?system?stores?as?B|G|R|A??
  • ????pixformat=?SDL_PIXELFORMAT_ARGB8888;????
  • #elif?LOAD_RGB24??
  • ????pixformat=?SDL_PIXELFORMAT_RGB888;????
  • #elif?LOAD_BGR24??
  • ????pixformat=?SDL_PIXELFORMAT_BGR888;????
  • #elif?LOAD_YUV420P??
  • ????//IYUV:?Y?+?U?+?V??(3?planes)??
  • ????//YV12:?Y?+?V?+?U??(3?planes)??
  • ????pixformat=?SDL_PIXELFORMAT_IYUV;????
  • #endif??
  • ??
  • ????SDL_Texture*?sdlTexture?=?SDL_CreateTexture(sdlRenderer,pixformat,?SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);??
  • ??
  • ??
  • ??
  • ????FILE?*fp=NULL;??
  • #if?LOAD_BGRA??
  • ????fp=fopen("../test_bgra_320x180.rgb","rb+");??
  • #elif?LOAD_RGB24??
  • ????fp=fopen("../test_rgb24_320x180.rgb","rb+");??
  • #elif?LOAD_BGR24??
  • ????fp=fopen("../test_bgr24_320x180.rgb","rb+");??
  • #elif?LOAD_YUV420P??
  • ????fp=fopen("../test_yuv420p_320x180.yuv","rb+");??
  • #endif??
  • ????if(fp==NULL){??
  • ????????printf("cannot?open?this?file\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????SDL_Rect?sdlRect;????
  • ??
  • ????SDL_Thread?*refresh_thread?=?SDL_CreateThread(refresh_video,NULL,NULL);??
  • ????SDL_Event?event;??
  • ????while(1){??
  • ????????//Wait??
  • ????????SDL_WaitEvent(&event);??
  • ????????if(event.type==REFRESH_EVENT){??
  • ????????????if?(fread(buffer,?1,?pixel_w*pixel_h*bpp/8,?fp)?!=?pixel_w*pixel_h*bpp/8){??
  • ????????????????//?Loop??
  • ????????????????fseek(fp,?0,?SEEK_SET);??
  • ????????????????fread(buffer,?1,?pixel_w*pixel_h*bpp/8,?fp);??
  • ????????????}??
  • ??
  • #if?LOAD_BGRA??
  • ????????????//We?don't?need?to?change?Endian??
  • ????????????//Because?input?BGRA?pixel?data(B|G|R|A)?is?same?as?ARGB8888?in?Little?Endian?(B|G|R|A)??
  • ????????????SDL_UpdateTexture(?sdlTexture,?NULL,?buffer,?pixel_w*4);????
  • #elif?LOAD_RGB24|LOAD_BGR24??
  • ????????????//change?24bit?to?32?bit??
  • ????????????//and?in?Windows?we?need?to?change?Endian??
  • ????????????CONVERT_24to32(buffer,buffer_convert,pixel_w,pixel_h);??
  • ????????????SDL_UpdateTexture(?sdlTexture,?NULL,?buffer_convert,?pixel_w*4);????
  • #elif?LOAD_YUV420P??
  • ????????????SDL_UpdateTexture(?sdlTexture,?NULL,?buffer,?pixel_w);????
  • #endif??
  • ????????????//FIX:?If?window?is?resize??
  • ????????????sdlRect.x?=?0;????
  • ????????????sdlRect.y?=?0;????
  • ????????????sdlRect.w?=?screen_w;????
  • ????????????sdlRect.h?=?screen_h;????
  • ??????????????
  • ????????????SDL_RenderClear(?sdlRenderer?);?????
  • ????????????SDL_RenderCopy(?sdlRenderer,?sdlTexture,?NULL,?&sdlRect);????
  • ????????????SDL_RenderPresent(?sdlRenderer?);????
  • ????????????//Delay?40ms??
  • ????????????SDL_Delay(40);??
  • ??????????????
  • ????????}else?if(event.type==SDL_WINDOWEVENT){??
  • ????????????//If?Resize??
  • ????????????SDL_GetWindowSize(screen,&screen_w,&screen_h);??
  • ????????}else?if(event.type==SDL_QUIT){??
  • ????????????break;??
  • ????????}??
  • ????}??
  • ??
  • ????return?0;??
  • }??


  • 運行結果

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

    ?

    下載


    代碼位于“Simplest Media Play”中
    ?
    ?

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

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

    ?
    ?

    注:

    該項目會不定時的更新并修復一些小問題,最新的版本請參考該系列文章的總述頁面:

    ?《最簡單的視音頻播放示例1:總述》


    上述工程包含了使用各種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視頻像素數據。

    總結

    以上是生活随笔為你收集整理的最简单的视音频播放示例7:SDL2播放RGB/YUV的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 色妇网| 一色av | 少妇性bbb搡bbb爽爽爽欧美 | 99资源网 | 男同激情视频 | 手机看片1024欧美 | 中文字幕三区 | 女色婷婷 | 国产精品男同 | 久久久久久久国产视频 | 色网导航站 | 一级片毛片 | 香蕉视频毛片 | 波多野结衣国产在线 | 国产一线二线三线女 | 美日韩久久| 99久久久久久久 | 丝袜国产一区 | 精品91在线| 亚洲无限观看 | 猛1被调教成公厕尿便失禁网站 | 男女猛烈无遮挡 | av在线不卡一区 | 日一区二区 | 亚洲在线激情 | 姑娘第5集高清在线观看 | 午夜视频在线网站 | 第一福利在线 | 国产a毛片 | 黑人爱爱视频 | 午夜久久电影 | 国产成人 综合 亚洲 | 精品一二三 | 精品久久一区二区三区 | av免费视屏| 国产精品欧美综合亚洲 | 亚洲а∨天堂久久精品2021 | 免费看黄色片网站 | 黄色视屏在线 | 日日摸夜夜添夜夜添高潮喷水 | 亚洲欧美日韩一区二区三区在线观看 | 免费啪 | 象人高潮调教丨vk | 少妇毛片一区二区三区粉嫩av | 亚洲欧美一区在线 | 久久亚洲AV成人无码一二三 | 体内精69xxxxxx| 午夜欧美精品久久久久久久 | 国产精品香蕉在线观看 | 超碰在线国产97 | 亚洲理论电影在线观看 | 国产熟女高潮视频 | 女同另类之国产女同 | 奇米综合| 日韩在线观看中文字幕 | 国产宾馆实践打屁股91 | 高h放荡受浪受bl | 99在线精品免费视频 | 日韩一区二区在线观看 | 欧美专区亚洲专区 | 色噜噜一区二区三区 | 欧美精品性生活 | 国产aaa级片| 先锋资源中文字幕 | 亚洲国产精 | 黄色资源网站 | 日本久热 | 欧美视频在线一区二区三区 | 久久中文字幕av | 亚洲综合a | 后进极品白嫩翘臀在线视频 | 韩国日本欧美一区 | 亚洲人女屁股眼交6 | 国产三级一区二区三区 | 亚洲精品乱码久久久久久9色 | 日本黄色三级网站 | 国产一区2区 | 一本一道波多野结衣一区二区 | 人人妻一区二区三区 | 五月综合色 | 日本三级黄在线观看 | 五月天婷婷伊人 | 日本免费不卡一区二区 | 在线xxxxx| 天堂视频中文在线 | 先锋影音一区二区 | 两个女人互添下身爱爱 | 91传媒理伦片在线观看 | 男人添女人囗交视频 | 成人免费毛片嘿嘿连载 | 精品一区二区三区视频在线观看 | 成人香蕉视频 | 色吊丝一区二区 | 娇妻之欲海泛舟无弹窗笔趣阁 | 国产精品人人做人人爽 | 少妇呻吟视频 | 九九久久国产精品 | 日韩在线观看网站 | 不卡网av|