【笔记】An ffmpeg and SDL Tutorial 02《视频播放》

来源:互联网 发布:淘粉吧和淘宝的关系 编辑:程序博客网 时间:2024/06/05 03:12


文章《An ffmpeg and SDL Tutorial 02》将的实在是太简略了,我们可以参考雷霄骅的文章《最简单的视音频播放示例7:SDL2播放RGB/YUV》。


概述

  

在这里使用的版本是SDL2。实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API。在Windows平台下,SDL封装了Direct3D这类的API用于播放视频;封装了DirectSound这类的API用于播放音频。因为SDL的编写目的就是简化视音频播放的开发难度,所以使用SDL播放视频(YUV/RGB)和音频(PCM)数据非常的容易。



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流程图及主要数据结构

就像FFmpeg一样,SDL2也有固定的执行逻辑,其流程图如下所示:



从上面可以看出,SDL2涉及的数据结构主要有SDL_Window、SDL_Renderer和SDL_Texture。几个关键的结构体之间的关系可以用下图所示:

C++代码及解释

class CMySDL2{public:CMySDL2();~CMySDL2();intInit(int width, int height);intUnInit();voidTick_Render(AVFrame *pFrame);// 消息处理voidTick_Event();private:intm_nW;intm_nH;SDL_Window*m_pWindow;SDL_Renderer*m_pRenderer;SDL_Texture*m_pTexture;SDL_Rectm_sdlRect;};int CMySDL2::Init(int width, int height){if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)){printf("Could not initialize SDL - %s\n", SDL_GetError());return -1;}//SDL 2.0 Support for multiple windowsm_nW = width;m_nH = height;m_pWindow = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,m_nW, m_nH, SDL_WINDOW_OPENGL);if (!m_pWindow){printf("SDL: could not create window - exiting:%s\n", SDL_GetError());return -1;}m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);m_pTexture = SDL_CreateTexture(m_pRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, m_nW, m_nH);m_sdlRect.x = 0;m_sdlRect.y = 0;m_sdlRect.w = m_nW;m_sdlRect.h = m_nH;return 0;}int CMySDL2::UnInit(){SDL_Quit();return 0;}void CMySDL2::Tick_Render(AVFrame *pFrame){SDL_UpdateTexture(m_pTexture, NULL, pFrame->data[0], m_nW);m_sdlRect.x = 0;m_sdlRect.y = 0;m_sdlRect.w = m_nW;m_sdlRect.h = m_nH;SDL_RenderClear(m_pRenderer);//SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect );  SDL_RenderCopy(m_pRenderer, m_pTexture, NULL, &m_sdlRect);SDL_RenderPresent(m_pRenderer);}void CMySDL2::Tick_Event(){static SDL_Event event;SDL_PollEvent(&event);switch (event.type) {case SDL_QUIT:SDL_Quit();exit(0);break;default:break;}}//  函数 函数调用int main(int argc, char **argv){my::InitFFmpegLibrary();CMyFFmpeg my;my.Init("video\\yu_15s.mp4");my.Log_StructInfo();CMyDecoder dec;dec.Init(&my, AV_PIX_FMT_YUV420P);AVFrame*pFrame;CMySDL2 mySDL;mySDL.Init(my.GetWidth(), my.GetHeight());std::ofstream ofile;ofile.open("my.yuv", std::ios::binary);while (true){pFrame = dec.GetFrame();if (pFrame){mySDL.Tick_Render(pFrame);}mySDL.Tick_Event();Sleep(10);}mySDL.UnInit();    return 0;}


总结

最后总结下编写代码中遇到的两个问题:SDL绘图崩溃、视频花屏。相关代码可以查看GIT的历史记录。

SDL绘图崩溃:avcodec_decode_video2解码出来的数据必须sws_scale后才能使用:因为解出来的可能有黑边,长宽不一定就是视频的长宽。

视频花屏:av_frame_unref(pFrame);只能在程序运行结束后调用。可以查看CMyDecoder的Init和Uninit相关代码。


0 0
原创粉丝点击