本篇实现基于ffmpeg动态库用测试程序播放本地文件和RTSP视频流。

参考文章:http://blog.csdn.net/leixiaohua1020/article/details/8652605

http://blog.csdn.net/guanghua2_0beta/article/details/37578299

创建工程,参考上一篇文章:http://www.cnblogs.com/wenjingu/p/3990071.html,注意:下载SDL2库的开发版,lib文件放到lib文件夹下,dll放到debug文件夹下。

代码如下,在参考文章的基础上做了少量改动,主要是将ffmpeg老版本的部分函数在替换为2.4版本中的新函数。

#include "stdafx.h"

#ifdef __cplusplus
extern "C" {
#endif #include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h> #ifdef __cplusplus
}
#endif int ffplayer()
{
AVFormatContext *pFormatCtx;
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
//char filepath[]="F:\\Work\\ffmpegdemo\\Debug\\Wildlife.wmv";
char rtspUrl[] = "rtsp://admin:12345@192.168.10.76:554";
av_register_all();//注册组件
avformat_network_init();//支持网络流
pFormatCtx = avformat_alloc_context();//初始化AVFormatContext
if(avformat_open_input(&pFormatCtx,/*filepath*/rtspUrl,NULL,NULL)!=){//打开文件或网络流
printf("无法打开文件\n");
return -;
}
if(avformat_find_stream_info(pFormatCtx, NULL)<)//查找流信息
{
printf("Couldn't find stream information.\n");
return -;
}
videoindex=-;
for(i=; i<pFormatCtx->nb_streams; i++) //获取视频流ID
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoindex=i;
break;
}
if(videoindex==-)
{
printf("Didn't find a video stream.\n");
return -;
}
pCodecCtx=pFormatCtx->streams[videoindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);//查找解码器
if(pCodec==NULL)
{
printf("Codec not found.\n");
return -;
}
if(avcodec_open2(pCodecCtx, pCodec, NULL)<)//打开解码器
{
printf("Could not open codec.\n");
return -;
}
AVFrame *pFrame,*pFrameYUV;
pFrame=avcodec_alloc_frame();//存储解码后AVFrame
pFrameYUV=avcodec_alloc_frame();//存储转换后AVFrame
uint8_t *out_buffer;
out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];//分配AVFrame所需内存
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//填充AVFrame //------------SDL初始化--------
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf( "Could not initialize SDL - %s\n", SDL_GetError());
return -;
}
SDL_Window *screen = SDL_CreateWindow("RTSP Client Demo",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
pCodecCtx->width, pCodecCtx->height,
SDL_WINDOW_RESIZABLE/* SDL_WINDOW_HIDDEN*/| SDL_WINDOW_OPENGL);
if(!screen) {
printf("SDL: could not set video mode - exiting\n");
return -;
}
SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -, );
SDL_Texture* sdlTexture = SDL_CreateTexture(
sdlRenderer,
SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,
pCodecCtx->height); SDL_Rect rect;
//-----------------------------
int ret, got_picture;
static struct SwsContext *img_convert_ctx;
int y_size = pCodecCtx->width * pCodecCtx->height; SDL_Event event;
AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));//存储解码前数据包AVPacket
av_new_packet(packet, y_size);
//输出一下信息-----------------------------
printf("文件信息-----------------------------------------\n");
//av_dump_format(pFormatCtx,0,filepath,0);
printf("-------------------------------------------------\n");
//------------------------------
while(av_read_frame(pFormatCtx, packet)>=)//循环获取压缩数据包AVPacket
{
if(packet->stream_index==videoindex)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);//解码。输入为AVPacket,输出为AVFrame
if(ret < )
{
printf("解码错误\n");
return -;
}
if(got_picture)
{
//像素格式转换。pFrame转换为pFrameYUV。
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, , pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
sws_freeContext(img_convert_ctx);
//------------SDL显示--------
rect.x = ;
rect.y = ;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height; SDL_UpdateTexture( sdlTexture, &rect, pFrameYUV->data[], pFrameYUV->linesize[] );
SDL_RenderClear( sdlRenderer );
SDL_RenderCopy( sdlRenderer, sdlTexture, &rect, &rect );
SDL_RenderPresent( sdlRenderer );
//延时20ms
SDL_Delay();
//------------SDL-----------
}
}
av_free_packet(packet);
SDL_PollEvent(&event);
switch( event.type ) {
case SDL_QUIT:
SDL_Quit();
exit();
break;
default:
break;
}
} SDL_DestroyTexture(sdlTexture);
delete[] out_buffer;
av_free(pFrameYUV);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx); return ;
} int _tmain(int argc, _TCHAR* argv[])
{
ffplayer(); return ;
}

测试效果:

播放rtsp网络流

也可以播放本地文件,将rtspUrl替换为filepath即可。

ffmpeg学习(三)——ffmpeg+SDL2 实现简单播放器的更多相关文章

  1. [开源]基于ffmpeg和libvlc的视频剪辑、播放器

    [开源]基于ffmpeg和libvlc的视频剪辑.播放器 以前研究的时候,写过一个简单的基于VLC的视频播放器.后来因为各种项目,有时为了方便测试,等各种原因,陆续加了一些功能,现在集成了视频播放.视 ...

  2. FFmpeg入门,简单播放器

    一个偶然的机缘,好像要做直播相关的项目 为了筹备,前期做一些只是储备,于是开始学习ffmpeg 这是学习的第一课 做一个简单的播放器,播放视频画面帧 思路是,将视频文件解码,得到帧,然后使用定时器,1 ...

  3. 【C++】从零开始,只使用FFmpeg,Win32 API,实现一个播放器(一)

    前言 起初只是想做一个直接读取视频文件然后播放字符动画的程序.我的设想很简单,只要有现成的库,帮我把视频文件解析成一帧一帧的原始画面信息,那么我只需要读取里面的每一个像素的RGB数值,计算出亮度,然后 ...

  4. 基于ffmpeg和libvlc的视频剪辑、播放器

    以前研究的时候,写过一个简单的基于VLC的视频播放器.后来因为各种项目,有时为了方便测试,等各种原因,陆续加了一些功能,现在集成了视频播放.视频加减速.视频剪切,视频合并(增加中)等功能在一起.有时候 ...

  5. 利用Docker挂载Nginx-rtmp(服务器直播流分发)+FFmpeg(推流)+Vue.js结合Video.js(播放器流播放)来实现实时网络直播

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_75 众所周知,在视频直播领域,有不同的商家提供各种的商业解决方案,其中比较靠谱的服务商有阿里云直播,腾讯云直播,以及又拍云和网易云 ...

  6. [ 原创 ]学习笔记-做一个Android音乐播放器是遇到的一些困难

    最近再做一个安卓的音乐播放器,是实验室里学长派的任务,我是在eclipse上进行开发的,由于没有android的基础,所以做起来困难重重. 首先是布局上的困难 1.layout里的控件属性不熟悉 2. ...

  7. FFmpeg 学习(三):将 FFmpeg 移植到 Android平台

    首先需要去FFmpeg的官网http://www.ffmpeg.org/去下载FFmpeg的源码,目前的版本号为FFmpeg3.3(Hilbert). 下载的文件为压缩包,解压后得到ffmpeg-3. ...

  8. ffmpeg学习笔记-ffmpeg在VS下的运用

    ffmpeg官网提供了window平台下额开发工具供开发者使用,这篇文章主要以3.2版本的ffmpeg作为演示,记录在VS2013下,怎么去编译ffmpeg 下载 在官网中,按照以下步骤下载 下载Wi ...

  9. Vue学习(三)-Vue-router路由的简单使用

    一.Vue-Router环境的安装: 如果使用vue-cli脚手架搭建,项目创建过程中会提示你自否选择使用vue-router,选择使用即可, 二.路由学习 1.路由的配置    vue-cli项目自 ...

随机推荐

  1. json中key大小写转换

    最近工作中遇到json格式的字符串中的key为大写的,需要转换成小写的来解析,开始想使用正则来替换,结果不是很方便,后来考虑把JSONObject重新来封装. 如下json格式:{PWACHECKIN ...

  2. MySQL单机单实例安装脚本

    说明:使用mysql generic tar.gz包快速安装mysql 三个文件installation_of_single_mysql.sh.template_install-my.cnf.mysq ...

  3. Hive常见问题汇总

    参考资料: Hive常见问题汇总 啟動hive出錯,提示沒有權限 2015年04月02日 09:58:49 阅读数:31769 这里小编汇集,使用Hive时遇到的常见问题. 1,执行#hive命令进入 ...

  4. Selenium2+python自动化63-简易项目搭建

    前言 到unittest这里基本上可以搭建一个简易的项目框架了,我们可以用一条run_main.py脚本去控制执行所有的用例,并生成报告,发送邮件一系列的动作 一.新建工程 1.打开pycharm左上 ...

  5. 20165233 Java第五、六章学习总结

    20165233 2017-2018-2 <Java程序设计>第四周学习总结 教材学习内容总结 ch05 子类与父类以及子类的继承性 一个子类只能有一个父类 使用extends关键字定义子 ...

  6. django-DIL模板自定义过滤器,自定义标签,自定义包含标签

    自定义过滤器 DTL模板语言生来只是为了方便的展示信息,所以与编程语言相比显得有点薄弱,有时候不能满足我们的需求.因此django提供了一个接口,让开发者能自定义标签和过滤器. 首先,你需要添加一个t ...

  7. django2.0模板相关设置

    看到了django的模板有include标签 include 标签 {% include %} 标签允许在模板中包含其它的模板的内容. 下面这个例子都包含了 nav.html 模板: {% inclu ...

  8. Node.js 项目打包

    Node项目基于Electron打包 Electron打包打包后项目.exe程序包含在文件夹中,基于Electron打包的基础上直接打包成exe程序 参考一 参考二 需求的软件环境: NSIS 2.4 ...

  9. javascript中defer的作用

    javascript中defer的作用 <script src="../CGI-bin/delscript.js" defer></script>中的def ...

  10. 多产生半成品工单的问题 修改带SO的半成品工单无法分配给SO的问题的

    原因:验货及VIP带SO的半成品MO无法分配给对应的SO问题, 解决: SELECT SL.ENTERPRISE , SL.ENGINE_ID , SL.SITEID , ML.MO_ID || '_ ...