• 音视频从入门到精通——FFmpeg结构体:AVPacket分析


    FFmpeg结构体 AVPacket分析

    FFmpeg结构体

    AVPacket保存的是解码前的数据,也就是压缩后的数据。
    该结构本身不直接包含数据,其有一个指向数据域的指针,FFmpeg中很多的数据结构都使用这种方法来管理数据。

    
    /**
     * This structure stores compressed data. It is typically exported by demuxers
     * and then passed as input to decoders, or received as output from encoders and
     * then passed to muxers.
     *
     * For video, it should typically contain one compressed frame. For audio it may
     * contain several compressed frames. Encoders are allowed to output empty
     * packets, with no compressed data, containing only side data
     * (e.g. to update some stream parameters at the end of encoding).
     *
     * The semantics of data ownership depends on the buf field.
     * If it is set, the packet data is dynamically allocated and is
     * valid indefinitely until a call to av_packet_unref() reduces the
     * reference count to 0.
     *
     * If the buf field is not set av_packet_ref() would make a copy instead
     * of increasing the reference count.
     *
     * The side data is always allocated with av_malloc(), copied by
     * av_packet_ref() and freed by av_packet_unref().
     *
     * sizeof(AVPacket) being a part of the public ABI is deprecated. once
     * av_init_packet() is removed, new packets will only be able to be allocated
     * with av_packet_alloc(), and new fields may be added to the end of the struct
     * with a minor bump.
     *
     * @see av_packet_alloc
     * @see av_packet_ref
     * @see av_packet_unref
     */
    typedef struct AVPacket {
        /**
         * A reference to the reference-counted buffer where the packet data is
         * stored.
         * May be NULL, then the packet data is not reference-counted.
         */
        AVBufferRef *buf;
        /**
         * Presentation timestamp in AVStream->time_base units; the time at which
         * the decompressed packet will be presented to the user.
         * Can be AV_NOPTS_VALUE if it is not stored in the file.
         * pts MUST be larger or equal to dts as presentation cannot happen before
         * decompression, unless one wants to view hex dumps. Some formats misuse
         * the terms dts and pts/cts to mean something different. Such timestamps
         * must be converted to true pts/dts before they are stored in AVPacket.
         */
        int64_t pts;
        /**
         * Decompression timestamp in AVStream->time_base units; the time at which
         * the packet is decompressed.
         * Can be AV_NOPTS_VALUE if it is not stored in the file.
         */
        int64_t dts;
        uint8_t *data;
        int   size;
        int   stream_index;
        /**
         * A combination of AV_PKT_FLAG values
         */
        int   flags;
        /**
         * Additional packet data that can be provided by the container.
         * Packet can contain several types of side information.
         */
        AVPacketSideData *side_data;
        int side_data_elems;
    
        /**
         * Duration of this packet in AVStream->time_base units, 0 if unknown.
         * Equals next_pts - this_pts in presentation order.
         */
        int64_t duration;
    
        int64_t pos;                            ///< byte position in stream, -1 if unknown
    
        /**
         * for some private data of the user
         */
        void *opaque;
    
        /**
         * AVBufferRef for free use by the API user. FFmpeg will never check the
         * contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when
         * the packet is unreferenced. av_packet_copy_props() calls create a new
         * reference with av_buffer_ref() for the target packet's opaque_ref field.
         *
         * This is unrelated to the opaque field, although it serves a similar
         * purpose.
         */
        AVBufferRef *opaque_ref;
    
        /**
         * Time base of the packet's timestamps.
         * In the future, this field may be set on packets output by encoders or
         * demuxers, but its value will be by default ignored on input to decoders
         * or muxers.
         */
        AVRational time_base;
    } AVPacket;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    部分字段说明

    typedef struct AVPacket {
    AVBufferRef *buf; //用来管理data指针引用的数据缓存
    int64_t pts; //显示时间,结合AVStream->time_base转换成时间戳
    int64_t dts; //解码时间,结合AVStream->time_base转换成时间戳
    uint8_t *data; //★指向保存压缩数据的指针,这就是AVPacket的实际数据
    int size; //data的大小
    int stream_index; //packet在stream的index位置
    int flags; //标示,结合AV_PKT_FLAG使用,其中最低为1表示该数据是一个关键帧。 
    /*
    * flags 可选:
    * #define AV_PKT_FLAG_KEY 0x0001 //关键帧
    * #define AV_PKT_FLAG_CORRUPT 0x0002 //损坏的数据
    * #define AV_PKT_FLAG_DISCARD 0x0004 /丢弃的数据 
    */
    AVPacketSideData *side_data; //容器提供的一些附加数据
    int side_data_elems; //边缘数据元数个数
    int64_t duration; //数据的时长,以所属媒体流的时间基准为单位,未知则值为默认值0 int64_t pos; //数据在流媒体中的位置,未知则值为默认值-1
        #if FF_API_CONVERGENCE_DURATION
        attribute_deprecated
        int64_t convergence_duration; //该字段已deprecated,不在使用 
      #endif
    } AVPacket;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    解码时AVPacket典型的使用场景为:

    AVPacket *packet = av_packet_alloc(); // 创建一个packet
    while(av_read_frame(pFormatCtx,packet))
    {
        if(packet->stream_index == audio_index)
        {
            ...
        }
        else if(packet->stream_index == video_index)
        {
            ...
        }
    
        av_packet_unref(packet); // 不要忘记减少引用技术
    }
    
    av_packet_free(packet);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    AVPacket 相关函数介绍

    av_read_frame:从媒体流中读取帧填充到Packet的数据缓存空间。如果Packet->buf为空,则Packet的数据缓存空间会在下次调用av_read_frame的时候失效。这也就是为何在FFmpeg3:播放音频中,从流中读取到Packet的时,在将该Packet插入队列时,要调用av_dup_avpacket重新复制一份缓存数据。

    av_packet_alloc: 创建一个AVPacket,将其字段设为默认值(data为空,没有数据缓存空间)

    av_packet_free: 释放使用av_packet_alloc创建的AVPacket,如果该Packet有引用计数(packet->buf不为空),则先调用av_packet_unref(&packet)。

    av_packet_clone: 其功能是 av_packet_alloc + av_packet_ref

    av_init_packet: 初始化packet的值为默认值,该函数不会影响data引用的数据缓存空间和size,需要单独处理。

    av_new_packet: av_init_packet的增强版,不但会初始化字段,还为data分配了存储空间。

    av_copy_packet: 复制一个新的packet,包括数据缓存。

    av_packet_from_data: 初始化一个引用计数的packet,并指定了其数据缓存。

    av_grow_packet: 增大Packet->data指向的数据缓存。

    av_shrink_packet :减小Packet->data指向的数据缓存。

    av_dup_packet: 是复制src->data引用的数据缓存,赋值给dst,也就是创建两个独立packet。说是3的版本册除了该方法,但4.1的源码里面又出现了该方法。

    已经废弃的两个函数:av_dup_packetav_free_packet
    av_free_packet: 释放packet,包括其data引用的数据缓存,现在可以使用av_packet_freeav_packet_unref代替。

    FFmpeg AVPacket和AVFrame区别

    在这里插入图片描述

    AVPacket:存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据)
    AVFrame:存储非压缩的数据(视频对应RGB/YUV像素数据,音频对应PCM采样数据)

    重要结构体之间的关系

    在这里插入图片描述
    FFmpeg 中结构体很多。最关键的结构体可以分成以下几类:

    解协议(http, rtsp, rtmp, mms)

    • AVIOContext ,URLProtocol ,URLContext 主要存储视音频使用的协议的类型以及状态。URLProtocol 存 储输入视音频使用的封装格式。每种协议都对应一个 URLProtocol 结构(注意:FFmpeg 中文件也被当 做一种协议 “file” )。

    解封装(flv, avi, rmvb, mp4)

    • AVFormatContext 主要存储视音频封装格式中包含的信息;AVInputFormat 存储输入视音频使用的封装格式。每种视音频封装格式都对应一个 AVInputFormat 结构。

    解码(h264, mpeg2, aac, mp3)

    • 每个 AVStream 存储一个视频/音频流的相关数据;每个 AVStream 对应一个 AVCodecContext ,存储该视 频/音频流使用解码方式的相关数据;每个 AVCodecContext 中对应一个 AVCodec ,包含该视频/音频对应 的解码器。每种解码器都对应一个 AVCodec 结构。

    存数据

    视频的话,每个结构一般是存一帧;音频可能有好几帧

    • 解码前数据:AVPacket
    • 解码后数据:AVFrame

    参考

    FFmpeg AVPacket 剖析以及使用
    FFmpeg 中AVPacket的使用
    ffmpeg中AVPacket与AVFrame中数据的传递与释放
    AVPacket 详细说明

    FFMPEG结构体分析:AVFrame
    FFMPEG结构体分析:AVFormatContext
    FFMPEG结构体分析:AVCodecContext
    FFMPEG结构体分析:AVIOContext
    FFMPEG结构体分析:AVCodec
    FFMPEG结构体分析:AVStream
    FFMPEG结构体分析:AVPacket

  • 相关阅读:
    计算机网络(六):应用层
    docker基于alpine基础镜像合集(java、python)集成chrome
    Java 哈希表
    Shiro
    基于Echarts实现可视化数据大屏电子商务公共服务平台大数据中心
    无Tomcat实现@Controller和@RequestMapping及HTTP服务
    es6模块+异步promise+async/await
    德国大陆博世 ars 548 4D 毫米波雷达 window 系统或者 Ubuntu 系统通讯以及数据解析和显示程序
    STM32系列(HAL库)——串口IAP
    [附源码]计算机毕业设计springboot美发店会员管理系统
  • 原文地址:https://blog.csdn.net/e891377/article/details/126707492