用ffmpeg把H264数据流解码成YUV420P
2015-06-17 09:18
525 查看
在网上找了很久这方面的内容,发现网上的代码都太旧了,所使用的函数旧到连最新版本的ffmpeg都已经不包含了,所以对于我这个初学者来说太坑拉。不过经过多次查找ffmpeg的头文件和结合网上的内容,终于成功可以解码拉。现在贴出来。
首先是初始化一些参数
[cpp] view plaincopy
//下面初始化h264解码库
avcodec_init();
av_register_all();
AVFrame *pFrame_ = NULL;
AVCodecContext *codec_ = avcodec_alloc_context();
/* find the video encoder */
AVCodec *videoCodec = avcodec_find_decoder(CODEC_ID_H264);
if (!videoCodec)
{
cout << "codec not found!" << endl;
return -1;
}
//初始化参数,下面的参数应该由具体的业务决定
codec_->time_base.num = 1;
codec_->frame_number = 1; //每包一个视频帧
codec_->codec_type = AVMEDIA_TYPE_VIDEO;
codec_->bit_rate = 0;
codec_->time_base.den = 30;//帧率
codec_->width = 1280;//视频宽
codec_->height = 720;//视频高
if(avcodec_open(codec_, videoCodec) >= 0)
pFrame_ = avcodec_alloc_frame();// Allocate video frame
else
return -1;
下面是具体的解码的代码
[cpp] view plaincopy
AVPacket packet = {0};
int frameFinished = dwBufsize;//这个是随便填入数字,没什么作用
packet.data = pBuffer;//这里填入一个指向完整H264数据帧的指针
packet.size = dwBufsize;//这个填入H264数据帧的大小
//下面开始真正的解码
avcodec_decode_video2(codec_, pFrame_, &frameFinished, &packet);
if(frameFinished)//成功解码
{
int picSize = codec_->height * codec_->width;
int newSize = picSize * 1.5;
//申请内存
unsigned char *buf = new unsigned char[newSize];
int height = p->codec->height;
int width = p->codec->width;
//写入数据
int a=0,i;
for (i=0; i<height; i++)
{
memcpy(buf+a,pFrame_->data[0] + i * pFrame_->linesize[0], width);
a+=width;
}
for (i=0; i<height/2; i++)
{
memcpy(buf+a,pFrame_->data[1] + i * pFrame_->linesize[1], width/2);
a+=width/2;
}
for (i=0; i<height/2; i++)
{
memcpy(buf+a,pFrame_->data[2] + i * pFrame_->linesize[2], width/2);
a+=width/2;
}
//===============
//到这里,buf里面已经是yuv420p的数据了,可以对它做任何的处理拉!
//===============
delete [] buf;
}
不过我发现这样解码很耗cpu资源,我的Core2 E7400 2.8G的处理器,解码1920X1080分辨率每秒30帧的视频时,CPU占用率能用到差不多50%。
PS:原来avcodec_decode_video2这个函数会修改codec_里面的参数的,也就是说如果原来里面填的分别率是1280X720,运行avcodec_decode_video2后[b]codec_里面会变成实际视频的分辨率。[/b]
首先是初始化一些参数
[cpp] view plaincopy
//下面初始化h264解码库
avcodec_init();
av_register_all();
AVFrame *pFrame_ = NULL;
AVCodecContext *codec_ = avcodec_alloc_context();
/* find the video encoder */
AVCodec *videoCodec = avcodec_find_decoder(CODEC_ID_H264);
if (!videoCodec)
{
cout << "codec not found!" << endl;
return -1;
}
//初始化参数,下面的参数应该由具体的业务决定
codec_->time_base.num = 1;
codec_->frame_number = 1; //每包一个视频帧
codec_->codec_type = AVMEDIA_TYPE_VIDEO;
codec_->bit_rate = 0;
codec_->time_base.den = 30;//帧率
codec_->width = 1280;//视频宽
codec_->height = 720;//视频高
if(avcodec_open(codec_, videoCodec) >= 0)
pFrame_ = avcodec_alloc_frame();// Allocate video frame
else
return -1;
下面是具体的解码的代码
[cpp] view plaincopy
AVPacket packet = {0};
int frameFinished = dwBufsize;//这个是随便填入数字,没什么作用
packet.data = pBuffer;//这里填入一个指向完整H264数据帧的指针
packet.size = dwBufsize;//这个填入H264数据帧的大小
//下面开始真正的解码
avcodec_decode_video2(codec_, pFrame_, &frameFinished, &packet);
if(frameFinished)//成功解码
{
int picSize = codec_->height * codec_->width;
int newSize = picSize * 1.5;
//申请内存
unsigned char *buf = new unsigned char[newSize];
int height = p->codec->height;
int width = p->codec->width;
//写入数据
int a=0,i;
for (i=0; i<height; i++)
{
memcpy(buf+a,pFrame_->data[0] + i * pFrame_->linesize[0], width);
a+=width;
}
for (i=0; i<height/2; i++)
{
memcpy(buf+a,pFrame_->data[1] + i * pFrame_->linesize[1], width/2);
a+=width/2;
}
for (i=0; i<height/2; i++)
{
memcpy(buf+a,pFrame_->data[2] + i * pFrame_->linesize[2], width/2);
a+=width/2;
}
//===============
//到这里,buf里面已经是yuv420p的数据了,可以对它做任何的处理拉!
//===============
delete [] buf;
}
不过我发现这样解码很耗cpu资源,我的Core2 E7400 2.8G的处理器,解码1920X1080分辨率每秒30帧的视频时,CPU占用率能用到差不多50%。
PS:原来avcodec_decode_video2这个函数会修改codec_里面的参数的,也就是说如果原来里面填的分别率是1280X720,运行avcodec_decode_video2后[b]codec_里面会变成实际视频的分辨率。[/b]
相关文章推荐
- Scala学习(一)--Scala基础学习
- linux定时器
- sdl2.0示例
- Android Loader学习
- android小事记
- Android 4.4 实现状态栏(status bar)透明效果
- 第十四周项目3:OOP版电子词典
- 立方尾不变
- android软重启问题
- 严重:IOException while loading persisted sessions: java.io.EOFException
- Trie——字典树
- 一步一步写算法(洗牌算法)
- 利用CSS3打造一组质感细腻丝滑的按钮
- Volley简单学习使用一
- 架构师速成3-开发者境界
- 架构师速成3-开发者境界 分类: 架构师速成 2015-06-17 09:14 173人阅读 评论(0) 收藏
- C#中的Linq Intersect与Except方法使用实例
- seekg() 与 tellg() 的用法及功能
- 只打开一个子窗体
- SDL2.0 学习笔记-1 windows下的第一个测试程序