• 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;
  • 相关阅读:
    什么是仿射变换
    转:vim比较好的学习资料
    学好C++的五十条建议
    转:美国设置地理系的大学名单
    转:windows下安装emacs
    我学习GNU/Linux: 如何上手
    Linux学习路线图 (转载)
    unix编程学习路线图(转)
    转:C++资源之不完全导引
    Why Linux Programming?
  • 原文地址:https://www.cnblogs.com/lifexy/p/13256397.html
Copyright © 2020-2023  润新知