基于<最简单的基于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:
AVFrame *pFrame,*pFrameYUV;
pFrame=avcodec_alloc_frame();
pFrameYUV=avcodec_alloc_frame();
uint8_t *out_buffer=(uint8_t*)av_malloc(avpicture_get_size(PIX_FMT_YUV420P,
pCodecCtx->width, pCodecCtx->height);
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P,
pCodecCtx->width, pCodecCtx->height);
代码段2:
int screen_w=,screen_h=;
SDL_Window *screen;
//SDL 2.0 Support for multiple windows
screen_w = pCodecCtx->width;
screen_h = pCodecCtx->height;
screen = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
screen_w, screen_h,
SDL_WINDOW_OPENGL);
代码段3:
//IYUV: Y + U + V (3 planes)
//YV12: Y + V + U (3 planes)
SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,pCodecCtx->height); SDL_Rect sdlRect;
sdlRect.x = ;
sdlRect.y = ;
sdlRect.w = screen_w;
sdlRect.h = screen_h;
代码段4:
struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
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);
对转换后存放数据的数据缓冲区,进行按格式存放划分。
---------------------------------------------------------------------------------------------
其中查找资料的过程中,记录下资料的出处:
1)SDL实现overlay方式双屏显示的应用流程分析(thinkvd开发日志)
http://blog.163.com/tfn2008@yeah/blog/static/110321319201275111614200/
http://blog.csdn.net/zhuweigangzwg/article/details/17223841
3)SDL2.0在mfc窗口中显示yuv的一种方法
http://airmanisvip.blog.163.com/blog/static/18058158201261015741216/
4)如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器
http://blog.csdn.net/love4mario/article/details/17652355
5)最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
http://blog.csdn.net/leixiaohua1020/article/details/38868499
6)SDL 2.0 API by Name
https://wiki.libsdl.org/CategoryAPI
-----------------------------------------------------------------------------------------------
本文出自:http://www.cnblogs.com/lihaiping/p/4025138.html
个人的理解,如果有误,请指正。望努力拍砖。
%8O0]$KP6.jpg)
%8O0]$KP6.jpg)
基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结的更多相关文章
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] ...
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 用JavaCV改写“100行代码实现最简单的基于FFMPEG+SDL的视频播放器 ”
FFMPEG的文档少,JavaCV的文档就更少了.从网上找到这篇100行代码实现最简单的基于FFMPEG+SDL的视频播放器.地址是http://blog.csdn.net/leixiaohua102 ...
- 音视频处理之FFmpeg+SDL+MFC视频播放器20180411
一.FFmpeg+SDL+MFC视频播放器 1.MFC知识 1).创建MFC工程的方法 打开VC++ 文件->新建->项目->MFC应用程序 应用程序类型->基于对话框 取消勾 ...
- 【转】100行代码实现最简单的基于FFMPEG+SDL的视频播放器
FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手.我刚接触FFMPEG的时候也感觉不知从何学起. 因此我把自己做项目过程中实现的一个非常简单的视频播放器 ...
- FFMPEG+SDL实现视频播放器
一. 前言 基于学习ffmpeg和sdl,写一个视频播放器是个不错的练手项目. 视频播放器的原理很多人的博客都有讲过,这里出于自己总结的目的,还是会做一些概况. 二. 视频播放器基本原理 2.1 解封 ...
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...
随机推荐
- 免费申请 Github 私有仓库--学生和教育人士的福利
免费申请 Github 私有仓库 -学生和教育人士的福利 Github 是全球知名的软件项目托管网站.在 Github 创建私有仓库是需要收费的,收费方案有多种,费用最小的方案是每月 7 美元的“微型 ...
- Git教程Git多人协作开发
Git可以完成两件事情: 1. 版本控制 2.多人协作开发 如今的项目,规模越来越大,功能越来越多,需要有一个团队进行开发. 如果有多个开发人员共同开发一个项目,如何进行协作的呢. Git提供了一个非 ...
- composer安装第三方的库packagist.org(laravel框架引入第三方库)
建立composer.json composer require phpoffice/phpexcel //安装一个excel扩展库 composer require gregwar/captcha ...
- JAVA class 编译jar。 控制台使用jar
//编译jar jar -cvf -mgtvEncode.jar -mgtvEncode.class //使用jar java -cp mgtvEncode.jar mgtvEncode
- 批处理学习笔记9 - 深入学习For命令2
这一篇是对于for /f的扩展,上一篇说道/f可以读txt文件里的数据.这里了解下tokens和delims功能 平常文本文件保存数据经常用这样的格式 avi|wmv|rm|mkv|mp4 以读取这个 ...
- [svc]kill pkill killall管理进程
进程讲解 操作配置 http://www.centoscn.com/CentOS/help/2013/0809/1218.html 终止一个进程或终止一个正在运行的程序,一般是通过 kill .kil ...
- copy 的实现原理与深浅拷贝
转自:http://bbs.9ria.com/thread-210322-1-1.html 首先,从copy开始说,简而言之,copy的目的就是生成一个新的实例,然后把其成员都按原实例赋值.对于非指针 ...
- Mysql 中创建索引和索引的使用问题
在数据库中合理的使用索引是提升mysql数据库的一种高效和快捷的方式,但是在索引的使用上在我的使用中发现有很多坑,因为自己之前没有认识到,所以来总结一下 索引的介绍 索引是一种特殊的文件,其中包含着对 ...
- python地址解析经纬度,城市
1.地址列表 1.txt 上海市普陀区梅川路299-301号 浙江省杭州市拱墅区丰登路305-311号1层 江苏省南京市鼓楼区碧树园86号101室 浙江省宁波市江北区范江岸路38弄6号-10号1层商铺 ...
- nrm 的使用
我们介绍过cnpmjs.org和淘宝 npm 两个 NPM 镜像.除此之外,还有一些国外的 NPM 镜像.不同地区访问不同的镜像速度可能有差异,因此有时候需要切换 NPM 镜像.相比每次切换时都手动指 ...