基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结

最近因为项目接近收尾阶段,所以变的没有之前那么忙了,所以最近重新拿起了之前的一些FFMPEG和SDL的相关流媒体播放器的例子在看。

同时自己也用FFMPEG2.01,SDL2.01结合MFC以及网上罗列的一些资料,打算打造一款自己的简易播放器。

最先开始是阅读了<An ffmpeg and SDL Tutorial>以及来源与(http://blog.csdn.net/love4mario/article/details/17652355)中的中文资料,同时认真对tutorial01-08中的代码,也进行一次阅读。

然后打算修改tutorial07中的代码来做播放器的代码。

修改完了以后,编译也通过了,然后播放出来的画面却是这个样子的:

开始的时候,不理解者几个函数里面的参数,感觉是这里设置出错了。

在经过查找资料以后,得到的个人理解为:

/**
* \brief Update the given texture rectangle with new pixel data.
* \param texture The texture to update
* \param rect A pointer to the rectangle of pixels to update, or NULL to update the entire texture.
* \param pixels The raw pixel data.
* \param pitch The number of bytes between rows of pixel data.
* \return 0 on success, or -1 if the texture is not valid.
* \note This is a fairly slow function.
*/
extern DECLSPEC int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,const SDL_Rect * rect,const void *pixels, int pitch);

SDL_UpdateTexture( SDL_Texture * texture,        /*需要更新的Texture,*/
              const SDL_Rect * rect,         /*更新的区域,如果为NULL,表示更新整个区域*/
            const void *pixels,            /*the raw pixel data,元素像素数据*/
           int pitch);                      /*the number of bytes between rows of pixel data,每一行原始数据的大小*/

------------------------------------------------------------------------------------------------------------------------------------------

/**

* \brief Copy a portion of the texture to the current rendering target.
* \param renderer The renderer which should copy parts of a texture.
* \param texture The source texture.
* \param srcrect A pointer to the source rectangle, or NULL for the entire  texture.
* \param dstrect A pointer to the destination rectangle, or NULL for the entire rendering target.
* \return 0 on success, or -1 on error
*/
extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer,   /*从texture复制到rendering的目标*/
                         SDL_Texture * texture,    /*源texture*/
                         const SDL_Rect * srcrect,   /*源拷贝的范围*/
                         const SDL_Rect * dstrect);  /*目的拷贝范围*/

于是继续进行修改:

这个时候,画面已经能正常显示了,但是并没有达到我的目的,我的目的本来是想让整个绿色区域(也就算一个static控件)全部铺满视频。

所以这个时候,我去群里问了一下,有好心的朋友告诉我,你看一下是不是转化的时候设置有问题。

于是我这个时候我就拿很有代表性的例子,也比较简单的例子<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0>来做测试,查看时哪里出了问题。

这个例子虽然简单,但是很有代表性,因为代码工程不大,容易调试和找问题,同时它又把重点函数全部提了出来。

下一步,调试<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0>:

代码段1:

1     AVFrame    *pFrame,*pFrameYUV;
2     pFrame=avcodec_alloc_frame();
3     pFrameYUV=avcodec_alloc_frame();
4     uint8_t *out_buffer=(uint8_t*)av_malloc(avpicture_get_size(PIX_FMT_YUV420P,
5                                                  pCodecCtx->width, pCodecCtx->height);
6     avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P,
7                           pCodecCtx->width, pCodecCtx->height);

代码段2:

1     int screen_w=0,screen_h=0;
2     SDL_Window *screen;
3     //SDL 2.0 Support for multiple windows
4     screen_w = pCodecCtx->width;
5     screen_h = pCodecCtx->height;
6     screen = SDL_CreateWindow("Simplest ffmpeg player‘s Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
7                             screen_w, screen_h,
8                             SDL_WINDOW_OPENGL);

代码段3:

 1     //IYUV: Y + U + V  (3 planes)
 2     //YV12: Y + V + U  (3 planes)
 3     SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,     SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,
 4                                     pCodecCtx->width,pCodecCtx->height);
 5
 6     SDL_Rect sdlRect;
 7     sdlRect.x = 0;
 8     sdlRect.y = 0;
 9     sdlRect.w = screen_w;
10     sdlRect.h = screen_h;  

代码段4:

1     struct SwsContext *img_convert_ctx;
2     img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
3                        pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); 

上面这4段代码就是转换参数相关的代码,因为这里面的代码,它在设置显示的时候:

screen_w = pCodecCtx->width;

screen_h = pCodecCtx->height;

所以我们在参考上面代码时候,目的和源设置一样的,所以不知道上面这些关键函数到底是跟显示有什么关系,哪些应该需要设置为我们想要的显示效果,哪些参数必须使用源流中的参数。

所以现在我打算改变一下参数,让它最后显示出来的视频大小为宽度为800,高度为600.

所以我们再创建窗口的时候,

screen_w =800;

screen_h =600;

那么还需要哪些关键函数必须跟着做变化呢?

首先来看代码1:

AVFrame *pFrame,*pFrameYUV;这两个指针,前面一个用来指向解码以后的帧数据缓存,后面一个pFrameYUV用来指向数据转换以后的缓存,就算我们最后显示的时候取数据的缓存指针。

即:

SDL_UpdateTexture( sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0] );

这个函数在进行更新数据的时候,需要从pFrameYUV指向的内存数据区去取数据,然后更新到sdlTexture缓冲区。

{

在这个更新的过程,其实并不是仅仅的进行数据缓冲区的拷贝,因为这个函数还需要做很多的事情.()

SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING,
                        screen_w,screen_h);

这个函数指定显示的时候,数据格式:SDL_PIXELFORMAT_YV12

}

而渲染数据进行拷贝的时候:

SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, NULL);

就是把开始更新到sdlTexture数据缓冲区的数据,再进行一次拷贝到渲染缓冲区。最后就可以进行渲染显示了。

那么在数据格式进行转换之前,我们需要设置什么呢?

img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, /*源数据格式信息*/
                  screen_w,screen_h,PIX_FMT_YUV420P,            /*目的数据格式信息*/

                  SWS_BICUBIC, NULL, NULL, NULL);

转换前的获取转换上下文,这个函数将告诉我们在进行转换的时候,需要将源数据---(转换成怎么样的)--->目的数据格式信息。

注意:

也许你也跟我有一样的疑问,为什么这里设置转换参数的时候,目的数据格式为:PIX_FMT_YUV420P 而不是我们最后显示的数据格式:YV12.

确实是这样的,这里我们设置的转换目的参数为PIX_FMT_YUV420P 而不是YV12.

显示的数据格式为yv12,我们可以从

SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING,screen_w,screen_h);

这个函数指定,这里就是对显示的数据进行初始化。

那么数据从PIX_FMT_YUV420P ----------------------------->YV12又是那个函数做的呢?

这个过程就是我们上面的函数SDL_UpdateTexture中实现的,它不仅会将pFrameYUV指向的缓存区进行拷贝,而且会将PIX_FMT_YUV420P --拷贝成->YV12格式。

上面这个过程我们明白了从转换后处理的数据到显示数据的一个过程。那么如果源数据的宽度和高度并不是我们想要的,我们需要对源数据进行拉伸或者放大,那么我们转换后的数据缓冲区是不是就和源数据缓冲区的大小不一样?

这是肯定的。

所以转换前后存放数据的缓冲区大小也就不一样,所以这里我们需要为转换后的数据缓冲区申请缓冲区大小,同时需要对申请以后得到的转换后的数据缓冲区进行一定格式的划分。

这个过程我们由下面这个函数来完成:

uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P,
                      screen_w,screen_h));

申请转换以后的数据缓冲区大小。
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P,
            screen_w,screen_h);

对转换后存放数据的数据缓冲区,进行按格式存放划分。

---------------------------------------------------------------------------------------------

个人的理解,如果有误,请指正。望努力拍砖。

时间: 2024-10-05 02:48:21

基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结的相关文章

最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)

===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x) 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0) 最简单的基于FFmpeg的解码器-纯净版(不包括libavformat) 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器 最简单的基于FFMPEG的Hellowor

最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)

简介 之前做过一个FFMPEG+SDL的简单播放器:<100行代码实现最简单的基于FFMPEG+SDL的视频播放器>.该播放器采用SDL1.2显示视频.最近有不少人反映SDL已经升级到2.0版本了,甚至官网的Wiki上都只有SDL2.0的文档了,因此下载了SDL 2.0 并且进行了简单的研究.随后对此前的播放器进行了修改,将SDL1.2换成了SDL2.0. 注:<100行代码实现最简单的基于FFMPEG+SDL的视频播放器>文章中提到的很多知识这里不再重复.本文重点记录SDL1.2

100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】

转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 简介 流程图 simplest_ffmpeg_player标准版代码 simplest_ffmpeg_player_suSU版代码 结果 FFMPEG相关学习资料 补充问题 ===================================================== 最简单的基于FFmp

最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器

本文补充记录<最简单的基于FFMPEG+SDL的视频播放器>中的两个例子:FFmpeg视频解码器和SDL像素数据播放器.这两个部分是从视频播放器中拆分出来的两个例子.FFmpeg视频解码器实现了视频数据到YUV数据的解码,而SDL像素数据播放器实现了YUV数据的显示.简而言之,原先的FFmpeg+SDL视频播放器实现了: 视频数据->YUV->显示器 FFmpeg视频解码器实现了: 视频数据->YUV SDL像素数据播放器实现了: YUV->显示器 FFmpeg视频解码

用JavaCV改写“100行代码实现最简单的基于FFMPEG+SDL的视频播放器 ”

FFMPEG的文档少,JavaCV的文档就更少了.从网上找到这篇100行代码实现最简单的基于FFMPEG+SDL的视频播放器.地址是http://blog.csdn.net/leixiaohua1020/article/details/8652605. 用JavaCV重新实现并使用opencv_highgui进行显示. 1 import com.googlecode.javacpp.IntPointer; 2 import com.googlecode.javacpp.Pointer; 3 im

FFMPEG+SDL实现视频播放器

一. 前言 基于学习ffmpeg和sdl,写一个视频播放器是个不错的练手项目. 视频播放器的原理很多人的博客都有讲过,这里出于自己总结的目的,还是会做一些概况. 二. 视频播放器基本原理 2.1 解封装 视频文件基本上都是将编码好的音频和视频数据封装在一起形成的,因此拿到视频文件的第一步就是先将它解封装,分为视频流和音频流压缩编码数据.常见的封装格式有MP4.MKV.FLV.AVI.RMVB.TS等.例如,FLV格式的文件经过解封装后,可能得到H.264编码的视频码流和AAC编码的音频码流. 在

最简单的基于FFMPEG+SDL的视频播放器附件:Helloworld

本文记录一个基于FFmpeg的HelloWorld程序.该程序可以打印出FFmpeg类库的基本信息.使用该程序通常可以验证FFmpeg是否正确的安装配置. 源代码 /** * 最简单的FFmpeg Helloworld程序 * Simplest FFmpeg HelloWorld * * 雷霄骅 Lei Xiaohua * [email protected] * 中国传媒大学/数字电视技术 * Communication University of China / Digital TV Tech

最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)

简介 之前做过一个简单的音频播放器:<最简单的基于FFMPEG+SDL的音频播放器>,采用的是SDL1.2.前两天刚把原先做的<最简单的基于FFMPEG+SDL的视频播放器>更新采用了SDL2.0,于是顺手也把音频播放器更新成为SDL2.0. SourceForge项目主页:https://sourceforge.net/projects/simplestffmpegaudioplayer/ 完整工程下载地址:http://download.csdn.net/detail/leix

[原]零基础学习SDL开发之在Android使用SDL2.0显示BMP图

关于如何移植SDL2.0到安卓上面来参考我的上一篇文章:[原]零基础学习SDL开发之移植SDL2.0到Android 在一篇文章我们主要使用SDL2.0来加载一张BMP图来渲染显示. 博主的开发环境:Ubuntu 14.04 64位,Eclipse + CDT + ADT+NDK 博主曾经自己使用NDK编译出了libSDL2.so,然后使用共享库的方式来调用libSDL2中的函数,结果发现SDL\src\core\android\SDL_android.c 这个jni函数写的实在是不够自己另外做