zoukankan      html  css  js  c++  java
  • 4.FFMPEG-AVFrame

    在ffmpeg中,解码前的数据结构体为AVPacket(参考:3.AVPacket使用),而解码后的数据为AVFrame(视频的YUV, RGB, 音频的PCM)

     

    1.AVFrame介绍

    AVFrame必须使用av_frame_alloc()来分配。注意,这只是分配AVFrame本身,缓冲区的数据必须通过其他途径被管理.
    因为AVFrame通常只分配一次,然后多次复用来保存不同类型的数据,复用的时候需要调用av_frame_unref()将其重置到它前面的原始清洁状态.
    释放的时候必须用av_frame_free()释放。

    2.AVFrame结构体

    AVFrame结构体中有很多成员,常见的成员如下所示,注释已替换:

    typedef struct AVFrame {
    #define AV_NUM_DATA_POINTERS 8
    
    uint8_t *data[AV_NUM_DATA_POINTERS];
    //存储原始帧数据(视频的YUV, RGB, 音频的PCM),数组的每一个元素是一个指针,指向了AVBufferRef *buf中的data
    //对于packet格式,都存在data[0]中,比如yuv,data[0]中就存的是yuvyuvyuv...,pcm则是lrlrlrlr...
    //对于planar格式,则是分开存储,比如yuv,data[0]存y,data[1]存u,data[2]存v,pcm则是data[0]存L,data[1]存R
    
    
    int linesize[AV_NUM_DATA_POINTERS];
    //对于视频,linesize是每个图像的宽大小(字节数)。注意有对齐要求(16或32对齐)
    //对于音频,则是每个data[]里的字节大小,并且每个通道(一般就两通道:L和R)的字节数相同
    
    
    uint8_t **extended_data;
    //extended_data:*extended_data始终等于data[0]里的成员。
    //之所以取名为extended_data,是因为data[]最大只能8个通道.
    //比如planar格式的pcm的通道数超过了8个,那么就只能使用extended_data来获取数据.
    
    
    
    int width, height;
    //视频帧的尺寸(以像素为单位)
    //用户可以通过if (frame->width > 0 && frame->height > 0)来判断是否为视频流
    
    int nb_samples;
    //音频帧的通道数
    
    
    int format;
    //帧的格式,如果未知或未设置为-1
    //对于视频帧,参考AVPixelFormat枚举值,比如:AV_PIX_FMT_YUV420P
    //对于音频帧,参考AVSampleFormat枚举值,比如:AV_SAMPLE_FMT_U8
    
    
    int key_frame;
    //是否为一幅完整的画面,关键帧(I帧)的标识
    //1->关键帧,0->非关键帧
    
    enum AVPictureType pict_type;
    //视频帧类型(I、B、P等),比如:AV_PICTURE_TYPE_I(I帧)
    //I帧:一幅完整的画面
    //B帧:参考前面和后面两帧的数据加上本帧的变化而得出的本帧数据
    //P帧:参考前面而得出的本帧数据.
    //如果I帧不完整,那么整个GOP(Group of Picture)都是花屏的.
    
    /**
    * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
    */
    AVRational sample_aspect_ratio;
    //像素的宽高比,通过av_q2d()来获取值,如果未知/未指定,为0/1。
    
    /**
    * Presentation timestamp in time_base units (time when frame should be shown to user).
    */
    int64_t pts;
    //显示时间戳,表示当前为第几帧,如果要换算为时分秒,则需要AVStream的time_base时基来一起换算
    //比如:
    //int timeVal=av_q2d(pFormatCtx->streams[videoindex]->time_base) * pFrame->pts*100;    
    //int hour = timeVal/360000;
    //int minute = timeVal%360000/6000;
    //int second = timeVal%6000/100;
    //int msec = timeVal%100*10;
    
    
    #if FF_API_PKT_PTS
    /**
    * PTS copied from the AVPacket that was decoded to produce this frame.
    * @deprecated use the pts field instead
    */
    int64_t pkt_pts;    //使用pts字段代替(pts=pkt_pts)
    #endif
    
    
    int64_t pkt_dts;
    //pkt_dts:解码时间戳,等于AVPacket的dts,如果AVPacket只有dts而未设置pts,此值也是此frame的pts
    
    
    int coded_picture_number;
    //编码顺序的图像
    
    int display_picture_number;
    //播放顺序的图像
    
    /**
    * quality (between 1 (good) and FF_LAMBDA_MAX (bad))
    */
    int quality;
    //视频质量,值越小越好
    
    
    int repeat_pict;
    //当解码时,这表示图片必须延迟多少.extra_delay = repeat_pict / (2*fps)
    
    int interlaced_frame;
    //图像逐行/隔行模式标识。
    
    int top_field_first;
    //如果内容是隔行模式扫描,则首先显示顶部字段。
    
    
    int palette_has_changed;
    //用来告诉应用程序,调色板已从前一帧更改。
    
    
    int64_t reordered_opaque;
    //重新排序的不透明64位(通常是整数或双精度浮点PTS,但可以是任何东西)。
    
    int sample_rate;
    //音频数据的采样率。
    
    uint64_t channel_layout;
    //音频数据的通道布局,参考channel_layout.h
    //比如AV_CH_FRONT_LEFT:表示前左声道
    
    /**
    * AVBuffer references backing the data for this frame. If all elements of
    * this array are NULL, then this frame is not reference counted. This array
    * must be filled contiguously -- if buf[i] is non-NULL then buf[j] must
    * also be non-NULL for all j < i.
    *
    * There may be at most one AVBuffer per data plane, so for video this array
    * always contains all the references. For planar audio with more than
    * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in
    * this array. Then the extra AVBufferRef pointers are stored in the
    * extended_buf array.
    */
    AVBufferRef *buf[AV_NUM_DATA_POINTERS];
    //通过引用计数,使该AVBufferRef来间接使用AVBuffer缓冲区,也就是data[]指向的原始数据.
    //用户不应直接使用data成员,应通过buf成员间接使用data成员
    //如果buf[]的所有元素都为NULL,则此帧不会被引用计数。必须连续填充buf[] - 如果buf[i]为非NULL,则对于所有j<i,buf[j]也必须为非NULL
    
    AVBufferRef **extended_buf;
    int nb_extended_buf;
    //和extended_data类似,因为buf最多存储8通道.
    //extended_buf和AVFrame.extended_data唯一不同在于:extended_data包含所有指向各plane的指针,而extended_buf只包含buf中装不下的指针。
    AVFrameSideData **side_data;
    int nb_side_data;
    //边缘数据和数目
    
    /**
    * @defgroup lavu_frame_flags AV_FRAME_FLAGS
    * @ingroup lavu_frame
    * Flags describing additional frame properties.
    *
    * @{
    */
    
    
    #define AV_FRAME_FLAG_CORRUPT (1 << 0)
    //标记需要解码但不应该输出的帧的标志。帧数据可能被损坏,例如由于解码错误
    
    #define AV_FRAME_FLAG_DISCARD (1 << 2)
    //标记需要解码但不应该输出的帧的标志。
    
    int flags;    //编解码失败后,用户可以通过该flag查看是否为AV_FRAME_FLAG_CORRUPT或者AV_FRAME_FLAG_DISCARD
    
    
    enum AVColorRange color_range;    //图像的编码格式(MPEG/JPEG),解码时,由库设置,编码时,由用户来设置
    
    enum AVColorPrimaries color_primaries;    //图像源初选的色度坐标
    
    enum AVColorTransferCharacteristic color_trc;    //图像颜色传输特性
    
    /**
    * YUV colorspace type.
    * - encoding: Set by user
    * - decoding: Set by libavcodec
    */
    enum AVColorSpace colorspace;    
    //图像彩色空间类型,解码时,由库设置,编码时,由用户来设置
    //比如等于AVCOL_SPC_RGB时,那么color_trc等于AVCOL_TRC_IEC61966_2_1
    
    enum AVChromaLocation chroma_location;
    //储存的颜色色度样品的位置
    
    /**
    * reordered pos from the last AVPacket that has been input into the decoder
    * - encoding: unused
    * - decoding: Read by user.
    */
    int64_t pkt_pos;
    //标记最后一个解码的packet在输入文件中的位置偏移量。
    
    
    int64_t pkt_duration;
    //该帧的持续时间,需要通过AVStream的time_base时基来换算
    
    
    /**
    * metadata.
    * - encoding: Set by user.
    * - decoding: Set by libavcodec.
    */
    AVDictionary *metadata;
    
    
    int decode_error_flags; //解码帧的错误标志
    #define FF_DECODE_ERROR_INVALID_BITSTREAM 1
    #define FF_DECODE_ERROR_MISSING_REFERENCE 2
    #define FF_DECODE_ERROR_CONCEALMENT_ACTIVE 4
    #define FF_DECODE_ERROR_DECODE_SLICES 8
    
    
    int channels;
    //音频通道数量,仅用于音频
    //用户可以通过 if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0))来判断该frame是否为音频
    
    int pkt_size;    
    //压缩帧的相应数据包的大小。
    
    
    size_t crop_top;
    size_t crop_bottom;
    size_t crop_left;
    size_t crop_right;
    //用于裁剪视频帧图像用的。四个值分别为从frame的上/下/左/右边界裁切的像素数。
    
    //...
    }AVFrame;
  • 相关阅读:
    Sqlserver 实际开发中表变量的用法
    Python Day 20 面向对象 (面向对象的组合用法,面向对象的三大特性
    Python Day 19 面向对象(初识面向对象)
    Python Day 18 常用模块(模块和包)
    Python Day 17 常用模块(常用模块一 时间模块,random模块,os模块,sys模块,序列化模块)
    Python Day 15 函数(递归函数、二分查找算法)
    Python Day 14 函数(内置函数,匿名函数(lambda表达式))
    Python Day 13 函数(迭代器,生成器,列表推导式,生成器表达式)
    Python Day 11 + Python Day 12 函数(函数名的应用,闭包,装饰器)
    Python Day 10 函数(名称空间,作用域,作用域链,加载顺序等; 函数的嵌套 global,nonlocal)
  • 原文地址:https://www.cnblogs.com/lifexy/p/13256397.html
Copyright © 2011-2022 走看看