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

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

下面贴出的是我自己封装的FFmpeg视频压缩代码,如有更好的建议请告诉我,转载请注明出处。

首先我们设计一个视频压缩相关的类,定义如下

class Ffmpeg_Encoder
{
public:

	AVFrame *m_pRGBFrame;	//帧对象
	AVFrame *m_pYUVFrame;	//帧对象
	AVCodec *pCodecH264;	//编码器
	AVCodecContext *c;		//编码器数据结构对象
	uint8_t *yuv_buff;      //yuv图像数据区
	uint8_t *rgb_buff;		//rgb图像数据区
	SwsContext *scxt;		//图像格式转换对象
	uint8_t *outbuf;		//编码出来视频数据缓存
	int outbuf_size;        //编码输出数据去大小
	int nDataLen;			//rgb图像数据区长度
	int width;				//输出视频宽度
	int height;				//输出视频高度

public:
	void Ffmpeg_Encoder_Init();//初始化
	void Ffmpeg_Encoder_Setpara(CodecID mycodeid,int vwidth,int vheight);//设置参数,第一个参数为编码器,第二个参数为压缩出来的视频的宽度,第三个视频则为其高度
	void Ffmpeg_Encoder_Encode(FILE *file, uint8_t *data);//编码并写入数据到文件
	void Ffmpeg_Encoder_Close();//关闭
};

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

void Ffmpeg_Encoder::Ffmpeg_Encoder_Init()
{
	av_register_all();
	avcodec_register_all();

	m_pRGBFrame = new AVFrame[1];//RGB帧数据赋值
	m_pYUVFrame = new AVFrame[1];//YUV帧数据赋值  

	c = NULL;//解码器指针对象赋初值
}
void Ffmpeg_Encoder::Ffmpeg_Encoder_Setpara(CodecID mycodeid, int vwidth, int vheight)
{
	pCodecH264 = avcodec_find_encoder(mycodeid);//查找h264编码器
	if (!pCodecH264)
	{
		fprintf(stderr, "h264 codec not found\n");
		exit(1);
	}
	width = vwidth;
	height = vheight;

	c = avcodec_alloc_context3(pCodecH264);//函数用于分配一个AVCodecContext并设置默认值,如果失败返回NULL,并可用av_free()进行释放
	c->bit_rate = 400000; //设置采样参数,即比特率
	c->width = vwidth;//设置编码视频宽度
	c->height = vheight; //设置编码视频高度
	c->time_base.den = 2;//设置帧率,num为分子和den为分母,如果是1/25则表示25帧/s
	c->time_base.num = 1;
	c->gop_size = 10; //设置GOP大小,该值表示每10帧会插入一个I帧
	c->max_b_frames = 1;//设置B帧最大数,该值表示在两个非B帧之间,所允许插入的B帧的最大帧数
	c->pix_fmt = PIX_FMT_YUV420P;//设置像素格式

	av_opt_set(c->priv_data, "tune", "zerolatency", 0);//设置编码器的延时,解决前面的几十帧不出数据的情况

	if (avcodec_open2(c, pCodecH264, NULL) < 0)return;//打开编码器

	nDataLen = vwidth*vheight * 3;//计算图像rgb数据区长度

	yuv_buff = new uint8_t[nDataLen/2];//初始化数据区,为yuv图像帧准备填充缓存
	rgb_buff = new uint8_t[nDataLen];//初始化数据区,为rgb图像帧准备填充缓存
	outbuf_size = 100000;////初始化编码输出数据区
	outbuf = new uint8_t[outbuf_size];

	scxt = sws_getContext(c->width, c->height, PIX_FMT_BGR24, c->width, c->height, PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL);//初始化格式转换函数
}
void Ffmpeg_Encoder::Ffmpeg_Encoder_Encode(FILE *file, uint8_t *data)
{
	memcpy(rgb_buff, data, nDataLen);//拷贝图像数据到rgb图像帧缓存中准备处理
	avpicture_fill((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, PIX_FMT_RGB24, width, height);//将rgb_buff填充到m_pRGBFrame
	avpicture_fill((AVPicture*)m_pYUVFrame, (uint8_t*)yuv_buff, PIX_FMT_YUV420P, width, height);//将yuv_buff填充到m_pYUVFrame
	sws_scale(scxt, m_pRGBFrame->data, m_pRGBFrame->linesize, 0, c->height, m_pYUVFrame->data, m_pYUVFrame->linesize);// 将RGB转化为YUV
	int myoutputlen = avcodec_encode_video(c, outbuf, outbuf_size, m_pYUVFrame);
	fwrite(outbuf, 1, myoutputlen, file);
}
void Ffmpeg_Encoder::Ffmpeg_Encoder_Close()
{
	delete[]m_pRGBFrame;
	delete[]m_pYUVFrame;
	delete[]rgb_buff;
	delete[]yuv_buff;
	delete[]outbuf;
	sws_freeContext(scxt);
	avcodec_close(c);//关闭编码器
	av_free(c);
}

最后我们只需要在主函数对这几个函数进行调用就可以了,由于本人为了方便直接用OpencCV来打开图像并取得图像的数据区,所以如果希望直接运行本人后面所发的工程的话还需要自行去配置OpenCV,不过这个在网上实在是说烂了,随便找找就能配置出来。如果不希望用OpenCV来打开图像的话,本人在代码中也注明了应该修改的位置,可自行想办法得到图像数据区并放入视频压缩函数即可。

void main()
{
	Ffmpeg_Encoder ffmpegobj;
	ffmpegobj.Ffmpeg_Encoder_Init();//初始化编码器
	ffmpegobj.Ffmpeg_Encoder_Setpara(CODEC_ID_H264,800,600);//设置编码器参数

	//图象编码
	FILE *f = NULL;
	char * filename = "myData.h264";
	fopen_s(&f, filename, "wb");//打开文件存储编码完成数据

	IplImage* img = NULL;//OpenCV图像数据结构指针
	IplImage* resizeimg = NULL;//尺寸
	int picturecount = 1;
	while (picturecount != 9)
	{
		/**此部分用的是OpenCV读入图像对象并取得图像的数据区,也可以用别的方法获得图像数据区**/
		char chpicname[100];
		sprintf(chpicname, "testpicture\\Horse%d.jpg", picturecount);//获得图片路径
		//sprintf(chpicname, "1.jpg", picturecount);//获得图片路径
		img = cvLoadImage(chpicname, 1);//打开图像
		//由于OpenCV图像数据区是以BGR排列的,所以要将其数据转换为正常的RGB排列才能做进一步的压缩,不然压出来的视频颜色会不正确
		uchar* data = (uchar*)(img->imageData);
		uchar mid = 0;
		for (int row = 0; row<img->height; row++)
		for (int cols = 0; cols < img->width; cols++)
		{
			mid = data[row*img->widthStep / sizeof(uchar)+cols*img->nChannels + 0];//G
			data[row*img->widthStep / sizeof(uchar)+cols*img->nChannels + 0] = data[row*img->widthStep / sizeof(uchar)+cols*img->nChannels + 2];
			data[row*img->widthStep / sizeof(uchar)+cols*img->nChannels + 2] = mid;
		}
		resizeimg = cvCreateImage(cvSize(800, 600), 8, 3);
		cvResize(img, resizeimg, CV_INTER_LINEAR);//调整图像大小
		/**此部分用的是OpenCV读入图像对象并取得图像的数据区,也可以用别的方法获得图像数据区**/

		ffmpegobj.Ffmpeg_Encoder_Encode(f, (uchar*)resizeimg->imageData);//编码

		cvReleaseImage(&img);//释放图像数据结构指针对像所指内容
		cvReleaseImage(&resizeimg);
		picturecount++;
	}
	fclose(f);
	ffmpegobj.Ffmpeg_Encoder_Close();
}

OK,到此用FFmpeg进行视频压缩的博客就告一段落了,晚些会放出整个工程的下载,不过配置还是需要自行动手的哈哈。

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

时间: 2024-12-29 19:57:14

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

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

同上面所写的两篇文章,本篇依然是介绍FFmpge的相关操作,前一篇讲的是视频压缩,本篇则相反的讲视频的解码.废话不多说,直接上代码吧. 同理于上篇,本篇先设计一个视频解码相关的类,定义如下: class Ffmpeg_Decoder { public: AVCodecParserContext *avParserContext; AVPacket avpkt; //数据包结构体 AVFrame *m_pRGBFrame; //帧对象 AVFrame *m_pYUVFrame; //帧对象 AVC

利用键盘左右键使图像左右移动,上下键使图像的两个纹理可见度比例上下调整

利用键盘左右键使图像左右移动, glm::mat4 trans; trans = glm::translate(trans, glm::vec3(translation, 0.0f, 0.0f)); glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "transform"), 1, GL_FALSE, glm::value_ptr(trans)); 1 void processInput(GLFWwindow* window)

在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开

从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

(数据科学学习手札55)利用ggthemr来美化ggplot2图像

一.简介 R中的ggplot2是一个非常强大灵活的数据可视化包,熟悉其绘图规则后便可以自由地生成各种可视化图像,但其默认的色彩和样式在很多时候难免有些过于朴素,本文将要介绍的ggthemr包专门针对原生ggplot2图像进行美化,掌握它之后你就可以创作出更具特色和美感的数据可视化作品. 二.基础内容 2.1 安装 不同于常规的R包,ggthemr并没有在CRAN上发布,因此我们需要使用devtools中的install_github()直接从github上安装它,参照github上ggthemr

从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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

图像去雾 利用最小值滤波(待改进)

图像去雾 我的个神啊~ 调了这么久终于阶段性"胜利了" -- 利用最小值滤波正确实现图像去雾. 因为是C语言实现,很多细节都要注意,很砸时间--本来看起来很简单的程序,就是有bug,debug的时间很长了,这也是一种锻炼吧,难得的实战机会.磨C 这把刀这么久了,是该做做具体应用了!刀子是否锋利,要接受考验! 程序很大程度上没有利用OpenCV的一些数据操作的接口,除了图像显示和读取之外,其他的数据处理部分都是自己实现的.这几天的时间全砸进去了~ 暑假哇~时间过的慢点可好~ 由于项目正在

Windows下利用live555实现H264实时流RTSP发送

文如其名,最近在做的项目要求利用RTSP协议转发处理完的H264视频数据给上一层客户端,环境是Windows的VS2013,于是就各种百度谷歌找代码.结果在得到利用live555去做比较简单的结论的同时也悲情地发现,网上别人贴出来的代码基本都是Linux上面的.在修改了两份来适用于Windows无效后,又一次陷入了百度谷歌的无尽搜索中.Anyway,最后终于解决了,所以贴出代码跟大家分享下,希望能给和我需求相似的童鞋一点启发,也希望有高手指正其中的问题. 用live555进行RTSP的播放基本上