SDL2播放FFmpeg解压的视频

SDL2简化了播放过程,这里引入播放视频。

1. 以我的《FFmpeg入门测试》为工程。

2. 到http://www.libsdl.org/index.php下载SDL2-devel-2.0.9-VC.zip (Visual C++ 32/64-bit)最新版。解压将SDL2-2.0.9\lib\x86目录内的SDL2.dll考入解决方案的Debug目录中。在解决方案目录中新建SDL目录,拷入SDL2-2.0.9内的include和lib两个目录。

3. 创建开发环境:

3.1 包含编译文件

3.1.1 包含头目录:项目->属性->VC++目录->包含目录:F:\FFmpegTest\SDL\include。

3.1.2 包含库目录:项目->属性->VC++目录->库目录:F:\FFmpegTest\SDL\lib\x86。

3.1.3 包含链接库文件:项目->属性->链接器->输入->附加依赖项:SDL2.lib;SDL2main.lib。

4. 输入源代码:

#include <iostream>

#define __STDC_CONSTANT_MACROS //使用FFmpeg定义宏

extern "C"
{
    #include "libavutil/imgutils.h"   //av_image使用
    #include "libavcodec/avcodec.h"   //编解码处理
    #include "libavformat/avformat.h" //文件封装处理
    #include "libswscale/swscale.h"//图像变换
    #include "libavdevice/avdevice.h"
    #include "SDL.h"
};

void PrintErrStr(const char *str)
{
	printf(str);
	printf("\n\n");
	system("pause");
}

int Decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt)//解码
{
	 int ret = avcodec_send_packet(dec_ctx, pkt);// 先发送包数据到解码上下文中
	 if (ret < 0)
	 {
		 PrintErrStr("发送数据包进行解码时出错.");
		 return ret;
	 }
	 return avcodec_receive_frame(dec_ctx, frame);// 然后从解码上下文中读取帧数据到frame对象中
}

#undef main
int main()
{
	AVFormatContext *pFormatCtx = NULL;//主要用于处理封装格式(FLV/MKV/RMVB等)
	AVCodecContext *pVideoCodecCtx = NULL;
	AVCodecContext *pAudioCodecCtx = NULL;
	AVCodec *pVideoCodec = NULL;
	AVCodec *pAudioCodec = NULL;
	AVFrame *pFrame;   //存储非压缩的数据(视频对应RGB/YUV像素数据,音频对应PCM采样数据)
	AVPacket packet;   //存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据)

	//SDL变量
	SDL_Window *screen;
	SDL_Renderer* sdlRenderer;
	SDL_Texture* sdlTexture;
	SDL_Rect sdlRect;

	int iHour, iMinute, iSecond, iTotalSeconds;//HH:MM:SS
	int videoStreamIndex, audioStreamIndex; //音视频流索引
	int ret, FrameBytes;
	const char In_FileName[] = "F:\\TestMov\\Titanic.ts";//输入文件
	const char Out_h264_FileName[] = "F:\\TestMov\\output.h264";//输出h264文件
	const char Out_rgb24_FileName[] = "F:\\TestMov\\output.rgb24";//输出h264文件

	FILE *fp_Out_h264_File = fopen(Out_h264_FileName, "wb+");
	FILE *fp_Out_rgb24_File = fopen(Out_rgb24_FileName, "wb+");

	int OutImgW = 640;
	int OutImgH = 272;
	int Img_linesize = OutImgW * 3;
	int OutImg_linesize[3] = {Img_linesize, 0, 0};

	sdlRect.x = 0;
	sdlRect.y = 0;
	sdlRect.w = OutImgW;
	sdlRect.h = OutImgH;

	avdevice_register_all();//注册所有组件
	if (avformat_open_input(&pFormatCtx, In_FileName, NULL, NULL) != 0)//打开输入视频文件
	{
		PrintErrStr("打开输入文件失败。");
		return -1;
	}

	if (avformat_find_stream_info(pFormatCtx, NULL) < 0)//获取文件信息
	{
		PrintErrStr("没有发现流信息。");
		return -1;
	}

	videoStreamIndex = -1;
	audioStreamIndex = -1;
	for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)//寻找流索引
	{
		if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)//查找视频流索引
		{
			videoStreamIndex = i;
		}
		else
		if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)//查找音频流索引
		{
			audioStreamIndex = i;
		}
	}
	if ((videoStreamIndex == -1)||(audioStreamIndex == -1))
	{
		PrintErrStr("没有发现视频或音频流。");
		return -1;
	}

	pVideoCodec = avcodec_find_decoder(pFormatCtx->streams[videoStreamIndex]->codecpar->codec_id);//查找视频解码器
	if (pVideoCodec == NULL)
	{
		PrintErrStr("没有找到视频解码器。");
		return -1;
	}
	pAudioCodec = avcodec_find_decoder(pFormatCtx->streams[audioStreamIndex]->codecpar->codec_id);//查找音频解码器
	if (pVideoCodec == NULL)
	{
		PrintErrStr("没有找到音频解码器。");
		return -1;
	}

	pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec);//申请视频解码空间
	if (pVideoCodecCtx == NULL)
	{
		PrintErrStr("无法分配视频解码器。");
		return -1;
	}
	pAudioCodecCtx = avcodec_alloc_context3(pAudioCodec);//申请音频解码空间
	if (pAudioCodecCtx == NULL)
	{
		PrintErrStr("无法分配音频解码器。");
		return -1;
	}
	avcodec_parameters_to_context(pVideoCodecCtx, pFormatCtx->streams[videoStreamIndex]->codecpar);
	avcodec_parameters_to_context(pAudioCodecCtx, pFormatCtx->streams[audioStreamIndex]->codecpar);

	if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) //打开视频解码器
	{
		PrintErrStr("没有打开视频解码器。");
		return -1;
	}
	if (avcodec_open2(pAudioCodecCtx, pAudioCodec, NULL) < 0) //打开音频解码器
	{
		PrintErrStr("没有打开音频解码器。");
		return -1;
	}

	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))//SDL2初始化视频
	{
		printf("无法初始化SDL2:%s\n", SDL_GetError());
		printf("\n\n");
		system("pause");
		return -1;
	}
	screen = SDL_CreateWindow("SDL2 + ffmpeg player‘s Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, OutImgW, OutImgH, SDL_WINDOW_SHOWN);
	if (!screen)
	{
		printf("创建SDL2窗口失败:%s\n", SDL_GetError());
		printf("\n\n");
		system("pause");
		return -1;
	}
	sdlRenderer = SDL_CreateRenderer(screen, -1, 0);//SDL2创建渲染
	sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, OutImgW, OutImgH);//SDL2创建纹理

	pFrame = av_frame_alloc();//申请解压帧缓存
	if (pFrame == NULL)
	{
		PrintErrStr("申请解压帧缓存失败。");
		return -1;
	}

	FrameBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, pVideoCodecCtx->width, pVideoCodecCtx->height, 1);//获取视频帧字节数
	uint8_t *pFrameBuffer = (uint8_t *)av_malloc(FrameBytes);//创建动态视频帧数组

	while (av_read_frame(pFormatCtx, &packet) >= 0)//从文件中读取一个packet
	{
		if (packet.stream_index == videoStreamIndex)//如果是视频帧
		{
			//fwrite(packet.data, packet.size, 1, fp_Out_h264_File);//写视频包文件
			ret = Decode(pVideoCodecCtx, pFrame, &packet);//解码 packet->pFrame
			if (ret == 0) //已得到解码的图像在pFrame里
			{
				struct SwsContext *pSwsCtx = NULL;
				pSwsCtx = sws_getContext( pVideoCodecCtx->width, pVideoCodecCtx->height, pVideoCodecCtx->pix_fmt,//源宽度高度和格式YUV420
					                      OutImgW, OutImgH, AV_PIX_FMT_RGB24,//转换到目标的宽度高度和格式
					                      SWS_FAST_BILINEAR,//缩放算法
					                      NULL, NULL, NULL);//初始化转换
				if (!pSwsCtx)
				{
					PrintErrStr("无法初始化转换Frame帧。");
					return -1;
				}
				sws_scale(pSwsCtx, pFrame->data, pFrame->linesize, 0, pVideoCodecCtx->height, &pFrameBuffer, OutImg_linesize);

				//SDL_Update
				SDL_UpdateTexture(sdlTexture, NULL, pFrameBuffer, Img_linesize);//刷新显示
				SDL_RenderClear(sdlRenderer);//清除上次渲染
				SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);//拷贝纹理
				SDL_RenderPresent(sdlRenderer);//渲染
				SDL_Delay(40);//延时

				//fwrite(pFrameBuffer, FrameBytes, 1, fp_Out_rgb24_File);//写RGB视频文件
				sws_freeContext(pSwsCtx);//释放转换
			}
		}
		av_packet_unref(&packet);
	}

	//输出信息
	puts("[文件信息]");
	iTotalSeconds = (int)pFormatCtx->duration / 1000000; //S
	iHour = iTotalSeconds / 3600;//小时
	iMinute = iTotalSeconds % 3600 / 60;//分钟
	iSecond = iTotalSeconds % 60;//秒
	printf("播放时间:%02d:%02d:%02d\n", iHour, iMinute, iSecond);
	printf("流 个 数:%d\n", pFormatCtx->nb_streams);
	printf("封装格式:%s\n", pFormatCtx->iformat->long_name);
	printf("\n");

	puts("[视频信息]");
	printf("编码格式:%s\n", pVideoCodec->long_name);
	printf("视频码率:%I64d kb/s\n", pVideoCodecCtx->bit_rate / 1000);
	printf("分 辨 率:%d * %d\n", pVideoCodecCtx->width, pVideoCodecCtx->height);
	printf("\n");

	puts("[音频信息]");
	printf("编码格式:%s\n", pAudioCodec->long_name);
	printf("音频码率:%I64d kb/s\n", pAudioCodecCtx->bit_rate / 1000);
	printf("通 道 数:%d\n", pAudioCodecCtx->channels);
	printf("采 样 率:%d\n", pAudioCodecCtx->sample_rate);
	printf("\n");

	SDL_Quit();
	fclose(fp_Out_h264_File);
	fclose(fp_Out_rgb24_File);
	av_free(pFrameBuffer);
	av_frame_free(&pFrame);
	avcodec_close(pVideoCodecCtx);
	avcodec_close(pAudioCodecCtx);
	avformat_close_input(&pFormatCtx);

	printf("\n\n");
	system("pause");
}

5. 编译运行:输出一个窗口播放视频,输出文件已无意义,被注释掉。

因SDL内也有一个main,所以在主程序main前输入#undef main,避免错误。

原文地址:https://www.cnblogs.com/hbg200/p/10353780.html

时间: 2024-10-12 19:19:57

SDL2播放FFmpeg解压的视频的相关文章

演示基于SDL2.0+FFmpeg的播放器

SDL是一个跨平台的渲染组件,目前已经推出到2.0.3版本,支持Win/Linux/OSX/Android.网上很多介绍大多是基于SDL1.2版本的,与2.0版本有一定的差别,本文演示如何用SDL2.0版本播放视频(仅视频). SDL下载网站:http://libsdl.org 参考网址:http://blog.csdn.net/dawdo222/article/details/8692834 上代码: // 演示如何用SDL2进行播放 //可参考http://blog.csdn.net/daw

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

以前研究的时候,写过一个简单的基于VLC的视频播放器.后来因为各种项目,有时为了方便测试,等各种原因,陆续加了一些功能,现在集成了视频播放.视频加减速.视频剪切,视频合并(增加中)等功能在一起.有时候看点网上下载的视频,可以一边看,一边能处理视频前后的广告,感觉也还可以用,就想把它开源出去,一方面希望有需要的朋友可以参考.借鉴,另一方面也希望可以促进它进一步的丰富功能,最终能实现一款简单又够用的视频剪辑软件. 程序框架 先上一张程序截图 基本上讲,它的播放功能是基于VLC,剪辑功能是基于FFmp

day03 hadoop的解压与配置文件的配置,还需要看视频

拷贝hadoop1.2.1.tar.gz安装包到其他的节点上 scp -r ~/hadoop-1.2.1.tar.gz  [email protected]:~/ tar -zxvf hadoop-1.2.1.tar.gz  解压tar包 ln -sf /root/hadoop-1.2.1 /home/hadoop-1.2  创建快捷方式 scp ./* [email protected]:/home/hadoop-1.2/conf/   拷贝当前目录下的所有文件到指定的主机的指定目录下 [[e

让Fedora25播放大多数多媒体——音频和视频

Fedora25在默认情况下播放多媒体不太乐观,只要按下列方法的做,基本上就可以播放所有的多媒体格式,包括对rm等格式的支持和Apple公司的和Microsoft公司的都能很好的支持. 在安装前请先安装RPM Fusion源(前面博客有提到http://wzbao.blog.51cto.com/11237209/1917345) 1.音频播放:        安装audacious dnf install audacious audacious-plugins audacious-plugins

Youtube-dl 配置 使用方法 + 配合aria2 多线程 下载 + 配合 ffmpeg 自动合并分段视频

首先介绍软件,Youtube-dl可以下载网页的视频,功能很强大. 但遇到分段视频不能合并,遇到视频音频分开播放的网站也没办法合并视频音频,所以 需要用ffmpeg来配合的合并视频.合并过程是无损的,不用担心.自动操作,不用自己动手. 但Youtube-dl还有个缺点,就是下载时单线程.简直就是龟速,下载视频往往还比较大,单线程是不可能使用的. 所以需要aria2来使用多线程. 一.安装python环境,官网 https://www.python.org/,下载最新版本. 安装时记得添加环境.

利用FFMPEG简单分离音视频数据流

上一篇文章我们搭好了环境并编译出所需的ffmpeg库,本篇我们讨论如何利用ffmpeg提供的API函数进行多媒体文件的解封装(demux)过程.在讲解之前,我们需要了解一些基本的多媒体文件知识,大虾请飘过. 容器格式:不管是音频文件还是视频格式的文件,都是一个多媒体的容器,即container,比如常见的视频容器格式有avi.mp4.mkv.flv.rm/rmvb.mov.ts.vob.dat,音频容器格式有MP3.WAV.AAC.APE,FLAC等等,它容纳了视频.音频.字幕(subtitle

最简单的视频播放示例7:SDL2播放YUV

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

最简单的视音频播放演示样例7:SDL2播放RGB/YUV

===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频播放演示样例2:GDI播放YUV, RGB 最简单的视音频播放演示样例3:Direct3D播放YUV,RGB(通过Surface) 最简单的视音频播放演示样例4:Direct3D播放RGB(通过Texture) 最简单的视音频播放演示样例5:OpenGL播放RGB/YUV 最简单的视音频播放演示样例

高效同步数据的方法及效率测试--边打包边压缩边传输边解压20150105

有些时候在备份或者同步有很多文件的大目录时(比如几个GB或者几十个GB的数据库目录.log目录),直接scp的话花费的时间较长,虽然可以采用先压缩再传输再解压的方法,传输的数据量确实减少了,但压缩和解压也会耗费很多的时间,总体效果也不令人满意,昨天晚上突发奇想,由于之前做过流媒体视频点播的项目的经验,如果能像看高清视频一样只需要下载完视频文件的metadata头就可以实现边下载边播放,即渐进式下载(http://baike.baidu.com/link?url=fTWQYBTqQr1BisysC