• ffmpeg源码笔记-AvFrame和AvPacket(四)


            在FFmpeg中,未压缩的图像和压缩的视频码流分别使用AVFrame结构和AVPacket结构保存; 针对视频编码器,其流程为从数据源获取图像格式的输入数据,保存为AVFrame对象并传入编码器,从编码器输出AVPacket结构;

    1. AVFrame结构体 

    1. typedef struct AVFrame {
    2. #define AV_NUM_DATA_POINTERS 8 //表示一个AVFrame结构最多保存8个图像分量;
    3. //待编码的图像像素数据保存在其中,各图像分量的像素数据保存在AVframe::data[0]~data[7]
    4. uint8_t *data[AV_NUM_DATA_POINTERS];
    5. int linesize[AV_NUM_DATA_POINTERS]; //每个分量的存储区的宽度,称为步长;
    6. /*指向数据平面/通道的指针。
    7. 对于视频,指向data[]
    8. 对于planar音频,每个通道有分离的数据指针,且linesize[0]包含每个通道buffer的大小;
    9. 对于packed音频,仅仅是一个数据指针,且linesize[0]包含所有通道buffer的总大小;
    10. */
    11. uint8_t **extended_data;
    12. //图像宽高
    13. int width, height;
    14. //本帧描述的音频采样数(每个频道)
    15. int nb_samples;
    16. //帧格式,常见的为AV_PIX_FMT_YUV420P
    17. int format;
    18. int key_frame; //当前帧的关键帧标识位;1表该帧为关键帧;0表非关键帧;
    19. enum AVPictureType pict_type;//当前帧的类型,0,1,2分别表示I帧,P帧,B帧;
    20. //采样视频帧的长宽比,如果未知/未指定,则为0/1;
    21. AVRational sample_aspect_ratio;
    22. int64_t pts;//当前帧的显示时间戳;
    23. #if FF_API_PKT_PTS
    24. //PTS复制自AVPacket,被解码产生此帧。
    25. int64_t pkt_pts;
    26. #endif
    27. //dts从触发返回帧的AVPacket中复制
    28. //这也是由AVPacket计算出的AVFrame的显示时间。 无PTS值的DTS值
    29. int64_t pkt_dts;
    30. //按位流顺序排列的图片编号
    31. int coded_picture_number;
    32. //图片编号按显示顺序排列
    33. int display_picture_number;
    34. //质量
    35. int quality;
    36. void *opaque; //用户私有数据
    37. //当解码时,这表示图像必须延迟多少
    38. int repeat_pict;
    39. //图片的内容是交错的
    40. int interlaced_frame;
    41. //如果内容是交错的,则首先显示顶部字段。
    42. int top_field_first;
    43. //告诉用户应用程序调色板已从上一帧更改。
    44. int palette_has_changed;
    45. int64_t reordered_opaque;
    46. //音频数据采样速率
    47. int sample_rate;
    48. //音频数据的通道布局。
    49. uint64_t channel_layout;
    50. //AVBuffer引用支持这个帧的数据
    51. AVBufferRef *buf[AV_NUM_DATA_POINTERS];
    52. AVBufferRef **extended_buf;
    53. //扩展buf中的元素数目
    54. int nb_extended_buf;
    55. AVFrameSideData **side_data;
    56. int nb_side_data;
    57. //帧标志
    58. int flags;
    59. enum AVColorRange color_range;
    60. enum AVColorPrimaries color_primaries;
    61. enum AVColorTransferCharacteristic color_trc;
    62. enum AVColorSpace colorspace;
    63. enum AVChromaLocation chroma_location;
    64. //帧时间戳估计使用各种启发式
    65. int64_t best_effort_timestamp;
    66. //从输入到解码器的最后一个AVPacket重新排序pos
    67. int64_t pkt_pos;
    68. //对应报文的持续时间,以AVStream->time_base units表示,如果未知则为0
    69. int64_t pkt_duration;
    70. AVDictionary *metadata;
    71. //音频通道数,仅用于音频
    72. int channels;
    73. //包含压缩帧的相应数据包的大小
    74. int pkt_size;
    75. AVBufferRef *hw_frames_ctx;
    76. AVBufferRef *opaque_ref;
    77. size_t crop_top;
    78. size_t crop_bottom;
    79. size_t crop_left;
    80. size_t crop_right;
    81. AVBufferRef *private_ref;
    82. } AVFrame;

            在AVFrame结构中,它所包含的最重要的结构即数据的缓存区;待编码的数据的像素数据保存在AVFrame结构的data指针所保存的内存区中;

            一个AVFrame结构最多可以保存8个图像分量,各图像分量的像素数据保存在AVFrame::data[0]

    ~AVFrame::data[7]所指向的内存区中;

    1.1 创建AVFrame结构的实例并初始化

    AVFrame *av_frame_alloc(void);

    注:仅仅创建AVFrame结构的实例,以及初始化内部各个字段的值,并没有分配用于存储其内部图像的内存空间;

    1.2 给AVFrame结构体中的音视频数据分配内存空间

    int av_frame_get_buffer(AVFrame *frame, int align);

    作用:实际分配内存空间;

    参数1:AVFrame指针;

    参数2:对齐方式,<=0表示以32字节对齐;否则以align对齐;

     sample示例:

    1. //创建AVFrame结构的实例并初始化;
    2. //仅仅创建AVFrame的实例,并没有分配用于存储其内部图像的内存空间;
    3. frame = av_frame_alloc();
    4. if (!frame) {
    5. fprintf(stderr, "Could not allocate video frame\n");
    6. exit(1);
    7. }
    8. frame->format = c->pix_fmt;
    9. frame->width = c->width;
    10. frame->height = c->height;
    11. //给AVFrame结构中的音视频数据分配内存空间;
    12. ret = av_frame_get_buffer(frame, 0);
    13. if (ret < 0) {
    14. fprintf(stderr, "Could not allocate the video frame data\n");
    15. exit(1);
    16. }

    1.3 将保存了图像数据的AVFrame结构传入编码器

    int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);

    参数1:当前编码器的上下文结构l;

    参数2:待编码的图像结构;当该参数为NULL时表示编码结束,此时应该刷新编码器缓存的码流;

    返回值:0:正常执行; 负数表错误码;

    AVERROR(EAGAIN):输入缓存已满,应该调用avcodec_receive_packet获取输出数据后在尝试输入;

    AVERROR_EOF:编码器已收到刷新指令,不再接收的图像输入;

    VERROR(EINVAL):编码器状态错误;

    VERROR(ENOMEM):内存空间不足;

    1.4 释放分配的图像帧结构

    void av_frame_free(AVFrame **frame)

    2. AVPacket结构体

    1. typedef struct AVPacket {
    2. AVBufferRef *buf;
    3. int64_t pts;//当前packet的显示时间戳;必须大于等于dts
    4. int64_t dts;//当前packet的解码时间戳,以AVStream的time_base为单位;
    5. uint8_t *data;//码流数据保存在data指针指向的内存;
    6. int size;//数据长度为size字节;可通过data和size读取编码后的码流;
    7. int stream_index;//当前packet所从属的stream序号;
    8. int flags;
    9. AVPacketSideData *side_data;
    10. int side_data_elems;
    11. //当前packet的显示时长,即按照顺序显示下一帧pts与当前pts的差值;
    12. int64_t duration;
    13. //当前packet在数据流中的二进制位置; -1表示未知;
    14. int64_t pos;
    15. } AVPacket;

    2.1 创建AVPacket结构的实例并初始化

    AVPacket *av_packet_alloc(void);

    2.2 依照一个已存在的packet创建新的packet,新packet是对原packet的引用;

    AVPacket *av_packet_clone(const AVPacket *src);

    2.3 释放一个packet,若该packet存在引用计数,则其引用计数减1

    void av_packet_free(AVPacket **pkt);

     2.4 按照指定大小分配一个packet的存储空间,并初始化该packet

    int av_new_packet(AVPacket *pkt, int size);

    2.5 根据传入的packet创建新的引用packet

    int av_packet_ref(AVPacket *dst, const AVPacket *src);

    2.6 回收该packet

    void av_packet_unref(AVPacket *pkt);

    2.7 从编码器中获取输出的码流,并保存在传入的AVPacket结构中;

     int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);

    参数1:当前编码器上下文结构;

    参数2:输出的码流包结构,包含编码器输出的视频码流;

    返回值:0表正常,负数为错误码;

    AVERROR(EAGAIN):编码器尚未完成对新一帧的编码,应继续通过函数avcodec_send_frame传入后续图像;

    AVERROR_EOF:编码器已经完成输出内部缓存的码流,编码完成;

    VERROR(EINVAL):编码器状态错误;

  • 相关阅读:
    【Java】如何判断一个空对象
    计算机网络八股文复习
    AQS很难,面试不会?看我一篇文章吊打面试官
    Linux 下 C语言版本的线程池
    从 internal 修饰符一探 kotlin 的可见性控制
    自动化运维中间件架构概况
    企业在申请专利时如何明确要申请专利的技术点
    深度神经网络和人工神经网络区别
    给力心理平台项目开发介绍
    横板格斗类游戏实战:定时器Timer模块设计
  • 原文地址:https://blog.csdn.net/qq_39048131/article/details/125773892