FFmpeg的常见结构体

原创 2018年04月17日 15:00:36

小程之前介绍过FFmpeg的帧的结构(AVPacket跟AVFrame),帧会在一些流程中使用到。

除了帧结构,FFmpeg还有其它一些结构会在流程中使用到。

FFmpeg还有哪些常见的结构呢?先来看一下这个截图:
AVFormatContext聚合结构

这张图中的主角,是AVFormatContext。AVFormatContext,是FFmpeg的基本结构之一,对应于封装格式(或容器格式)。

围绕FFmpeg的“格式场景”,本文介绍FFmpeg常见的数据结构

按照上图,小程依次介绍图中的几个结构体。

(一)AVCodec

AVCodec是FFmpeg设计上的一个结构体,用来保存编解码器的信息,也就是说,AVCodec是编码器或解码器。

小程还是以调试的办法,具体看一下AVCodec变量中的内容。

(1)演示代码

演示代码的目录结构是这样的:
代码目录结构

其中的FFmpeg静态库是事先编译好的(这里是macos版本,因为小程用了mac电脑),编译的办法可以参考之前的文章,读者可以关注“广州小程”微信公众号,并在相应的菜单项中找到文章。

moments.mp4 是试用的视频文件(mp4封装格式)。对于封装格式,在公众号的“音视频”之“基础概念与流程”中也可以找到,小程有专门介绍过媒体格式。

makefile是编译脚本,用来编译演示代码,当然也可以直接用gcc来编译。

show_avcodec.c就是演示代码了,内容如下:

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"

void show_avcodec(const char* filepath) {
    av_register_all();
    av_log_set_level(AV_LOG_DEBUG);
    AVFormatContext* formatContext = avformat_alloc_context();
    int status = 0;
    int success = 0;
    int videostreamidx = -1;
    AVCodecContext* codecContext = NULL;
    status = avformat_open_input(&formatContext, filepath, NULL, NULL);
    if (status == 0) {
        status = avformat_find_stream_info(formatContext, NULL);
        if (status >= 0) {
            for (int i = 0; i < formatContext->nb_streams; i ++) {
                if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
                    videostreamidx = i;
                    break;
                }
            }
            if (videostreamidx > -1) {
                codecContext = formatContext->streams[videostreamidx]->codec;
                AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
                if (codec) {
                    status = avcodec_open2(codecContext, codec, NULL);
                    if (status == 0) {
                        success = 1;
                    }
                }
            }
        }
        else {
            av_log(NULL, AV_LOG_DEBUG, "avformat_find_stream_info error\n");
        }
        avformat_close_input(&formatContext);
    }
    avformat_free_context(formatContext);
}

int main(int argc, char *argv[])
{
    show_avcodec("moments.mp4");
    return 0;
}

(2)编译与调试

makefile的内容:

exe=showavcodec
srcs=show_avcodec.c 
$(exe):$(srcs)
    gcc -o $(exe) $(srcs) -Iffmpeg/include/ -Lffmpeg -lffmpeg -liconv -lz -g
clean:
    rm -f $(exe) *.o

直接执行make来编译,编译后会生成符号表文件即showavcodec.dSYM。

这里只是简单看一下AVCodec的内容,用gdb来调试即可:

gdb showavcodec
b 25
r

在断点的地方,看一下AVCodec变量中的值:
avcodec的内容

(3)AVCodec结构内容

AVCodec是编解码器的结构体,在libavcodec/avcodec.h中定义。

在这个示例中,AVCodec是一个解码器。

AVCodec结构中的一些变量,从它的名字或者FFmpeg详细的注释中,可以知道是什么含义。

比如name是编解码的名称,而long_name就是长的名称,等等。

在设计上,AVCodec是编解码器的抽象,所以,编解码器是有相应的具体实现的。

事实上,每一个编解码器都有具体的实现。

比如h264的解码器(libavcodec/h264.c):
h264解码器

比如mp3lame的编码器(libavcodec/libmp3lame.c)
mp3lame编码器

FFmpeg会使用上这些具体的编解码器的实现,以完成编解码等功能。

(二)AVCodecContext

AVCodecContext可以简单理解为AVCodec的使用场景,而实际上AVCodecContext包括的内容,除了关联AVCodec,还有其它信息。

跟调试AVCodec变量一样,直接使用上面的演示代码就可以调试AVCodecContext,部分代码如下 :

if (videostreamidx > -1) {
    codecContext = formatContext->streams[videostreamidx]->codec;
    AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
    if (codec) {
        status = avcodec_open2(codecContext, codec, NULL);
        if (status == 0) {
            success = 1;
        }
    }
}

同样用gdb来调试就可以了,在拿到codecContext后下断点,可以看到AVCodecContext的部分内容如下:
avcodeccontext内容

其中有一些变量应该引起注意,比如:

width/height 视频的宽与高
codec_id 编解码器的id,根据它可以找到对应的编解码器
extradata 对于h264编码的视频,保存了pps与sps的参数信息
profile 视频编码复杂等级
sample_rate 音频的采样率
channels 音频的声道数
sample_fmt 音频的采样格式

跟AVCodec一样,AVCodecContext结构体在libavcodec/avcodec.h中定义。

(三)AVStream

上面介绍了AVCodec、AVCodecContext,现在介绍AVStream。

这三者的大概关系是这样的:

AVStream聚合AVCodecContext

AVStream对应音频流、视频流、字幕等媒体流。

FFmepg以流的概念来封装不同的媒体。

调试AVStream的示例代码与编译,可以查看上面AVCodec调试的介绍。大概如下:
查看AVStream的代码

下断点,可以看到AVStream中的内容,比如:
AVStream中的变量值

AVStream中的一些变量:

index,流的索引
codec,流对应的avcodeccontext
time_base,时间基准(比例)
duration,流的时长
metadata,流的元信息
nb_frames,流中帧的数量

AVStream结构,在libavformat/avformat.h中定义。

(四)AVFormatContext

AVFormatContext是主角,表示为格式的场景,对应于封装格式(或容器格式)。

同样,使用之前的示例代码,在avformat_open_input函数后下断点:
avformatcontext示例代码

可以查看avformatcontext结构中的变量值:
avformatcontext结构中的变量值

AVFormatContext中的metadata记录了多媒体文件的一些信息(比如作者、专辑之类),可以这样取得里面的信息:

if (formatCtx->metadata) {
    AVDictionaryEntry *item = NULL;
    while((item = av_dict_get(formatCtx->metadata, "", item, AV_DICT_IGNORE_SUFFIX))){
        printf("key:%s value:%s \n", item->key, item->value);
    }

    // 或者这样:
    AVDictionaryEntry *tag = NULL;
    tag = av_dict_get(formatCtx->metadata, "artist", NULL, 0);
    if (tag) {
        std::string artist = (char*)tag->value;
    }
}

AVFormatContext的一些变量说明:

iformat/oformat,输入/输出格式,在解复用(解封装)或复用(封装)时使用。
pb,输入或输出场景,提供数据操作接口(比如读写、seek等)。
nb_streams,流的个数(以流的方式来复用)。
streams,流的数组。
filename,文件名。
start_time,流的起始时间,以AV_TIME_BASE为单位(除以AV_TIME_BASE转为秒)。
duration,流的时长,以AV_TIME_BASE为单位。
bit_rate,比特率。
probesize,在检测容器格式时,最大的探测大小,在avformat_open_input之前设置(或不设置使用默认值)。
max_analyze_duration,最大的分析数据的时长,在检测编码格式时使用,在avformat_find_stream_info前设置(或不设置),越大越耗时。
metadata,元信息。

AVFormatContext结构,在libavformat/avformat.h中定义。

(五)AVIOContext

AVIOContext是输入输出信息的结构体,它在FFmpeg结构体系中的位置是这样的:
aviocontext的位置

可以看到,AVIOContext是AVFormatContext的一个成员,叫作pb。

pb是提供数据的变量,既用于读(解码)也用于写(编码)。

(1)解码时

在解码时,pb提供解码的原始数据,一般在调用avio_alloc_context创建aviocontext时,指定read与seek函数(自定义的实现,提供读数据、跳转位置的功能),然后把创建的aviocontext(即pb)直接设置给AVFormatContext。比如这样:

pb = avio_alloc_context(readBuf, readBufLen, 0, this, myReadFunc, NULL, mySeekFunc);
mFormatCtx->pb = pb;

或者,在解码时,这样使用aviocontext:

mIOContext.read_packet = myReadFunc;
mIOContext.seek = mySeekFunc;
const int MAX_PRO_SIZE = 32*1024;
unsigned char* probuf = (unsigned char*)av_malloc(MAX_PRO_SIZE);
mIOContext.buffer = probuf;
mIOContext.buf_ptr = probuf;
mIOContext.buffer_size = MAX_PRO_SIZE;
mIOContext.buf_end = probuf + MAX_PRO_SIZE;
mIOContext.max_packet_size = MAX_PRO_SIZE;
formatContext->pb = &mIOContext;

其中,函数myReadFunc与mySeekFunc,按照结构体AVIOContext中的格式说明(参照头文件说明)来定义即可。

解码时,pb的设置,要在avformat_open_input调用前完成。

(2)编码时

在编码写文件时,pb提供写到文件的数据(编码后的数据,对应AVPacket),比如可以直接用avio_open2来打开pb:

if (!(mFormatContext->flags & AVFMT_NOFILE)) {
    err = avio_open2(&mFormatContext->pb, url, AVIO_FLAG_WRITE, &mFormatContext->interrupt_callback, NULL);
    // ...
}

写文件时,可以用av_write_frame来写入一个packet,也可以用avio_write往pb中写入数据。

编码写文件时,pb的设置,要在avformat_write_header调用前完成。

(3)AVIOContext的变量

这里只列表一部分:

buffer,AVIOContext缓存数据的buffer,起始地址。
buffer_size,buffer的大小。
buf_ptr,操作buffer的当前位置。
buf_end,数据的结束位置,有可能未到buffer的未端。
opaque,指向URLContext,提供读、写、seek等接口,可以让它为空,从而使用自定义的接口。
read_packet/write_packet/seek,读写与seek的接口,可以在avio_alloc_context时指定,从而自定义。

AVIOContext结构体在libavformat/avio.h中定义。

至此,FFmpeg常见的几个结构体就介绍完毕了。


总结一下,本文介绍了FFmpeg的常见结构体,包括AVFormatContext、AVIOContext、AVStream、AVCodecContext、AVCodec等,并且以调试的方式查看了结构体的一些变量值。

版权声明:本文为公众号“广州小程”原创文章,欢迎扫描博客左侧的二维码,关注有用的技能与通用能力。 https://blog.csdn.net/freejet2018/article/details/79974975

FFMPEG中最关键的结构体之间的关系

FFMPEG中结构体很多。最关键的结构体可以分成以下几类: a)        解协议 AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。U...
  • leixiaohua1020
  • leixiaohua1020
  • 2013-09-14 20:41:53
  • 37948

FFMPEG中常用的几种结构体

AVFormatContext                是一个贯穿始终的数据结构,很多函数都要用到它作为 参数。它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。下面看几个...
  • CSDN_wei
  • CSDN_wei
  • 2015-12-23 11:32:57
  • 576

FFMPEG的重要的结构体

1. FFMPEG中最关键的结构体之间的关系 FFMPEG中结构体很多。最关键的结构体可以分成以下几类: a)        解协议(http,rtsp,rtmp,mms) AVIOCon...
  • Runningzyx
  • Runningzyx
  • 2016-09-13 16:51:35
  • 1021

【ffmpeg】常用结构体集合

看大牛雷霄骅的博客,再次精简出学习ffmpeg的一些知识, 本篇简要整理一下ffmpeg中常用的几个结构体,以作备忘。 本人所用ffmpeg源码版本:ffmpeg-2.8.3,注意,版本不同,某些...
  • u012819339
  • u012819339
  • 2015-12-16 13:44:41
  • 2714

ffmpeg结构体的关系

基本概念:    编解码器、数据帧、媒体流和容器是数字媒体处理系统的四个基本概念。 首先需要统一术语:     容器/文件(Conainer/File):即特定格式的多媒体文件。     媒体...
  • jacklam200
  • jacklam200
  • 2012-11-13 23:34:40
  • 4126

ffmpeg常见结构体说明

AVFormatContext http://blog.csdn.net/ym012/article/details/6537788 AVStream http://blog.c...
  • zzdwuliang
  • zzdwuliang
  • 2013-12-12 23:58:26
  • 684

对于位域在结构体中的比特序

对于小端系统来说,用结构体表示位域,其排在前面的占字节的低端,排在后面的占字节序的低端。 例: 对应结构体为: typedef struct tagRTP_HEAD_S {     ...
  • Season_hangzhou
  • Season_hangzhou
  • 2014-03-03 12:20:19
  • 1072

ffmpeg常用结构体及函数

libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能;音视频的格式解析协议,为 libavcodec 分析码流提供独立的音频或视频码...
  • CheDanDeHuiYi
  • CheDanDeHuiYi
  • 2017-09-25 16:26:00
  • 176

FFMPEG之结构体解析 --- AVCodec

在FFMPEG中定义了一系列的结构体,计划写一些分析结构体的文章,在这里列一个列表: FFMPEG之结构体解析 --- AVFormatContext FFMPEG之结构体解析 --- AV...
  • rony2012
  • rony2012
  • 2017-07-09 18:35:21
  • 133

FFmpeg源代码简单分析:结构体成员管理系统-AVClass

打算写两篇文章记录FFmpeg中和AVOption有关的源代码。AVOption用于在FFmpeg中描述结构体中的成员变量。它最主要的作用可以概括为两个字:“赋值”。一个AVOption结构体包含了变...
  • leixiaohua1020
  • leixiaohua1020
  • 2015-03-15 19:21:03
  • 12223
收藏助手
不良信息举报
您举报文章:FFmpeg的常见结构体
举报原因:
原因补充:

(最多只允许输入30个字)