对于FFmpeg相信做视频或图像处理这一块的都不会陌生,在网上也能找到非常多相关的代码。但因为版本号不同等原因。往往找到的代码都是须要自行改动才干够用,为此本人希望能尽绵薄之力,将开发包和自行编写的代码都放出来,假设刚開始学习的人想要能够直接执行的代码做參考的话。能够下载我放出的FFmpeg开发包进行配置(配置的教程地址例如以下:点击打开链接)。然后參考我写的编解码代码来进行程序的开发。

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

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

class Ffmpeg_Encoder
{
public:
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; //输出视频高度
AVPacket pkt; //数据包对象
int imgwidthlen; //图像宽度占用空间
public:
void Ffmpeg_Encoder_Init();//初始化
void Ffmpeg_Encoder_Setpara(AVCodecID 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_pYUVFrame = new AVFrame[1];//YUV帧数据赋值
c = NULL;//解码器指针对象赋初值
}
void Ffmpeg_Encoder::Ffmpeg_Encoder_Setpara(AVCodecID 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 = 1024*1024; //码率,越高视频质量越好
c->width = vwidth;//设置编码视频宽度
c->height = vheight; //设置编码视频高度
c->time_base.den = 25;//设置帧率,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 = AV_PIX_FMT_YUV420P;//设置像素格式 imgwidthlen = c->width * 3;
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, AV_PIX_FMT_BGR24, c->width, c->height, AV_PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL);//初始化格式转换函数
av_image_fill_arrays(m_pYUVFrame->data, m_pYUVFrame->linesize, yuv_buff, AV_PIX_FMT_YUV420P, width, height, 1);
}

void Ffmpeg_Encoder::Ffmpeg_Encoder_Encode(FILE *file, uint8_t *data)
{
av_init_packet(&pkt);
memcpy(rgb_buff, data, nDataLen);//拷贝图像数据到rgb图像帧缓存中准备处理
sws_scale(scxt, &rgb_buff, &imgwidthlen, 0, c->height, m_pYUVFrame->data, m_pYUVFrame->linesize);// 将RGB转化为YUV int myoutputlen = 0;
int returnvalue = avcodec_encode_video2(c, &pkt, m_pYUVFrame, &myoutputlen);
if (returnvalue == 0)
{
fwrite(pkt.data, 1, pkt.size, file);
}
}

void Ffmpeg_Encoder::Ffmpeg_Encoder_Close()
{
delete[]m_pYUVFrame;
delete[]rgb_buff;
delete[]yuv_buff;
delete[]outbuf;
sws_freeContext(scxt);
avcodec_close(c);//关闭编码器
av_free(c);
}

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

void main()
{
Ffmpeg_Encoder ffmpegobj;
//图象编码
FILE *f = NULL;
char * filename = "myData.h264";
fopen_s(&f, filename, "wb");//打开文件存储编码完毕数据 IplImage* img = NULL;//OpenCV图像数据结构指针 int picturecount = 1;
bool firstencode = true;
/**此部分用的是OpenCV读入图像对象并取得图像的数据区,也能够用别的方法获得图像数据区**/
img = cvLoadImage("1.png", 1);//打开图像
while (picturecount != 60)
{
if (firstencode)
{
firstencode = false;
ffmpegobj.Ffmpeg_Encoder_Init();//初始化编码器
ffmpegobj.Ffmpeg_Encoder_Setpara(AV_CODEC_ID_H264, img->width, img->height);//设置编码器參数
}
ffmpegobj.Ffmpeg_Encoder_Encode(f, (uchar*)img->imageData);//编码
picturecount++;
}
fclose(f);
ffmpegobj.Ffmpeg_Encoder_Close();
cvReleaseImage(&img);//释放图像数据结构指针对像所指内容
}

OK。到此用FFmpeg进行视频压缩的博客就告一段落了,以下是整个project的下载地址:点击打开链接。只是假设想要执行起来配置OpenCV还是须要自行动手的哈哈。

另外在做项目的过程中在编码这块还遇到一个非常奇怪的问题。就是在编码调用到avcodec_encode_video2特别是project也调用到解码函数的时候,在VS里面点击执行是没有问题的,但一执行release目录以下编译出来的exe文件,程序偶尔会报内存错误,错误的位置在avcodec_encode_video2这个函数里面。

这个让人百思不得其解。后来想想或者VS在执行的时候兼容性比較好,所以没有这个问题。是故例如以下图对exe文件的兼容性进行设置



    这个问题就攻克了,是故怀疑ffmpeg库的avcodec_encode_video2这个函数所在的dll对于windows或者是windows64位系统的兼容性不大好。

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

  1. Matlab利用subplot绘制多个图像

    利用subplot绘制多个图像 subplot(m,n,p) subplot是将多个图画到一个平面上的函数,m是行,n是列,p是所要绘制图所在的位置 x = 0:0.1:100; sinY = sin ...

  2. OpenCV实时美颜摄像并生成H264视频流

    为什么美颜摄像这么简单的功能,OpenCV这个开源项目网上很少有代码呢?对于在windows平台下,生成h264视频流也比价麻烦,没有现成的api可以使用,需要借助MinGw编译libx264,或者f ...

  3. 从wireshark数据中分析rtmp协议,并提取出H264视频流

    我写的小工具 rtmp_parse.exe 使用用法如先介绍下: -sps  [文件路径] 解析 sps 数据 文件当中的内容就是纯方本的hexstring: 如 42 E0 33 8D 68 05 ...

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

    在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或UR ...

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

    来源:http://www.aichengxu.com/view/37145 在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,f ...

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

    一.简介 R中的ggplot2是一个非常强大灵活的数据可视化包,熟悉其绘图规则后便可以自由地生成各种可视化图像,但其默认的色彩和样式在很多时候难免有些过于朴素,本文将要介绍的ggthemr包专门针对原 ...

  7. 利用PIL库创建空白图像

    背景 最近,想自己生成带位置坐标的文字数据集来训练文本位置探测网络. 理想情况是,给文字加盐噪声,背景不需要加噪声,所以需要创建一个空白的背景.将文字放在空白背景上,然后利用opencv加噪声. 解决 ...

  8. python利用sift和surf进行图像配准

    1.SIFT特征点和特征描述提取(注意opencv版本) 高斯金字塔:O组L层不同尺度的图像(每一组中各层尺寸相同,高斯函数的参数不同,不同组尺寸递减2倍) 特征点定位:极值点 特征点描述:根据不同b ...

  9. 利用onMouseOver和onMouseOut实现图像翻滚

    代码: <img src="images/001.jpg" alt="pic" onmouseover="this.src='images/00 ...

随机推荐

  1. Django--知识补充

    自定义标签或过滤器 渲染变量的方法(过滤器:修改数据或格式转换) {{ var | add }} {{ var | date:"Y-m" }} {{ var | safe }} 渲 ...

  2. js this 和 event 的区别

    今天在看javascript入门经典-事件一章中看到了 this 和 event 两种传参形式.因为作为一个初级的前端开发人员平时只用过 this传参,so很想弄清楚,this和event的区别是什么 ...

  3. VC++函数只被调用一次

    如何保证某个函数只被调用一次   一个函数caller会在其内部调用另外一个函数callee,现在的情况是,caller可能会在多个地方被多次调用,而你希望callee只在第一次被调用时被调用一次.一 ...

  4. Mybatis学习总结四(关联查询)

    一.一对一查询 实例:查询所有订单信息,关联查询下单用户信息. Method1:使用resultType,定义订单信息po类,此po类中包括了订单信息和用户信息. public class Order ...

  5. 脚手架工具搭建VUE应用

    首先需要安装node.js,然后安装CLI工具. vue init webpack vue-lesson2 使用element组件的话,需要用到如下命令: cd vue-lesson2 vue add ...

  6. 【转载】原 IntelliJ IDEA (idea)引入eclipse web项目

    原文地址:http://my.oschina.net/u/1170781/blog/192731 摘要 概述IntelliJ IDEA,以后都简称为idea,鼓捣了很久,看了很多例子才搞出来,希望对其 ...

  7. JavaScript中的方法

    JavaScript中的方法 在JavaScript中,可以通过对象来调用对应的方法.在JavaScript中,有三个重要的window对象方法:用于显示警告信息的alert.用于显示确认信息的con ...

  8. java面试题链接

    http://blog.csdn.net/jackfrued/article/details/17339393

  9. Dollar Dayz POJ - 3181

    解法 完全背包+大数...不想写大数了放个python得了 代码 dp=[0 for i in range(2000)] n,k=map(int,input().split()) num=[i for ...

  10. JSP页面中的动作标识

    JSP页面中的动作标识 制作人:全心全意 包含文件标识<jsp:include> 此标识和include指令类似,用于向当前页面中包含其它的文件,且包含的文件可以是动态文件,也可以是静态文 ...