FFmpeg笔记(六)-- 编解码相关类、结构体

AVFormatContext

AVFormatContext是一个描述编解码格式上下文的数据结构。

struct AVInputFormat *iformat;//输入数据的封装格式
AVIOContext *pb;//输入数据的缓存
unsigned int nb_streams;//音频流+视频流的总数
AVStream **streams;//音视频流
char filename[1024];//文件名
int64_t duration;//时长(单位:微秒us,转换为秒需要除以1000000)
int bit_rate;//比特率(单位bps,转换为kbps需要除以1000)
AVDictionary *metadata;//元数据
AVStream

AVStream是存储每一个视频/音频流信息的结构体。
结构体参数来自:这里

int index; //在AVFormatContext中的索引,这个数字是自动生成的,可以通过这个数字从AVFormatContext::streams表中索引到该流。
int id;//流的标识,依赖于具体的容器格式。解码:由libavformat设置。编码:由用户设置,如果未设置则由libavformat替换。
AVCodecContext *codec;//指向该流对应的AVCodecContext结构,调用avformat_open_input时生成。
AVRational time_base;//这是表示帧时间戳的基本时间单位(以秒为单位)。该流中媒体数据的pts和dts都将以这个时间基准为粒度。
int64_t start_time;//流的起始时间,以流的时间基准为单位。如需设置,100%确保你设置它的值真的是第一帧的pts。
int64_t duration;//解码流的持续时间。如果源文件未指定持续时间,但指定了比特率,则将根据比特率和文件大小估计该值。
int64_t nb_frames; //此流中的帧数(如果已知)或0。
enum AVDiscard discard;//选择哪些数据包可以随意丢弃,不需要去demux。
AVRational sample_aspect_ratio;//样本长宽比(如果未知,则为0)。
AVDictionary *metadata;//元数据信息。
AVRational avg_frame_rate;//平均帧速率。解封装:可以在创建流时设置为libavformat,也可以在avformat_find_stream_info()中设置。
//封装:可以由调用者在avformat_write_header()之前设置。
AVPacket attached_pic;//附带的图片。比如说一些MP3,AAC音频文件附带的专辑封面。
int probe_packets;//编解码器用于probe的包的个数。
int codec_info_nb_frames;//在av_find_stream_info()期间已经解封装的帧数。
int request_probe;//流探测状态,1表示探测完成,0表示没有探测请求,rest 执行探测。
int skip_to_keyframe;//表示应丢弃直到下一个关键帧的所有内容。
int skip_samples;//在从下一个数据包解码的帧开始时要跳过的采样数。
int64_t start_skip_samples;//如果不是0,则应该从流的开始跳过的采样的数目。
int64_t first_discard_sample;//如果不是0,则应该从流中丢弃第一个音频样本。

int64_t pts_reorder_error[MAX_REORDER_DELAY+1];
uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1];//内部数据,从pts生成dts。

int64_t last_dts_for_order_check;
uint8_t dts_ordered;
uint8_t dts_misordered;//内部数据,用于分析dts和检测故障mpeg流。
AVRational display_aspect_ratio;//显示宽高比。
AVIOContext

AVIOContext是FFMPEG管理输入输出数据的结构体。

unsigned char *buffer;//缓存开始位置
int buffer_size;//缓存大小(默认32768)
unsigned char *buf_ptr;//当前指针读取到的位置
unsigned char *buf_end;//缓存结束的位置
void *opaque;//URLContext结构体
AVCodecContext

AVCodecContext是一个描述编解码器上下文的数据结构。
注释来自这里

enum AVMediaType codec_type:编解码器的类型(视频,音频...)
struct AVCodec  *codec:采用的解码器AVCodec(H.264,MPEG2...)
int bit_rate:平均比特率
uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
AVRational time_base:根据该参数,可以把PTS转化为实际的时间(单位为秒s)
int width, height:如果是视频的话,代表宽和高
int refs:运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)
int sample_rate:采样率(音频)
int channels:声道数(音频)
enum AVSampleFormat sample_fmt:采样格式
int profile:型(H.264里面就有,其他编码标准应该也有)
int level:级(和profile差不太多)
AVCodec

解码器。结构来自:这里

/**
 * AVCodec.
 * H.264的解码器对象: ff_h264_decoder
 */
typedef struct AVCodec 
{
    // 解码器名字
    const char *name;
    // 解码器完整名
    const char *long_name;
    // 媒体类型
    // AVMEDIA_TYPE_VIDEO
    // AVMEDIA_TYPE_AUDIO
    // AVMEDIA_TYPE_DATA
    enum AVMediaType type;
        // 解码器ID(AV_CODEC_ID_H264)
    enum AVCodecID id;
    // 能力集
    // H264: CODEC_CAP_DR1|CODEC_CAP_DELAY|CODEC_CAP_SLICE_THREADS|CODEC_CAP_FRAME_THREADS
    int capabilities;
    // 支持的帧率(V)
    const AVRational *supported_framerates;
    // 支持的像素格式(V)
    // AV_PIX_FMT_YUV420P
    // AV_PIX_FMT_RGB24
    const enum AVPixelFormat *pix_fmts;
    // 支持的采样率(A)
    const int *supported_samplerates;
    // 支持的采样格式(A)
    const enum AVSampleFormat *sample_fmts;
    // 支持的声道数(A)
    const uint64_t *channel_layouts;
    // (这里的3条感觉就是打补丁打出来的字段)
    // 由解码器支持低分辨率的最大值,不能直接访问,使用av_codec_get_max_lowres()
    uint8_t max_lowres;
    // AVClass针对私有上下文
    const AVClass *priv_class;
    // 公认的配置文件数组,如果未知则为NULL,数组由FF_PROFILE_UNKNOWN表示终止
    const AVProfile *profiles;
    // 私有数据总长度
    int priv_data_size;
    // 下一个链接对象
    struct AVCodec *next;
    
    // 假如被定义了, 那么当他们被创建时则被线程上下文调用。
    // 假如编解码器在调用init()时分配了可写表, 那么在这里重新分配.
    // priv_data将被设置为原件的副本
    int (*init_thread_copy)(AVCodecContext *);
    /**
     * 将必要的上下文变量从上一个线程复制到当前线程的上下文,(跨线程拷贝)。
     * 假如没有被定义, 下一个线程将自动启动; 否则, 编解码器必须调用call ff_thread_finish_setup().
     *
     * 目标和源很少指向相同的上下文, 在这种情况下应该跳过memcpy()的调用。
     */
    int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src);
    // 私有的指定的编解码器默认值.
    const AVCodecDefault *defaults;
    // 初始化编解码器的静态数据, 由avcodec_register()来调用.
    void (*init_static_data)(struct AVCodec *codec);
    // 根据AVCodecContext来初始化
    int (*init)(AVCodecContext *);
    int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, const struct AVSubtitle *sub);
    // 编码数据到AVPacket.
    // @参数 avctx: 编解码上下文
    // @参数 avpkt: 输出的AVPacket,(可能包含上层调用者提供的缓冲区)
    // @参数[in] frame: AVFrame包含了未加工的数据来编码
    // @参数[out] got_packet_ptr: 设置为0或1来表示一个非空的AVPacket返回值avpkt
    // @返回值 0表示成功,其他错误代码表示错误
    int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr);
    // 执行解码,从数据包AVPacket中进行解码转为outdata和outdata_size,提供AVCodecContext来定义编解码上下文信息
    int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt);
    // 关闭编解码器对象
    int (*close)(AVCodecContext *);
    // 编码+解码的API函数, 用来解耦packet/frame数据流(就是提供自己玩的接口,而不是打包操作). 
    // 这些API和avcodec_ prefixed的API差不多,除了下面这些:
    // - 如果编解码器关闭或者是错误类型,那么就不要使用。
    // - 在调用AVCodec->send_packet()之前,改变了AVPacket参数数据
    // - 假如AV_CODEC_CAP_DELAY没有被设置、漏包或者帧压根没有被发送
    // 发送帧
    int (*send_frame)(AVCodecContext *avctx, const AVFrame *frame);
    // 发送包
    int (*send_packet)(AVCodecContext *avctx, const AVPacket *avpkt);
    // 接受帧
    int (*receive_frame)(AVCodecContext *avctx, AVFrame *frame);
    // 接受包
    int (*receive_packet)(AVCodecContext *avctx, AVPacket *avpkt);
    // 刷新缓冲区
    void (*flush)(AVCodecContext *);
    // 内部的编解码能力.
    // 可以查看FF_CODEC_CAP_*系列宏,在头文件internal.h中
    int caps_internal;
 
}
AVPacket

AVPacket是FFmpeg中很重要的一个数据结构,它保存了解复用(demuxer)之后,解码(decode)之前的数据(仍然是压缩后的数据)和关于这些数据的一些附加的信息,如显示时间戳(pts),解码时间戳(dts),数据时长(duration),所在流媒体的索引(stream_index)等等。详情看这里

pts: (int64_t)显示时间,结合AVStream->time_base转换成时间戳
dts: (int64_t)解码时间,结合AVStream->time_base转换成时间戳
size: (int)data的大小
stream_index: (int)packet在stream的index位置
flags: (int)标示,结合AV_PKT_FLAG使用,其中最低为1表示该数据是一个关键帧。
#define AV_PKT_FLAG_KEY    0x0001 //关键帧
#define AV_PKT_FLAG_CORRUPT 0x0002 //损坏的数据
#define AV_PKT_FLAG_DISCARD  0x0004 /丢弃的数据
side_data_elems: (int)边缘数据元数个数
duration: (int64_t)数据的时长,以所属媒体流的时间基准为单位,未知则值为默认值0
pos: (int64_t )数据在流媒体中的位置,未知则值为默认值-1
convergence_duration:该字段已deprecated,不在使用
关于数据缓存,AVPacket本身只是个容器,不直接的包含数据,而是通过数据缓存的指针引用数据。
uint8_t *data:指向保存压缩数据的指针,这就是AVPacket的实际数据。
AVPacketSideData *side_data:容器提供的一些附加数据
AVBufferRef *buf:用来管理data指针引用的数据缓存,其使用在后面介绍。
AVFrame

AVFrame用来存储解码后的(或原始)音频或视频数据,位于avcodec.h文件中。
AVFrame必须由av_frame_alloc()分配内存,同时必须由av_frame_free()释放。
AVFrame分配内存后能够被多次用来存储不同的数据(例如:decoder解码后的帧)。av_frame_unref释放任何持帧的引用,并结构体还原到未被使用的状态。来自这里
一个AVPacket包含一个视频帧(AVFrame),也可以包含多个音频帧。
一帧音频的数据量 = channel数 * nb_samples样本数 * 每个样本占用的字节数。

uint8_t *   data [AV_NUM_DATA_POINTERS];//解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)。
int linesize[AV_NUM_DATA_POINTERS];//在视频中,表示图片一行数据的大小。
uint8_t **extended_data;//指向数据平面/通道。
int width, height;//一个视频帧的宽度和高度。
int nb_samples;//这个AVFrame中的每个音频声道的样本数。
int format;//表示解码后的数据类型或格式,-1表示未被设置或不能识别的类型。
int key_frame;//是否为关键帧,1->关键帧,0->非关键帧。
enum AVPictureType pict_type;//帧的类型。
AVRational sample_aspect_ratio;//视频帧的宽高比,0表示未知。
int64_t pts;//显示时间戳,表示该什么时候被显示。
int64_t pkt_dts;//从AVPacket中拷贝的值。
int coded_picture_number;//编码帧序号。
int display_picture_number;//显示帧需要。
void *opaque;//用户私有信息。
int repeat_pict;//解码时,每帧图片延迟的时间,extra_delay = repeat_pict / (2*fps)。
int interlaced_frame;//是否是隔行扫描
int sample_rate;//音频的采样率。
uint64_t channel_layout;//音频的布局方式。
enum AVColorRange color_range;
enum AVColorPrimaries color_primaries;
enum AVColorTransferCharacteristic color_trc;
enum AVColorSpace colorspace;
enum AVChromaLocation chroma_location;
int64_t best_effort_timestamp;//大多数情况下AVFrame的pts和best_effort_timestamp值是一样的
int64_t pkt_pos;//记录最后一个进入解码器的packet在输入文件中的位置偏移量。
int64_t pkt_duration;//对应packet的时长,单位是AVStream->time_base。
AVDictionary *metadata;
int decode_error_flags;
int channels;//音频通道个数
int pkt_size;//对应packet的大小。
int8_t *qscale_table;
int qstride;
int qscale_type;
AVBufferRef *qp_table_buf;
AVBufferRef *hw_frames_ctx;
AVBufferRef *opaque_ref;
AVSampleFormat

音频数据格式。名称尾有p表示分片,如音频有两个声道,分片左声道存linesize[0],右声道存linesize[1],不分片都存linesize[0],左右左右...的顺序依次存储。

enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16,         ///< signed 16 bits
    AV_SAMPLE_FMT_S32,         ///< signed 32 bits
    AV_SAMPLE_FMT_FLT,         ///< float
    AV_SAMPLE_FMT_DBL,         ///< double

    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP,        ///< float, planar
    AV_SAMPLE_FMT_DBLP,        ///< double, planar

    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

AVPictureType

视频帧类型。

enum AVPictureType {
    AV_PICTURE_TYPE_NONE = 0, ///< Undefined
    AV_PICTURE_TYPE_I,     ///< Intra
    AV_PICTURE_TYPE_P,     ///< Predicted
    AV_PICTURE_TYPE_B,     ///< Bi-dir predicted
    AV_PICTURE_TYPE_S,     ///< S(GMC)-VOP MPEG-4
    AV_PICTURE_TYPE_SI,    ///< Switching Intra
    AV_PICTURE_TYPE_SP,    ///< Switching Predicted
    AV_PICTURE_TYPE_BI,    ///< BI type
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345