最簡單的視音頻播放示例系列文章列表:
最簡單的視音頻播放示例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播放視頻的技術(shù)。在這里使用的版本是SDL2。實際上SDL本身并不提供視音頻播放的功能,它只是封裝了視音頻播放的底層API。在Windows平臺下,SDL封裝了Direct3D這類的API用于播放視頻;封裝了DirectSound這類的API用于播放音頻。因為SDL的編寫目的就是簡化視音頻播放的開發(fā)難度,所以使用SDL播放視頻(YUV/RGB)和音頻(PCM)數(shù)據(jù)非常的容易。下文記錄一下使用SDL播放視頻數(shù)據(jù)的技術(shù)。
?
SDL簡介 SDL(Simple DirectMedia Layer)是一套開放源代碼的跨平臺多媒體開發(fā)庫,使用C語言寫成。SDL提供了數(shù)種控制圖像、聲音、輸出入的函數(shù),讓開發(fā)者只要用相同或是相似的代碼就可以開發(fā)出跨多個平臺(Linux、Windows、Mac OS X等)的應(yīng)用軟件。目前SDL多用于開發(fā)游戲、模擬器、媒體播放器等多媒體應(yīng)用領(lǐng)域。用下面這張圖可以很明確地說明SDL的位置。
SDL實際上并不限于視音頻的播放,它將功能分成下列數(shù)個子系統(tǒng)(subsystem):
Video(圖像):圖像控制以及線程(thread)和事件管理(event)。
Audio(聲音):聲音控制
Joystick(搖桿):游戲搖桿控制
CD-ROM(光盤驅(qū)動器):光盤媒體控制
Window Management(視窗管理):與視窗程序設(shè)計集成
Event(事件驅(qū)動):處理事件驅(qū)動
?
在Windows下,SDL與DirectX的對應(yīng)關(guān)系如下。
SDL
DirectX
SDL_Video、SDL_Image
DirectDraw、Direct3D
SDL_Audio、SDL_Mixer
DirectSound
SDL_Joystick、SDL_Base
DirectInput
SDL_Net
DirectPlay
?
SDL播放視頻的流程 SDL播放視頻的技術(shù)在此前做的FFmpeg的示例程序中已經(jīng)多次用到。在這里重新總結(jié)一下流程。 ? 1. ? ? ? 初始化
1) ? ? ? ? 初始化SDL
2) ? ? ? ? 創(chuàng)建窗口(Window)
3) ? ? ? ? 基于窗口創(chuàng)建渲染器(Render)
4) ? ? ? ? 創(chuàng)建紋理(Texture)
2. ? ? ? 循環(huán)顯示畫面
1) ? ? ? 設(shè)置紋理的數(shù)據(jù)
2) ? ? ? 紋理復(fù)制給渲染目標(biāo)
3) ? ? ? 顯示
? 下面詳細(xì)分析一下上文的流程。
1. ? ? ? 初始化
1) ? ? ? ? 初始化SDL
使用SDL_Init()初始化SDL。該函數(shù)可以確定希望激活的子系統(tǒng)。SDL_Init()函數(shù)原型如下:
[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:不捕獲關(guān)鍵信號(這個沒研究過)
SDL_INIT_EVERYTHING:包含上述所有選項
?
有關(guān)SDL_Init()有一點需要注意:初始化的時候盡量做到“夠用就好”,而不要用SDL_INIT_EVERYTHING。因為有些情況下使用SDL_INIT_EVERYTHING會出現(xiàn)一些不可預(yù)知的問題。例如,在MFC應(yīng)用程序中播放純音頻,如果初始化SDL的時候使用SDL_INIT_EVERYTHING,那么就會出現(xiàn)聽不到聲音的情況。后來發(fā)現(xiàn),去掉了SDL_INIT_VIDEO之后,問題才得以解決。
?2) ? ? ? ? 創(chuàng)建窗口(Window) 使用SDL_CreateWindow()創(chuàng)建一個用于視頻播放的窗口。SDL_CreateWindow()的原型如下。
[cpp] view plaincopy
SDL_Window?*?SDLCALL?SDL_CreateWindow(const?char?*title,?? ??????????????????????????????????????????????????????int?x,?int?y,?int?w,?? ??????????????????????????????????????????????????????int?h,?Uint32?flags);?? 參數(shù)含義如下。 title ?:窗口標(biāo)題 x ? ? ? :窗口位置x坐標(biāo)。也可以設(shè)置為SDL_WINDOWPOS_CENTERED或SDL_WINDOWPOS_UNDEFINED。 y ? ? ? :窗口位置y坐標(biāo)。同上。 w ? ? ?:窗口的寬 h ? ? ? :窗口的高 flags :支持下列標(biāo)識。包括了窗口的是否最大化、最小化,能否調(diào)整邊界等等屬性。 ? ? ? ?::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. ?返回創(chuàng)建完成的窗口的ID。如果創(chuàng)建失敗則返回0。 ? ?3) ? ? ? ? 基于窗口創(chuàng)建渲染器(Render) 使用SDL_CreateRenderer()基于窗口創(chuàng)建渲染器。SDL_CreateRenderer()原型如下。
[cpp] view plaincopy
SDL_Renderer?*?SDLCALL?SDL_CreateRenderer(SDL_Window?*?window,?? ???????????????????????????????????????????????int?index,?Uint32?flags);?? 參數(shù)含義如下。 window ? ?: 渲染的目標(biāo)窗口。 index ? ? ? ? :打算初始化的渲染設(shè)備的索引。設(shè)置“-1”則初始化默認(rèn)的渲染設(shè)備。 flags ? ? ? ? ?:支持以下值(位于SDL_RendererFlags定義中)
SDL_RENDERER_SOFTWARE :使用軟件渲染
? ? SDL_RENDERER_ACCELERATED :使用硬件加速
? ? SDL_RENDERER_PRESENTVSYNC:和顯示器的刷新率同步
? ? SDL_RENDERER_TARGETTEXTURE :不太懂
返回創(chuàng)建完成的渲染器的ID。如果創(chuàng)建失敗則返回NULL。 ?4) ? ? ? ? 創(chuàng)建紋理(Texture) 使用SDL_CreateTexture()基于渲染器創(chuàng)建一個紋理。SDL_CreateTexture()的原型如下。
[cpp] view plaincopy
SDL_Texture?*?SDLCALL?SDL_CreateTexture(SDL_Renderer?*?renderer,?? ????????????????????????????????????????????????????????Uint32?format,?? ????????????????????????????????????????????????????????int?access,?int?w,?? ????????????????????????????????????????????????????????int?h);?? 參數(shù)的含義如下。 renderer:目標(biāo)渲染器。 format ? ? ?:紋理的格式。后面會詳述。 access ? ? ?:可以取以下值(定義位于SDL_TextureAccess中)
SDL_TEXTUREACCESS_STATIC ? ? ? ? :變化極少
? ? SDL_TEXTUREACCESS_STREAMING ? ? ? ?:變化頻繁
? ? SDL_TEXTUREACCESS_TARGET ? ? ? :暫時沒有理解
w ? ? ? ? ? ? ? :紋理的寬 h ? ? ? ? ? ? ? ?:紋理的高 創(chuàng)建成功則返回紋理的ID,失敗返回0。 ? 在紋理的創(chuàng)建過程中,需要指定紋理的格式(即第二個參數(shù))。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?=?????? ????SDL_DEFINE_PIXELFOURCC('Y',?'V',?'1',?'2'),?? SDL_PIXELFORMAT_IYUV?=?????? ????SDL_DEFINE_PIXELFOURCC('I',?'Y',?'U',?'V'),?? SDL_PIXELFORMAT_YUY2?=?????? ????SDL_DEFINE_PIXELFOURCC('Y',?'U',?'Y',?'2'),?? SDL_PIXELFORMAT_UYVY?=?????? ????SDL_DEFINE_PIXELFOURCC('U',?'Y',?'V',?'Y'),?? SDL_PIXELFORMAT_YVYU?=?????? ????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代表了像素的幾個分量是一起存儲的,內(nèi)存中存儲方式如下:R1|G1|B1,R2|G2|B2…;ARRAY則代表了像素的幾個分量是分開存儲的,內(nèi)存中存儲方式如下:R1|R2|R3…,G1|G2|G3…,B1|B2|B3…SDL_PACKEDORDER_ARGB :代表了PACKED存儲方式下像素分量的順序。注意,這里所說的順序涉及到了一個“大端”和“小端”的問題。這個問題在《最簡單的視音頻播放示例2:GDI播放YUV, RGB》中已經(jīng)敘述,不再重復(fù)記錄。對于Windows這樣的“小端”系統(tǒng),“ARGB”格式在內(nèi)存中的存儲順序是B|G|R|A。SDL_PACKEDLAYOUT_8888 :說明了每個分量占據(jù)的比特數(shù)。例如ARGB格式每個分量分別占據(jù)了8bit。32 :每個像素占用的比特數(shù)。例如ARGB格式占用了32bit(每個分量占據(jù)8bit)。4 :每個像素占用的字節(jié)數(shù)。例如ARGB格式占用了4Byte(每個分量占據(jù)1Byte)。 ?
2. ? ? ? 循環(huán)顯示畫面
1) ? ? ? 設(shè)置紋理的數(shù)據(jù)
使用SDL_UpdateTexture()設(shè)置紋理的像素數(shù)據(jù)。SDL_UpdateTexture()的原型如下。
[cpp] view plaincopy
int?SDLCALL?SDL_UpdateTexture(SDL_Texture?*?texture,?? ??????????????????????????????????????????????const?SDL_Rect?*?rect,?? ??????????????????????????????????????????????const?void?*pixels,?int?pitch);?? 參數(shù)的含義如下。 texture:目標(biāo)紋理。 rect:更新像素的矩形區(qū)域。設(shè)置為NULL的時候更新整個區(qū)域。 pixels:像素數(shù)據(jù)。 pitch:一行像素數(shù)據(jù)的字節(jié)數(shù)。 成功的話返回0,失敗的話返回-1。 ? 2) ? ? ? 紋理復(fù)制給渲染目標(biāo) 使用SDL_RenderCopy()將紋理數(shù)據(jù)復(fù)制給渲染目標(biāo)。在使用SDL_RenderCopy()之前,可以使用SDL_RenderClear()先使用清空渲染目標(biāo)。實際上視頻播放的時候不使用SDL_RenderClear()也是可以的,因為視頻的后一幀會完全覆蓋前一幀。 SDL_RenderClear()原型如下。
[cpp] view plaincopy
int?SDLCALL?SDL_RenderClear(SDL_Renderer?*?renderer);?? 參數(shù)renderer用于指定渲染目標(biāo)。 SDL_RenderCopy()原型如下。
[cpp] view plaincopy
int?SDLCALL?SDL_RenderCopy(SDL_Renderer?*?renderer,?? ???????????????????????????????????????????SDL_Texture?*?texture,?? ???????????????????????????????????????????const?SDL_Rect?*?srcrect,?? ???????????????????????????????????????????const?SDL_Rect?*?dstrect);?? 參數(shù)的含義如下。 renderer:渲染目標(biāo)。 texture:輸入紋理。 srcrect:選擇輸入紋理的一塊矩形區(qū)域作為輸入。設(shè)置為NULL的時候整個紋理作為輸入。 dstrect:選擇渲染目標(biāo)的一塊矩形區(qū)域作為輸出。設(shè)置為NULL的時候整個渲染目標(biāo)作為輸出。 成功的話返回0,失敗的話返回-1。 ? 3) ? ? ? 顯示 使用SDL_RenderPresent()顯示畫面。SDL_RenderPresent()原型如下。
[cpp] view plaincopy
void?SDLCALL?SDL_RenderPresent(SDL_Renderer?*?renderer);?? ?參數(shù)renderer用于指定渲染目標(biāo)。
流程總結(jié) 在《最簡單的基于FFMPEG+SDL的視頻播放器 ver2(采用SDL2.0)》中總結(jié)過SDL2播放視頻的流程,在這里簡單復(fù)制過來。 使用SDL播放視頻的流程可以概括為下圖。
SDL中幾個關(guān)鍵的結(jié)構(gòu)體之間的關(guān)系可以用下圖概述。
簡單解釋一下各變量的作用: SDL_Window就是使用SDL的時候彈出的那個窗口。在SDL1.x版本中,只可以創(chuàng)建一個一個窗口。在SDL2.0版本中,可以創(chuàng)建多個窗口。 SDL_Texture用于顯示YUV數(shù)據(jù)。一個SDL_Texture對應(yīng)一幀YUV數(shù)據(jù)。 SDL_Renderer用于渲染SDL_Texture至SDL_Window。 SDL_Rect用于確定SDL_Texture顯示的位置。
?
代碼 貼出源代碼。
[cpp] view plaincopy
?? #include?<stdio.h>?? ?? extern?"C"?? {?? #include?"sdl/SDL.h"?? };?? ?? #define?LOAD_BGRA????1?? #define?LOAD_RGB24???0?? #define?LOAD_BGR24???0?? #define?LOAD_YUV420P?0?? ?? #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];?? unsigned?char?buffer_convert[pixel_w*pixel_h*4];?? ?? 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++){?? ???????????? ???????????? ???????????? ???????????? ????????????if(SDL_BYTEORDER==SDL_LIL_ENDIAN){?? ???????????????? ????????????????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{?? ???????????????? ????????????????image_out[(i*w+j)*4]='0';?? ????????????????memcpy(image_out+(i*w+j)*4+1,image_in+(i*w+j)*3,3);?? ????????????}?? ????????}?? }?? ?? ?? #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;??? ???? ????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?? ???? ????pixformat=?SDL_PIXELFORMAT_ARGB8888;???? #elif?LOAD_RGB24?? ????pixformat=?SDL_PIXELFORMAT_RGB888;???? #elif?LOAD_BGR24?? ????pixformat=?SDL_PIXELFORMAT_BGR888;???? #elif?LOAD_YUV420P?? ???? ???? ????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){?? ???????? ????????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){?? ???????????????? ????????????????fseek(fp,?0,?SEEK_SET);?? ????????????????fread(buffer,?1,?pixel_w*pixel_h*bpp/8,?fp);?? ????????????}?? ?? #if?LOAD_BGRA?? ???????????? ???????????? ????????????SDL_UpdateTexture(?sdlTexture,?NULL,?buffer,?pixel_w*4);???? #elif?LOAD_RGB24|LOAD_BGR24?? ???????????? ???????????? ????????????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?? ???????????? ????????????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?);???? ???????????? ????????????SDL_Delay(40);?? ?????????????? ????????}else?if(event.type==SDL_WINDOWEVENT){?? ???????????? ????????????SDL_GetWindowSize(screen,&screen_w,&screen_h);?? ????????}else?if(event.type==SDL_QUIT){?? ????????????break;?? ????????}?? ????}?? ?? ????return?0;?? }??
運(yùn)行結(jié)果 程序的運(yùn)行結(jié)果如下圖所示。
?
下載 代碼位于“Simplest Media Play”中 ? ?
SourceForge項目地址:https://sourceforge.net/projects/simplestmediaplay/
CSDN下載地址:http://download.csdn.net/detail/leixiaohua1020/8054395
? ?
注:
該項目會不定時的更新并修復(fù)一些小問題,最新的版本請參考該系列文章的總述頁面:
?《最簡單的視音頻播放示例1:總述》
上述工程包含了使用各種API(Direct3D,OpenGL,GDI,DirectSound,SDL2)播放多媒體例子。其中音頻輸入為PCM采樣數(shù)據(jù)。輸出至系統(tǒng)的聲卡播放出來。視頻輸入為YUV/RGB像素數(shù)據(jù)。輸出至顯示器上的一個窗口播放出來。 通過本工程的代碼初學(xué)者可以快速學(xué)習(xí)使用這幾個API播放視頻和音頻的技術(shù)。 一共包括了如下幾個子工程: simplest_audio_play_directsound: ? ? ? ? 使用DirectSound播放PCM音頻采樣數(shù)據(jù)。 simplest_audio_play_sdl2: ? ? ? ? ? ? ? ? ? ? ? 使用SDL2播放PCM音頻采樣數(shù)據(jù)。 simplest_video_play_direct3d: ? ? ? ? ? ? ? ?使用Direct3D的Surface播放RGB/YUV視頻像素數(shù)據(jù)。 simplest_video_play_direct3d_texture:使用Direct3D的Texture播放RGB視頻像素數(shù)據(jù)。 simplest_video_play_gdi: ? ? ? ? ? ? ? ? ? ? ? ? ?使用GDI播放RGB/YUV視頻像素數(shù)據(jù)。 simplest_video_play_opengl: ? ? ? ? ? ? ? ? ? 使用OpenGL播放RGB/YUV視頻像素數(shù)據(jù)。 simplest_video_play_opengl_texture: ? ?使用OpenGL的Texture播放YUV視頻像素數(shù)據(jù)。simplest_video_play_sdl2: ? ? ? ? ? ? ? ? ? ? ? ?使用SDL2播放RGB/YUV視頻像素數(shù)據(jù)。
總結(jié)
以上是生活随笔 為你收集整理的最简单的视音频播放示例7:SDL2播放RGB/YUV 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。