利用FFmpge进行视频解码(从H264视频流到图像)

同上面所写的两篇文章,本篇依然是介绍FFmpge的相关操作,前一篇讲的是视频压缩,本篇则相反的讲视频的解码。废话不多说,直接上代码吧。

同理于上篇,本篇先设计一个视频解码相关的类,定义如下:

class Ffmpeg_Decoder
{
public:
	AVCodecParserContext *avParserContext;
	AVPacket avpkt;			//数据包结构体
	AVFrame *m_pRGBFrame;	//帧对象
	AVFrame *m_pYUVFrame;	//帧对象
	AVCodec *pCodecH264;	//解码器
	AVCodecContext *c;		//解码器数据结构对象
	uint8_t *yuv_buff;      //yuv图像数据区
	uint8_t *rgb_buff;		//rgb图像数据区
	SwsContext *scxt;		//图像格式转换对象
	uint8_t *filebuf;		//读入文件缓存
	uint8_t *outbuf;		//解码出来视频数据缓存
	int nDataLen;			//rgb图像数据区长度

	IplImage* img;			//OpenCV图像显示对象

	uint8_t *pbuf;			//用以存放帧数据
	int nOutSize;			//用以记录帧数据长度
	int haveread;			//用以记录已读buf长度
	int decodelen;			//解码器返回长度
	int piclen;				//解码器返回图片长度
	int piccount;			//输出图片计数

public:
	void Ffmpeg_Decoder_Init();//初始化
	void Ffmpeg_Decoder_Show(AVFrame *pFrame, int width, int height);//显示图片
	void Ffmpeg_Decoder_Close();//关闭
};

对类中声明的三个函数进行定义

void Ffmpeg_Decoder::Ffmpeg_Decoder_Init()
{
	avcodec_register_all();     //注册编解码器
	av_init_packet(&avpkt);     //初始化包结构
	m_pRGBFrame = new AVFrame[1];//RGB帧数据赋值
	m_pYUVFrame = avcodec_alloc_frame();
	filebuf = new uint8_t[1024 * 1024];//初始化文件缓存数据区
	pbuf = new uint8_t[200 * 1024];//初始化帧数据区
	yuv_buff = new uint8_t[200 * 1024];//初始化YUV图像数据区
	rgb_buff = new uint8_t[1024 * 1024];//初始化RGB图像帧数据区
	pCodecH264 = avcodec_find_decoder(CODEC_ID_H264);     //查找h264解码器
	if (!pCodecH264)
	{
		fprintf(stderr, "h264 codec not found\n");
		exit(1);
	}
	avParserContext = av_parser_init(CODEC_ID_H264);
	if (!pCodecH264)return;
	c = avcodec_alloc_context3(pCodecH264);//函数用于分配一个AVCodecContext并设置默认值,如果失败返回NULL,并可用av_free()进行释放

	if (pCodecH264->capabilities&CODEC_CAP_TRUNCATED)
		c->flags |= CODEC_FLAG_TRUNCATED;	/* we do not send complete frames */
	if (avcodec_open2(c, pCodecH264, NULL) < 0)return;
	nDataLen = 0;
}
void Ffmpeg_Decoder::Ffmpeg_Decoder_Show(AVFrame *pFrame, int width, int height)
{
	CvSize  rectangle_img_size;
	rectangle_img_size.height = height;
	rectangle_img_size.width = width;

	img = cvCreateImage(rectangle_img_size, IPL_DEPTH_8U, 3);
	uchar* imgdata = (uchar*)(img->imageData);     //图像的数据指针

	for (int y = 0; y<height; y++)
	{
		memcpy(imgdata + y*width * 3, pFrame->data[0] + y*pFrame->linesize[0], width * 3);
	}
	cvShowImage("解码图像", img);
	cvWaitKey(1);//可以将图像停留时间设的长点以便观察
	cvReleaseImage(&img);
	imgdata = NULL;
}
void Ffmpeg_Decoder::Ffmpeg_Decoder_Close()
{
	delete[]filebuf;
	delete[]pbuf;
	delete[]yuv_buff;
	delete[]rgb_buff;
	av_free(m_pYUVFrame);//释放帧资源
	avcodec_close(c);//关闭解码器
	av_free(c);
}

后面是主函数部分,因为通常解码都是从文件中读取数据流或者从网络中得到数据缓存,所以出于方便和操作性本人把解码的部分代码写在了主函数中

void main()
{
	Ffmpeg_Decoder ffmpegobj;
	ffmpegobj.Ffmpeg_Decoder_Init();//初始化解码器
	FILE *pf = NULL;
	fopen_s(&pf, "myData.h264", "rb");
	while (true)
	{
		ffmpegobj.nDataLen = fread(ffmpegobj.filebuf, 1, 1024 * 10, pf);//读取文件数据
		if (ffmpegobj.nDataLen<=0)
		{
			fclose(pf);
			break;
		}
		else
		{
			ffmpegobj.haveread = 0;
			while (ffmpegobj.nDataLen > 0)
			{
				int nLength = av_parser_parse2(ffmpegobj.avParserContext, ffmpegobj.c, &ffmpegobj.yuv_buff,
					&ffmpegobj.nOutSize, ffmpegobj.filebuf + ffmpegobj.haveread, ffmpegobj.nDataLen, 0, 0, 0);//查找帧头
				ffmpegobj.nDataLen -= nLength;//查找过后指针移位标志
				ffmpegobj.haveread += nLength;
				if (ffmpegobj.nOutSize <= 0)
				{
					continue;
				}
				ffmpegobj.avpkt.size = ffmpegobj.nOutSize;//将帧数据放进包中
				ffmpegobj.avpkt.data = ffmpegobj.yuv_buff;
				while (ffmpegobj.avpkt.size > 0)
				{
					ffmpegobj.decodelen = avcodec_decode_video2(ffmpegobj.c, ffmpegobj.m_pYUVFrame, &ffmpegobj.piclen, &ffmpegobj.avpkt);//解码
					if (ffmpegobj.decodelen < 0)
					{
						break;
					}
					if (ffmpegobj.piclen)
					{
						ffmpegobj.scxt = sws_getContext(ffmpegobj.c->width, ffmpegobj.c->height, ffmpegobj.c->pix_fmt, ffmpegobj.c->width, ffmpegobj.c->height, PIX_FMT_BGR24, SWS_POINT, NULL, NULL, NULL);//初始化格式转换函数
						if (ffmpegobj.scxt!= NULL)
						{
							avpicture_fill((AVPicture*)ffmpegobj.m_pRGBFrame, (uint8_t*)ffmpegobj.rgb_buff, PIX_FMT_RGB24, ffmpegobj.c->width, ffmpegobj.c->height);//将rgb_buff填充到m_pRGBFrame
							if (avpicture_alloc((AVPicture *)ffmpegobj.m_pRGBFrame, PIX_FMT_RGB24, ffmpegobj.c->width, ffmpegobj.c->height) >= 0)
							{
								sws_scale(ffmpegobj.scxt, ffmpegobj.m_pYUVFrame->data, ffmpegobj.m_pYUVFrame->linesize, 0,
									ffmpegobj.c->height, ffmpegobj.m_pRGBFrame->data, ffmpegobj.m_pRGBFrame->linesize);
								ffmpegobj.Ffmpeg_Decoder_Show(ffmpegobj.m_pRGBFrame, ffmpegobj.c->width, ffmpegobj.c->height);//解码图像显示
							}
							sws_freeContext(ffmpegobj.scxt);//释放格式转换器资源
							avpicture_free((AVPicture *)ffmpegobj.m_pRGBFrame);//释放帧资源
							av_free_packet(&ffmpegobj.avpkt);//释放本次读取的帧内存
						}
					}
					ffmpegobj.avpkt.size -= ffmpegobj.decodelen;
					ffmpegobj.avpkt.data += ffmpegobj.decodelen;
				}
			}
		}
	}
	ffmpegobj.Ffmpeg_Decoder_Close();//关闭解码器
}

OK,到此用FFmpeg进行视频解码的博客就告一段落了,下面是整个工程的下载地址:点击打开链接。同上一篇编码的博文工程,如果想要工程运行起来需要自行配置OpenCV。

利用FFmpge进行视频解码(从H264视频流到图像)

时间: 2024-10-05 19:31:48

利用FFmpge进行视频解码(从H264视频流到图像)的相关文章

利用FFmpge进行视频压缩(从图像到H264视频流)

对于FFmpeg相信做视频或图像处理这一块的都不会陌生,在网上也能找到很多相关的代码,但由于版本不同等原因,往往找到的代码都是需要自行修改才可以用,为此本人希望能尽绵薄之力,将开发包和自行编写的代码都放出来,如果初学者想要可以直接运行的代码做参考的话,可以下载我放出的FFmpeg开发包进行配置(配置的教程地址如下:点击打开链接),然后参考我写的编解码代码来进行程序的开发. 下面贴出的是我自己封装的FFmpeg视频压缩代码,如有更好的建议请告诉我,转载请注明出处. 首先我们设计一个视频压缩相关的类

从wireshark抓包分析rtmp协议,并提取出H264视频流

利用wireshark抓取rtmp流数据, 分析到rtmp流后,写入过滤条件,如 tcp.stream eq 6 导出tcp流 保存16进制的数据为纯文本格式 一定要选择 Hex转储,然后点击 "Sava as"注意,这个流开始的第一个字节一定是03,才是正确的.至此,我们有了可以用于分析的rtmp流的数据. 从wireshark抓包分析rtmp协议,并提取出H264视频流 原文地址:https://www.cnblogs.com/russinovich/p/9240944.html

在iOS平台使用ffmpeg解码h264视频流

来源:http://www.aichengxu.com/view/37145 在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或URL传入即可打开.读取视频数据.解码器初始参数设置等,都可以通过调用API来完成. 但是对于h264流,没有任何封装格式,也就无法使用libavformat.所以许多工作需要自己手工完成. 这里的h264流指AnnexB,也

在iOS平台使用ffmpeg解码h264视频流(转)

在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或URL传入即可打开.读取视频数据.解码器初始参数设置等,都可以通过调用API来完成. 但是对于h264流,没有任何封装格式,也就无法使用libavformat.所以许多工作需要自己手工完成. 这里的h264流指AnnexB,也就是每个nal unit以起始码00 00 00 01 或 00 00 01开

利用开源程序(ImageMagick+tesseract-ocr)实现图像验证码识别

利用开源程序(ImageMagick+tesseract-ocr)实现图像验证码识别 分类: 开放项目2012-07-23 17:28 6712人阅读 评论(0) 收藏 举报 tiffimagecompression引擎pascalcharacter --------------------------------------------------低调的分割线--------------------------------------------------- Linux下有两个重要的编程准则

【DSP开发】利用CCS5.4开发基于DSP6455的JPEG2000图像解压缩过程

[DSP开发]利用CCS5.4开发基于DSP6455的JPEG2000图像解压缩过程 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明:前端是时间基于VS2010工程,在windows上实现了对openjpeg2000的改写,实现了从内存中读取数据进行解压缩的工作.由于某些技术储备需要,将其移植到DSP6455中进行解压缩.本文记录的就是整个移植过程. 0. 异想天开:试图在CCS上直接使用VS2010生成好的编译库 这个想法是一直就有的,在调试VS

利用ffmpeg0.6.1把.h264纯码流打包成.mp4 .avi等格式 (转载)

转自:http://cache2.weidaohang.org/h/index.php?q=aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1cWluZ183MzkvYXJ0aWNsZS9kZXRhaWxzLzY2MzY4NTc= 一直比较困惑一个问题,都说ffmpeg功能很强大,但是自己一直没有去研究一下,今天终于见识了一下它的强大之处了! 首先当然是在linux下编译和安装成功ffmpeg,关于具体的安装流程,可以参考我前面的一篇博文! 这里就直接介绍怎么把.h264纯码流打包

从RTSP协议传输的H264视频流中取出每一个帧属于I、P、B中的哪一种帧

本文地址:http://www.cnblogs.com/herbix/p/4270035.html RTSP是一个控制协议,其中的数据是用RTP传输的.RTP使用了UDP,每个UDP包的内容区(没有UDP头)都包含以下的几个部分: RTP_FIXED_HEADER 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

利用matlab自带函数快速提取二值图像的图像边缘 bwperim函数

clear all;close all;clc; I = imread('rice.png'); I = im2bw(I); J = bwperim(I); % 提取二值图像图像边缘 figure; subplot(121);imshow(I);title('原二值图像'); subplot(122);imshow(J);title('图像边缘'); ? 其他提取图像边缘的方法: 利用膨胀和腐蚀提取图像边缘 matlab实现 https://blog.csdn.net/Ibelievesunsh