博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用FFMPEG SDK解码流数据
阅读量:6548 次
发布时间:2019-06-24

本文共 1913 字,大约阅读时间需要 6 分钟。

本文以H264视频流为例,讲解解码流数据的步骤。

为突出重点,本文只专注于讨论解码视频流数据,不涉及其它(如开发环境的配置等)。如果您需要这方面的信息,请和我联系。

  • 准备变量

定义AVCodecContext。如果您使用类,可以定义成类成员。我这里定义成全局变量。

 

static
 AVCodecContext 
*
 g_pCodecCtx 
=
 NULL;

定义一个AVFrame,AVFrame描述一个多媒体帧。解码后的数据将被放在其中。

static
 AVFrame 
*
 g_pavfFrame 
=
 NULL;

 

  • 初始化解码器

现在开始初始化您的解码器。我把整个初始化过程包在了一个函数里,除非您有更好的主意,我建议您也这么做。函数长得象这样:

BOOL H264_Init()

{

}

初始化libavcodec,MMPEG要求,这个函数一定要第一个被调用:

avcodec_init();

挂上所有的codec。也许只挂一个H264的codec就行,我没试过:

av_register_all();

得到H264的解码器:

AVCodec 
*
 pCodec 
=
 avcodec_find_decoder(CODEC_ID_H264);

创建一个AVCodecContext,并用默认值初始化:

g_pCodecCtx 
=
 avcodec_alloc_context();

更改g_pCodecCtx的一些成员变量的值,您应该从解码方得到这些变量值:

g_pCodecCtx
->
time_base.num 
=
 
1
//
这两行:一秒钟25帧
g_pCodecCtx
->
time_base.den 
=
 
25
;
g_pCodecCtx
->
bit_rate 
=
 
0
//
初始化为0
g_pCodecCtx
->
frame_number 
=
 
1
//
每包一个视频帧
g_pCodecCtx
->
codec_type 
=
 CODEC_TYPE_VIDEO;
g_pCodecCtx
->
width 
=
 
704
//
这两行:视频的宽度和高度
g_pCodecCtx
->
height 
=
 
576
;

打开codec。如果打开成功的话,分配AVFrame:

 

if
(avcodec_open(g_pCodecCtx, pCodec) 
>=
 
0
)
ExpandedBlockStart.gif
{
g_pavfFrame 
=
 avcodec_alloc_frame();
//
 Allocate video frame
}

列出完整的初始化解码库的代码:

  • 解码

如果您只要求解成YUV 420I数据,只需一次调用就可以了:

 

avcodec_decode_video(g_pCodecCtx, g_pavfFrame, (
int
 
*
)
&
nGot, (unsigned __int8 
*
)pSrcData, dwDataLen);

这里,nGot用来返回解码成功与否,avcodec_decode_video调用完成后,如果nGot不等于0,则表示解码成功,否则未解出视频帧。

pSrcData是待解的H264编码的一段数据流,dwDataLen表示该段数据流的长度,单位是byte。

解码后的视频帧(YUV数据)被存入g_pavfFrame,g_pavfFrame->data[0]、g_pavfFrame->data[1]、g_pavfFrame->data[2]即是YUV数据。下面的示例代码把YUV数据压在了一块内存里,排列方式为:

YY

YY

U

V

该函数有返回值:如果解码成功,则返回本次解码使用的码流字节数,否则返回0。为简单起见,我这里假设pSrcData只包含一个视频帧。

同样,出于模块化的要求和代码维护的方便,我把解码动作也包在了一个函数里:

 

BOOL H264_Decode(
const
 PBYTE pSrcData, 
const
 DWORD dwDataLen, PBYTE pDeData, 
int
 
*
 pnWidth, 
int
 
*
 pnHeight)
pSrcData – 待解码数据
dwDataLen – 待解码数据字节数
pDeData – 用来返回解码后的YUV数据
pnWidth, pnHeight – 用来返回视频的长度和宽度

下面列出完整的代码:

  • 释放解码器

以上其实已经完成了本文的任务,但从负责任的角度,要善始善终嘛。

释放的过程没什么好说的,一看就明白。同样,我也把它们包在了一个函数里:

(抱歉的很,文章本来是用Word写的,代码块是一个个文本框,但贴到这里却变成了图片。) 

转载地址:http://txgdo.baihongyu.com/

你可能感兴趣的文章
linux如何分大于2T的磁盘分区
查看>>
Android:ListView、BaseAdapter、convertView、ListView优化及事件、notifyDataSetChanged()
查看>>
JS操作JSON总结
查看>>
Grafan5.4.2+Zabbix安装配置
查看>>
windows8.1 下硬盘安装 ubuntu-14.04.2-desktop-amd64.iso
查看>>
人大MapReduce编程题解答-001,A+B Per Line
查看>>
Java程序员从笨鸟到菜鸟之(三十四)大话设计模式(五)创建者模式和原型模式...
查看>>
eclipse构建maven的web项目
查看>>
Ubuntu去掉命令行前用户名和主机名步骤
查看>>
java实现断点续传
查看>>
Linux中sendmail启动速度慢的解决方法
查看>>
如何在Eclipse中查看Android API源码以及support包源码
查看>>
android SharedPreferences apply和commit的区别
查看>>
实现Bootstrap导航条可点击和鼠标悬停显示下拉菜单
查看>>
MongoDB入门3——更新文档和修改器1
查看>>
《现代操作系统》读书笔记之——进程间通信2
查看>>
面对高考
查看>>
php-excel-reader - 简单的excel 读取类
查看>>
ubuntu 在lnmp中php安装GD库
查看>>
Python学习笔记 1
查看>>