FFmpeg存放压缩后的音视频数据的结构体:AVPacket简介,结构体,函数
如下图的解码流程,AVPacket中的位置
FFmpeg源码中通过AVPacket存储压缩后的音视频数据。它通常由解复用器(demuxers)输出,然后作为输入传递给解码器。
或者从编码器作为输出接收,然后传递给多路复用器(muxers)。
对于视频,它通常包含一个压缩帧;对于音频,它可能包含几个压缩帧。编码器允许输出不包含压缩音视频数据、只包含side data(边数据:例如,在编码结束时更新一些流参数)的空的数据包( empty packets)。
AVPacket 结构体 所在的文件名 libavcodec/packet.h
/** AVPacket public API** This file is part of FFmpeg.** FFmpeg is free software; you can redistribute it and/or* modify it under the terms of the GNU Lesser General Public* License as published by the Free Software Foundation; either* version 2.1 of the License, or (at your option) any later version.** FFmpeg is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU* Lesser General Public License for more details.** You should have received a copy of the GNU Lesser General Public* License along with FFmpeg; if not, write to the Free Software* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/#ifndef AVCODEC_PACKET_H
#define AVCODEC_PACKET_H#include <stddef.h>
#include <stdint.h>#include "libavutil/attributes.h"
#include "libavutil/buffer.h"
#include "libavutil/dict.h"
#include "libavutil/rational.h"
#include "libavutil/version.h"#include "libavcodec/version_major.h"/*** @defgroup lavc_packet AVPacket** Types and functions for working with AVPacket.* @{*/
enum AVPacketSideDataType {/*** An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE* bytes worth of palette. This side data signals that a new palette is* present.*/AV_PKT_DATA_PALETTE,/*** The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format* that the extradata buffer was changed and the receiving side should* act upon it appropriately. The new extradata is embedded in the side* data buffer and should be immediately used for processing the current* frame or packet.*/AV_PKT_DATA_NEW_EXTRADATA,/*** An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows:* @code* u32le param_flags* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT)* s32le channel_count* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT)* u64le channel_layout* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE)* s32le sample_rate* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS)* s32le width* s32le height* @endcode*/AV_PKT_DATA_PARAM_CHANGE,/*** An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of* structures with info about macroblocks relevant to splitting the* packet into smaller packets on macroblock edges (e.g. as for RFC 2190).* That is, it does not necessarily contain info about all macroblocks,* as long as the distance between macroblocks in the info is smaller* than the target payload size.* Each MB info structure is 12 bytes, and is laid out as follows:* @code* u32le bit offset from the start of the packet* u8 current quantizer at the start of the macroblock* u8 GOB number* u16le macroblock address within the GOB* u8 horizontal MV predictor* u8 vertical MV predictor* u8 horizontal MV predictor for block number 3* u8 vertical MV predictor for block number 3* @endcode*/AV_PKT_DATA_H263_MB_INFO,/*** This side data should be associated with an audio stream and contains* ReplayGain information in form of the AVReplayGain struct.*/AV_PKT_DATA_REPLAYGAIN,/*** This side data contains a 3x3 transformation matrix describing an affine* transformation that needs to be applied to the decoded video frames for* correct presentation.** See libavutil/display.h for a detailed description of the data.*/AV_PKT_DATA_DISPLAYMATRIX,/*** This side data should be associated with a video stream and contains* Stereoscopic 3D information in form of the AVStereo3D struct.*/AV_PKT_DATA_STEREO3D,/*** This side data should be associated with an audio stream and corresponds* to enum AVAudioServiceType.*/AV_PKT_DATA_AUDIO_SERVICE_TYPE,/*** This side data contains quality related information from the encoder.* @code* u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad).* u8 picture type* u8 error count* u16 reserved* u64le[error count] sum of squared differences between encoder in and output* @endcode*/AV_PKT_DATA_QUALITY_STATS,/*** This side data contains an integer value representing the stream index* of a "fallback" track. A fallback track indicates an alternate* track to use when the current track can not be decoded for some reason.* e.g. no decoder available for codec.*/AV_PKT_DATA_FALLBACK_TRACK,/*** This side data corresponds to the AVCPBProperties struct.*/AV_PKT_DATA_CPB_PROPERTIES,/*** Recommmends skipping the specified number of samples* @code* u32le number of samples to skip from start of this packet* u32le number of samples to skip from end of this packet* u8 reason for start skip* u8 reason for end skip (0=padding silence, 1=convergence)* @endcode*/AV_PKT_DATA_SKIP_SAMPLES,/*** An AV_PKT_DATA_JP_DUALMONO side data packet indicates that* the packet may contain "dual mono" audio specific to Japanese DTV* and if it is true, recommends only the selected channel to be used.* @code* u8 selected channels (0=main/left, 1=sub/right, 2=both)* @endcode*/AV_PKT_DATA_JP_DUALMONO,/*** A list of zero terminated key/value strings. There is no end marker for* the list, so it is required to rely on the side data size to stop.*/AV_PKT_DATA_STRINGS_METADATA,/*** Subtitle event position* @code* u32le x1* u32le y1* u32le x2* u32le y2* @endcode*/AV_PKT_DATA_SUBTITLE_POSITION,/*** Data found in BlockAdditional element of matroska container. There is* no end marker for the data, so it is required to rely on the side data* size to recognize the end. 8 byte id (as found in BlockAddId) followed* by data.*/AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,/*** The optional first identifier line of a WebVTT cue.*/AV_PKT_DATA_WEBVTT_IDENTIFIER,/*** The optional settings (rendering instructions) that immediately* follow the timestamp specifier of a WebVTT cue.*/AV_PKT_DATA_WEBVTT_SETTINGS,/*** A list of zero terminated key/value strings. There is no end marker for* the list, so it is required to rely on the side data size to stop. This* side data includes updated metadata which appeared in the stream.*/AV_PKT_DATA_METADATA_UPDATE,/*** MPEGTS stream ID as uint8_t, this is required to pass the stream ID* information from the demuxer to the corresponding muxer.*/AV_PKT_DATA_MPEGTS_STREAM_ID,/*** Mastering display metadata (based on SMPTE-2086:2014). This metadata* should be associated with a video stream and contains data in the form* of the AVMasteringDisplayMetadata struct.*/AV_PKT_DATA_MASTERING_DISPLAY_METADATA,/*** This side data should be associated with a video stream and corresponds* to the AVSphericalMapping structure.*/AV_PKT_DATA_SPHERICAL,/*** Content light level (based on CTA-861.3). This metadata should be* associated with a video stream and contains data in the form of the* AVContentLightMetadata struct.*/AV_PKT_DATA_CONTENT_LIGHT_LEVEL,/*** ATSC A53 Part 4 Closed Captions. This metadata should be associated with* a video stream. A53 CC bitstream is stored as uint8_t in AVPacketSideData.data.* The number of bytes of CC data is AVPacketSideData.size.*/AV_PKT_DATA_A53_CC,/*** This side data is encryption initialization data.* The format is not part of ABI, use av_encryption_init_info_* methods to* access.*/AV_PKT_DATA_ENCRYPTION_INIT_INFO,/*** This side data contains encryption info for how to decrypt the packet.* The format is not part of ABI, use av_encryption_info_* methods to access.*/AV_PKT_DATA_ENCRYPTION_INFO,/*** Active Format Description data consisting of a single byte as specified* in ETSI TS 101 154 using AVActiveFormatDescription enum.*/AV_PKT_DATA_AFD,/*** Producer Reference Time data corresponding to the AVProducerReferenceTime struct,* usually exported by some encoders (on demand through the prft flag set in the* AVCodecContext export_side_data field).*/AV_PKT_DATA_PRFT,/*** ICC profile data consisting of an opaque octet buffer following the* format described by ISO 15076-1.*/AV_PKT_DATA_ICC_PROFILE,/*** DOVI configuration* ref:* dolby-vision-bitstreams-within-the-iso-base-media-file-format-v2.1.2, section 2.2* dolby-vision-bitstreams-in-mpeg-2-transport-stream-multiplex-v1.2, section 3.3* Tags are stored in struct AVDOVIDecoderConfigurationRecord.*/AV_PKT_DATA_DOVI_CONF,/*** Timecode which conforms to SMPTE ST 12-1:2014. The data is an array of 4 uint32_t* where the first uint32_t describes how many (1-3) of the other timecodes are used.* The timecode format is described in the documentation of av_timecode_get_smpte_from_framenum()* function in libavutil/timecode.h.*/AV_PKT_DATA_S12M_TIMECODE,/*** HDR10+ dynamic metadata associated with a video frame. The metadata is in* the form of the AVDynamicHDRPlus struct and contains* information for color volume transform - application 4 of* SMPTE 2094-40:2016 standard.*/AV_PKT_DATA_DYNAMIC_HDR10_PLUS,/*** The number of side data types.* This is not part of the public API/ABI in the sense that it may* change when new side data types are added.* This must stay the last enum value.* If its value becomes huge, some code using it* needs to be updated as it assumes it to be smaller than other limits.*/AV_PKT_DATA_NB
};#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATEDtypedef struct AVPacketSideData {uint8_t *data;size_t size;enum AVPacketSideDataType type;
} AVPacketSideData;/*** 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;#if FF_API_INIT_PACKET
attribute_deprecated
typedef struct AVPacketList {AVPacket pkt;struct AVPacketList *next;
} AVPacketList;
#endif#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe
#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
/*** Flag is used to discard packets which are required to maintain valid* decoder state but are not required for output and should be dropped* after decoding.**/
#define AV_PKT_FLAG_DISCARD 0x0004
/*** The packet comes from a trusted source.** Otherwise-unsafe constructs such as arbitrary pointers to data* outside the packet may be followed.*/
#define AV_PKT_FLAG_TRUSTED 0x0008
/*** Flag is used to indicate packets that contain frames that can* be discarded by the decoder. I.e. Non-reference frames.*/
#define AV_PKT_FLAG_DISPOSABLE 0x0010enum AVSideDataParamChangeFlags {
#if FF_API_OLD_CHANNEL_LAYOUT/*** @deprecated those are not used by any decoder*/AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001,AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT = 0x0002,
#endifAV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004,AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008,
};/*** Allocate an AVPacket and set its fields to default values. The resulting* struct must be freed using av_packet_free().** @return An AVPacket filled with default values or NULL on failure.** @note this only allocates the AVPacket itself, not the data buffers. Those* must be allocated through other means such as av_new_packet.** @see av_new_packet*/
AVPacket *av_packet_alloc(void);/*** Create a new packet that references the same data as src.** This is a shortcut for av_packet_alloc()+av_packet_ref().** @return newly created AVPacket on success, NULL on error.** @see av_packet_alloc* @see av_packet_ref*/
AVPacket *av_packet_clone(const AVPacket *src);/*** Free the packet, if the packet is reference counted, it will be* unreferenced first.** @param pkt packet to be freed. The pointer will be set to NULL.* @note passing NULL is a no-op.*/
void av_packet_free(AVPacket **pkt);#if FF_API_INIT_PACKET
/*** Initialize optional fields of a packet with default values.** Note, this does not touch the data and size members, which have to be* initialized separately.** @param pkt packet** @see av_packet_alloc* @see av_packet_unref** @deprecated This function is deprecated. Once it's removed,sizeof(AVPacket) will not be a part of the ABI anymore.*/
attribute_deprecated
void av_init_packet(AVPacket *pkt);
#endif/*** Allocate the payload of a packet and initialize its fields with* default values.** @param pkt packet* @param size wanted payload size* @return 0 if OK, AVERROR_xxx otherwise*/
int av_new_packet(AVPacket *pkt, int size);/*** Reduce packet size, correctly zeroing padding** @param pkt packet* @param size new size*/
void av_shrink_packet(AVPacket *pkt, int size);/*** Increase packet size, correctly zeroing padding** @param pkt packet* @param grow_by number of bytes by which to increase the size of the packet*/
int av_grow_packet(AVPacket *pkt, int grow_by);/*** Initialize a reference-counted packet from av_malloc()ed data.** @param pkt packet to be initialized. This function will set the data, size,* and buf fields, all others are left untouched.* @param data Data allocated by av_malloc() to be used as packet data. If this* function returns successfully, the data is owned by the underlying AVBuffer.* The caller may not access the data through other means.* @param size size of data in bytes, without the padding. I.e. the full buffer* size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE.** @return 0 on success, a negative AVERROR on error*/
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);/*** Allocate new information of a packet.** @param pkt packet* @param type side information type* @param size side information size* @return pointer to fresh allocated data or NULL otherwise*/
uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,size_t size);/*** Wrap an existing array as a packet side data.** @param pkt packet* @param type side information type* @param data the side data array. It must be allocated with the av_malloc()* family of functions. The ownership of the data is transferred to* pkt.* @param size side information size* @return a non-negative number on success, a negative AVERROR code on* failure. On failure, the packet is unchanged and the data remains* owned by the caller.*/
int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,uint8_t *data, size_t size);/*** Shrink the already allocated side data buffer** @param pkt packet* @param type side information type* @param size new side information size* @return 0 on success, < 0 on failure*/
int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,size_t size);/*** Get side information from packet.** @param pkt packet* @param type desired side information type* @param size If supplied, *size will be set to the size of the side data* or to zero if the desired side data is not present.* @return pointer to data if present or NULL otherwise*/
uint8_t* av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type,size_t *size);const char *av_packet_side_data_name(enum AVPacketSideDataType type);/*** Pack a dictionary for use in side_data.** @param dict The dictionary to pack.* @param size pointer to store the size of the returned data* @return pointer to data if successful, NULL otherwise*/
uint8_t *av_packet_pack_dictionary(AVDictionary *dict, size_t *size);
/*** Unpack a dictionary from side_data.** @param data data from side_data* @param size size of the data* @param dict the metadata storage dictionary* @return 0 on success, < 0 on failure*/
int av_packet_unpack_dictionary(const uint8_t *data, size_t size,AVDictionary **dict);/*** Convenience function to free all the side data stored.* All the other fields stay untouched.** @param pkt packet*/
void av_packet_free_side_data(AVPacket *pkt);/*** Setup a new reference to the data described by a given packet** If src is reference-counted, setup dst as a new reference to the* buffer in src. Otherwise allocate a new buffer in dst and copy the* data from src into it.** All the other fields are copied from src.** @see av_packet_unref** @param dst Destination packet. Will be completely overwritten.* @param src Source packet** @return 0 on success, a negative AVERROR on error. On error, dst* will be blank (as if returned by av_packet_alloc()).*/
int av_packet_ref(AVPacket *dst, const AVPacket *src);/*** Wipe the packet.** Unreference the buffer referenced by the packet and reset the* remaining packet fields to their default values.** @param pkt The packet to be unreferenced.*/
void av_packet_unref(AVPacket *pkt);/*** Move every field in src to dst and reset src.** @see av_packet_unref** @param src Source packet, will be reset* @param dst Destination packet*/
void av_packet_move_ref(AVPacket *dst, AVPacket *src);/*** Copy only "properties" fields from src to dst.** Properties for the purpose of this function are all the fields* beside those related to the packet data (buf, data, size)** @param dst Destination packet* @param src Source packet** @return 0 on success AVERROR on failure.*/
int av_packet_copy_props(AVPacket *dst, const AVPacket *src);/*** Ensure the data described by a given packet is reference counted.** @note This function does not ensure that the reference will be writable.* Use av_packet_make_writable instead for that purpose.** @see av_packet_ref* @see av_packet_make_writable** @param pkt packet whose data should be made reference counted.** @return 0 on success, a negative AVERROR on error. On failure, the* packet is unchanged.*/
int av_packet_make_refcounted(AVPacket *pkt);/*** Create a writable reference for the data described by a given packet,* avoiding data copy if possible.** @param pkt Packet whose data should be made writable.** @return 0 on success, a negative AVERROR on failure. On failure, the* packet is unchanged.*/
int av_packet_make_writable(AVPacket *pkt);/*** Convert valid timing fields (timestamps / durations) in a packet from one* timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be* ignored.** @param pkt packet on which the conversion will be performed* @param tb_src source timebase, in which the timing fields in pkt are* expressed* @param tb_dst destination timebase, to which the timing fields will be* converted*/
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);/*** @}*/#endif // AVCODEC_PACKET_H
AVPacket结构体
AVPacket结构体声明在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的头文件libavcodec/packet.h中:
/*** @}*//*** @defgroup lavc_packet AVPacket** Types and functions for working with AVPacket.* @{*//*** 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;
成员变量buf:
AVBufferRef类型指针,指向“存储packet(一个数据包的压缩后的音视频)数据的引用计数缓冲区”。如果为NULL,表示该packet数据未被引用计数。AVPacket通过AVBufferRef来管理引用计数缓冲区。通过AVBufferRef结构体里面的AVBuffer里面的成员变量refcount记录资源使用的次数,控制资源的释放。
关于AVBufferRef类型可以参考:FFmpeg引用计数数据缓冲区相关的结构体:AVBuffer、AVBufferRef。-CSDN博客
成员变量pts:
显示时间戳(presentation time stamp)。即帧显示的时间刻度,用来告诉播放器在哪个时间点显示此帧(可以简单理解为这帧视频或音频数据的播放时间)。其单位不是秒,而是以AVStream->time_base为单位。pts必须大于或等于dts,因为一帧视频或音频数据必须在解码后才能播放,所以一帧视频或音频数据的显示/播放时间必须大于或等于解码时间。
成员变量dts:
解码时间戳(Decompression timestamp)。即帧解码的时间刻度,用来告诉播放器在哪个时间点解码此帧。其单位不是秒,而是以AVStream->time_base为单位。
成员变量data:
指针,指向“存放压缩后的一帧(对于视频通常包含一个压缩帧,对于音频可能包含几个压缩帧)音视频数据的缓冲区”。
成员变量size:
成员变量data指向的缓冲区的大小,单位为字节。
成员变量stream_index:
索引,用来标识该AVPacket所属的视频/音频流的序号,表示这是第几路流。注意:它是从0而不是从1开始的。
成员变量flags:
AV_PKT_FLAG的组合。值有如下选择:
#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe
#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
/*** Flag is used to discard packets which are required to maintain valid* decoder state but are not required for output and should be dropped* after decoding.**/
#define AV_PKT_FLAG_DISCARD 0x0004
/*** The packet comes from a trusted source.** Otherwise-unsafe constructs such as arbitrary pointers to data* outside the packet may be followed.*/
#define AV_PKT_FLAG_TRUSTED 0x0008
/*** Flag is used to indicate packets that contain frames that can* be discarded by the decoder. I.e. Non-reference frames.*/
#define AV_PKT_FLAG_DISPOSABLE 0x0010
AV_PKT_FLAG_KEY:数据包包含一个关键帧,即当前AVPacket是关键帧。
AV_PKT_FLAG_CORRUPT:数据包内容已损坏。
AV_PKT_FLAG_DISCARD:用于丢弃需要保持有效解码器状态但不需要输出的数据包,并且在解码后应该丢弃。带有该标志的AVPacket所携带的数据为解码器相关的信息,不会被解码出一幅图像。
AV_PKT_FLAG_TRUSTED:该数据包来自一个可信的源。
AV_PKT_FLAG_DISPOSABLE:用于指示包含可以被解码器丢弃的帧的数据包。也就是非参考帧。
成员变量side_data:
存放“容器可以提供的额外数据包数据”的数组的首地址。数据包可以包含多种类型的边信息,比如,在编码结束的时候更新一些流的参数。指针side_data指向的空间存储了用于解码、展现或处理编码流的辅助信息,它通常由解复用器和编码器导出,可以以分组为单位提供给解码器和复用器,也可以作为全局侧数据(应用于整个编码流)。
成员变量side_data_elems:
side_data的数量。
成员变量duration:
该数据包的持续时间,以AVStream->time_base为单位。值为下一个数据包的pts减去当前数据包的pts。如果值为0表示未知。
成员变量pos:
该数据包在流中的位置,单位为字节。值为-1表示未知。
成员变量opaque:
指针,指向“存放用户使用的私有数据的缓冲区”。
成员变量time_base:
AVRational类型,数据包时间戳的时间基准,即pts和dts的时间基。
例如对于视频来说,这个值可能是 1,25 也就是说,1秒钟我们显示
AVPacket 相关函数说明
av_packet_alloc函数
av_packet_alloc函数定义在源文件libavcodec/avpacket.c中:
需要通过av_packet_free() 释放
* @note this only allocates the AVPacket itself, not the data buffers. Those
* must be allocated through other means such as av_new_packet.
需要注意的是: 通过 av_packet_alloc的只能 allocates avpacket自己,里面有写内容给了默认值,有些给了特殊值,//调用 get_packet_defaults(AVPacket *pkt)出了特殊值 的有pts,dts,pos,time_base(time_base在 ffmpeg4.3没有,在5.0以后有)
#define AV_NOPTS_VALUE ((int64_t)UINT64_C(0x8000000000000000))
pkt->pts = AV_NOPTS_VALUE;
pkt->dts = AV_NOPTS_VALUE;
pkt->pos = -1;
pkt->time_base = av_make_q(0, 1);
/*** Allocate an AVPacket and set its fields to default values. The resulting* struct must be freed using av_packet_free().** @return An AVPacket filled with default values or NULL on failure.** @note this only allocates the AVPacket itself, not the data buffers. Those* must be allocated through other means such as av_new_packet.** @see av_new_packet*/
AVPacket *av_packet_alloc(void);
实现
AVPacket *av_packet_alloc(void)
{AVPacket *pkt = av_malloc(sizeof(AVPacket));if (!pkt)return pkt;get_packet_defaults(pkt);return pkt;
}//调用 get_packet_defaults(AVPacket *pkt)出了默认值 的有pts,dts,pos,time_base
static void get_packet_defaults(AVPacket *pkt)
{// 清空值,都是0,这意味着后面学习的 av_init_packet(AVPacket * pkt)方法作用不大,因此在ffmpeg5.0之后,将av_init_packet这个方法 标志成了 过时的。memset(pkt, 0, sizeof(*pkt));pkt->pts = AV_NOPTS_VALUE;pkt->dts = AV_NOPTS_VALUE;pkt->pos = -1;pkt->time_base = av_make_q(0, 1);
}
测试,我们看到在 av_packet_alloc之后,除了avpacket自己有值外,里面的数据都是0或者特殊值。
void av_init_packet(AVPacket* pkt); 已过时
从前面我们使用 av_packet_alloc的源码可以看到,在alloc的时候 memset 了0,然后给了pts,dts,timebase,pos 特殊值,我们看到 av_inti_packet方法除了给 pos,pts,dts,timebase特殊值外,其他值也是0,
这说明:av_init_packet方法干了 av_packet_alloc的部分工作,如果user 是先调用了av_packet_alloc();然后再调用 av_init_packet,就会显得很 冗余,这可能也是ffmpeg在5.0上将此方法标识为过时的原因。
那么这个方法到底有没有应用场景呢?应该是有的,当我们不通过 av_packet_alloc()去 create一个AVPacket *的时候,而是直接在 栈上使用一个 AVPacket,那么这个方法就可以初始化avpacket的内容。
#if FF_API_INIT_PACKET
/*** Initialize optional fields of a packet with default values.** Note, this does not touch the data and size members, which have to be* initialized separately.** @param pkt packet** @see av_packet_alloc* @see av_packet_unref** @deprecated This function is deprecated. Once it's removed,sizeof(AVPacket) will not be a part of the ABI anymore.*/
attribute_deprecated
void av_init_packet(AVPacket *pkt);
#endif
实现
#if FF_API_INIT_PACKET
void av_init_packet(AVPacket *pkt)
{pkt->pts = AV_NOPTS_VALUE;pkt->dts = AV_NOPTS_VALUE;pkt->pos = -1;pkt->duration = 0;pkt->flags = 0;pkt->stream_index = 0;pkt->buf = NULL;pkt->side_data = NULL;pkt->side_data_elems = 0;pkt->opaque = NULL;pkt->opaque_ref = NULL;pkt->time_base = av_make_q(0, 1);
}
#endif
测试:
无作用版:
void createAVPacketandInit1() {AVPacket* avpacket = av_packet_alloc();if (avpacket == nullptr) {cout << "av_packet_alloc error" << endl;}cout << "debug point 0" << endl;av_init_packet(avpacket);cout << "debug point 1" << endl;
}
有点作用版:
void createAVPacketandInit() {AVPacket avpacket;cout << "debug point 0" << endl;av_init_packet(&avpacket);cout << "debug point 1" << endl;
}
av_packet_alloc 和 av_init_packet的区别是?
初始化的区别在于没有给size赋值。
我们再来回顾一下前面关于 这个 size是啥?
成员变量size:成员变量data指向的缓冲区的大小,单位为字节。
有啥用? 在后面 av_packet_clone函数中就可以看到,如果这个size的值没有被赋值过,则clone的new avpacket 会失败,也就是返回nullptr。
void av_packet_free(AVPacket **pkt);
/*** Free the packet, if the packet is reference counted, it will be* unreferenced first.** @param pkt packet to be freed. The pointer will be set to NULL.* @note passing NULL is a no-op.*/
void av_packet_free(AVPacket **pkt);
实现
从实现可以看到,这个不管是不ptk 是不是nullptr,都不会有错误
void av_packet_free(AVPacket **pkt)
{if (!pkt || !*pkt)return;av_packet_unref(*pkt);av_freep(pkt);
}
从这个方法来看,是将pkt的内部数据都释放了,并且给内部数据重新给了默认值
av_packet_unref(*pkt);void av_packet_unref(AVPacket *pkt)
{av_packet_free_side_data(pkt);av_buffer_unref(&pkt->opaque_ref);av_buffer_unref(&pkt->buf);get_packet_defaults(pkt);
}
从 av_freep 方法来看,是 将 &pkt,的值赋值给&val,然后将&pkg赋值为null,最后再free &val。
为什么写的这么复杂呢?
直接free &pkt 不行吗? 这个好处是啥呢?知道的童鞋可以回复一下,感谢!!!
void av_freep(void *arg)
{void *val;memcpy(&val, arg, sizeof(val));memcpy(arg, &(void *){ NULL }, sizeof(val));av_free(val);
}void av_free(void *ptr)
{
#if HAVE_ALIGNED_MALLOC_aligned_free(ptr);
#elsefree(ptr);
#endif
}
使用测试
void createAVpacketandFreeAVPacket() {AVPacket* avpacket = av_packet_alloc();if (avpacket == nullptr) {cout << "av_packet_alloc error" << endl;}cout << "debugpoint1" << endl;av_packet_free(&avpacket);cout << "debugpoint2" << endl;
}
AVPacket* av_packet_clone(const AVPacket* src);
This is a shortcut for av_packet_alloc()+av_packet_ref().
/*** Create a new packet that references the same data as src.** This is a shortcut for av_packet_alloc()+av_packet_ref().** @return newly created AVPacket on success, NULL on error.** @see av_packet_alloc* @see av_packet_ref*/
AVPacket* av_packet_clone(const AVPacket* src);
实现可以看到 :是先 ret = av_packet_alloc,然后调用 (av_packet_ref(ret, src)),最后返回 新建的这个ret。
这里的关键是 av_packet_ref(AVPacket *dst, const AVPacket *src) 方法
AVPacket *av_packet_clone(const AVPacket *src)
{AVPacket *ret = av_packet_alloc();if (!ret)return ret;if (av_packet_ref(ret, src))av_packet_free(&ret);return ret;
}
int av_packet_ref(AVPacket *dst, const AVPacket *src)
{int ret;dst->buf = NULL;ret = av_packet_copy_props(dst, src);if (ret < 0)goto fail;if (!src->buf) {ret = packet_alloc(&dst->buf, src->size);if (ret < 0)goto fail;av_assert1(!src->size || src->data);if (src->size)memcpy(dst->buf->data, src->data, src->size);dst->data = dst->buf->data;} else {dst->buf = av_buffer_ref(src->buf);if (!dst->buf) {ret = AVERROR(ENOMEM);goto fail;}dst->data = src->data;}dst->size = src->size;return 0;
fail:av_packet_unref(dst);return ret;
}
实验测试1 :如果在 src 是不是通过 av_packet_clone出来的,或者 没有通过 av_init_packet初始化过packet 的会有 runtime error
/***
*
* 实验测试当 AVPacket 没有赋值的时候,使用 av_packet_clone会报error
***/
void avpacketclone() {AVPacket avpacket1 ;//实验测试当 AVPacket 没有赋值的时候,使用 av_packet_clone会报errorAVPacket* newavpacket = av_packet_clone(&avpacket1);if (newavpacket == nullptr) {cout << "newavpacket = nullptr" << endl;}cout << "debug point" << endl;
}
实验测试2:
* 实验测试当 AVPacket 在栈空间,且通过 av_init_packet初始化,
* 返回的newavpacket是nullptr
* root case 是 av_packet_ref(ret, src) ,packet_alloc(&dst->buf, src->size) ;src->size 的值是 < 0的,因此返回nullptr
/***
*
* 实验测试当 AVPacket 在栈空间,且通过 av_init_packet初始化,
* 返回的newavpacket是nullptr
* root case 是 av_packet_ref(ret, src) ,packet_alloc(&dst->buf, src->size) ;src->size 的值是 < 0的,因此返回nullptr
*
***/
void avpacketclone1() {AVPacket avpacket1;//实验测试当 AVPacket 没有赋值的时候,使用 av_packet_clone会报errorav_init_packet(&avpacket1);//那么通过av_packet_alloc方法是否OK呢?AVPacket* newavpacket = av_packet_clone(&avpacket1);if (newavpacket == nullptr) {cout << "newavpacket = nullptr" << endl;}cout << "debug point" << endl;
}
实验测试3:
/// <summary>
/// 上述 通过 av_packet_clone方法 不是有 runtime exception就是 clone出来的newpacket为nullpptr
/// clone出来的newpacket 为nullptr 的root case 是 因为size 为一个默认值,很大的负数,没有被赋值为0或者其他值
/// 那我们下来手动的将这个 size这个值设置为 一个具体的数,行不行呢?
/// 如何设置这个值,我们查看 .h文件,发现有一个api说明比较像
/// int av_new_packet(AVPacket *pkt, int size);
/// 先来测试一下,我们再来研究这个 av_new_packet 函数
/// <summary>
/// 上述 通过 av_packet_clone方法 不是有 runtime exception就是 clone出来的newpacket为nullpptr
/// clone出来的newpacket 为nullptr 的root case 是 因为size 为一个默认值,很大的负数,没有被赋值为0或者其他值
/// 那我们下来手动的将这个 size这个值设置为 一个具体的数,行不行呢?
/// 如何设置这个值,我们查看 .h文件,发现有一个api说明比较像
/// int av_new_packet(AVPacket *pkt, int size);
/// 先来测试一下,我们再来研究这个 av_new_packet 函数
/// </summary>
void avpacketclone2() {AVPacket* avpacket = av_packet_alloc();int ret = 0;ret = av_new_packet(avpacket, 10);AVPacket* newavpacket = av_packet_clone(avpacket);if (newavpacket == nullptr) {cout << "newavpacket = nullptr" << endl;}cout << "debug point" << endl;
}
结论是:成功,且两个packet 的buf的指针是一样的。
int av_new_packet(AVPacket *pkt, int size);
给pkt 赋初始值(这个赋初值包含size吗?包含且为0,在后面的源码中可以看到);然后再给data 分配大小为size。
/*** Allocate the payload of a packet and initialize its fields with* default values.** @param pkt packet* @param size wanted payload size* @return 0 if OK, AVERROR_xxx otherwise*/
int av_new_packet(AVPacket *pkt, int size);
源码:
从代码中可以看到 apcket_alloc的时候,这个size就很关键了,size的大小决定了到底赋值还是不赋值
int av_new_packet(AVPacket *pkt, int size)
{AVBufferRef *buf = NULL;int ret = packet_alloc(&buf, size);if (ret < 0)return ret;get_packet_defaults(pkt);pkt->buf = buf;pkt->data = buf->data;pkt->size = size;return 0;
}//即使size的值是符合预期的,分配的大小 还要加上一个 AV_INPUT_BUFFER_PADDING_SIZE(64)
//为啥要多弄出来一个64 呢?这是因为有些解码器,编码器为了算法优化,会有一些多余的buffer(这个buffer一般都是小于等于64的),因此ffmpeg在设计的时候,就多加了个64
static int packet_alloc(AVBufferRef **buf, int size)
{int ret;// 错误判断if (size < 0 || size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)return AVERROR(EINVAL);/// 真的分配空间ret = av_buffer_realloc(buf, size + AV_INPUT_BUFFER_PADDING_SIZE);if (ret < 0)return ret;
///清空空间memset((*buf)->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);return 0;
}///这里看一下,ffmpeg中分配空间的方法
void *av_realloc(void *ptr, size_t size)
{
/// error判断void *ret;if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed))return NULL;
/// HAVE_ALIGNED_MALLOC=1,因此代码会走到 _aligned_realloc这一行
#if HAVE_ALIGNED_MALLOCret = _aligned_realloc(ptr, size + !size, ALIGN);
#elseret = realloc(ptr, size + !size);
#endif
/// CONFIG_MEMORY_POISONING =0; 因此下面的代码不会走。
#if CONFIG_MEMORY_POISONINGif (ret && !ptr)memset(ret, FF_MEMORY_POISON, size);
#endifreturn ret;
}///_aligned_realloc 方法的详细说明
https://learn.microsoft.com/zh-cn/cpp/c-runtime-library/reference/aligned-realloc?view=msvc-170_aligned_realloc(ptr, size + !size, ALIGN);ALIGN是32
给ptr 分配 (size + !size)的大小 ,这个大小为啥是 (size + !size)为什么这么写呢?
在c语言中 !0 = 1, !1=0, 猜测ffmpeg的开发者 这么写是为了保证这个值最少是1,可能是为了某个bug,也可能是为了保证这个值的必须 >0.void * _aligned_realloc(void *memblock,size_t size,size_t alignment
);memblock
当前的内存块指针。size
请求的内存分配的大小。alignment
对齐值,必须是 2 的整数次幂。static void get_packet_defaults(AVPacket *pkt)
{memset(pkt, 0, sizeof(*pkt));pkt->pts = AV_NOPTS_VALUE;pkt->dts = AV_NOPTS_VALUE;pkt->pos = -1;pkt->time_base = av_make_q(0, 1);
}
在看完源码之后,能想到这个api使用的时机是什么吗?
猜测是我们知道了要传入的packet 的data 大小,可以提前设定这个大小?
void av_shrink_packet(AVPacket *pkt, int size);
成员变量data:
指针,指向“存放压缩后的一帧(对于视频通常包含一个压缩帧,对于音频可能包含几个压缩帧)音视频数据的缓冲区”。
成员变量size:
成员变量data指向的缓冲区的大小,单位为字节。
shrink 是收缩,缩小的意思,从字面意思来是,是将pkt data 的size 变成现在的值。
将当前pkt 中的 data的大小变成size,如果当前pkt->size本身就比要设置的size小,则直接return,
例如原先pkt->size的值是8,user 想要改成,16,那就不变还是8
例如原先pkt->size的值是8,user 想要改成6,那么就会变成6.
然后还会将 pkt->data + size 后的 AV_INPUT_BUFFER_PADDING_SIZE大小的空间清零
这也很好理解,size 变化了,本身就在size后面多加了AV_INPUT_BUFFER_PADDING_SIZE,要保证 AV_INPUT_BUFFER_PADDING_SIZE 这段空间是清零的。
/*** Reduce packet size, correctly zeroing padding** @param pkt packet* @param size new size*/
void av_shrink_packet(AVPacket *pkt, int size);
实现
void av_shrink_packet(AVPacket *pkt, int size)
{if (pkt->size <= size)return;pkt->size = size;memset(pkt->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
}
问题是:在哪里使用呢?什么时机使用呢?
int av_grow_packet(AVPacket* pkt, int grow_by);
增加数据包大小,正确归零填充
/*** Increase packet size, correctly zeroing padding** @param pkt packet* @param grow_by number of bytes by which to increase the size of the packet*/
int av_grow_packet(AVPacket *pkt, int grow_by);
实现:
从实现来看,
增加数据包(pkt->data指向的缓冲区)的大小,让该大小增至(pkt->size + grow_by)字节。让地址为(pkt->data + pkt->size + grow_by)后的数据字节归零。执行该函数后,pkt->size会增至(pkt->size + grow_by)字节。返回0表示成功,返回负数表示失败。
int av_grow_packet(AVPacket *pkt, int grow_by)
{int new_size;av_assert0((unsigned)pkt->size <= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE);if ((unsigned)grow_by >INT_MAX - (pkt->size + AV_INPUT_BUFFER_PADDING_SIZE))return AVERROR(ENOMEM);new_size = pkt->size + grow_by + AV_INPUT_BUFFER_PADDING_SIZE;if (pkt->buf) {size_t data_offset;uint8_t *old_data = pkt->data;if (pkt->data == NULL) {data_offset = 0;pkt->data = pkt->buf->data;} else {data_offset = pkt->data - pkt->buf->data;if (data_offset > INT_MAX - new_size)return AVERROR(ENOMEM);}if (new_size + data_offset > pkt->buf->size ||!av_buffer_is_writable(pkt->buf)) {int ret;// allocate slightly more than requested to avoid excessive// reallocationsif (new_size + data_offset < INT_MAX - new_size/16)new_size += new_size/16;ret = av_buffer_realloc(&pkt->buf, new_size + data_offset);if (ret < 0) {pkt->data = old_data;return ret;}pkt->data = pkt->buf->data + data_offset;}} else {pkt->buf = av_buffer_alloc(new_size);if (!pkt->buf)return AVERROR(ENOMEM);if (pkt->size > 0)memcpy(pkt->buf->data, pkt->data, pkt->size);pkt->data = pkt->buf->data;}pkt->size += grow_by;memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);return 0;
}
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
/*** Initialize a reference-counted packet from av_malloc()ed data.** @param pkt packet to be initialized. This function will set the data, size,* and buf fields, all others are left untouched.* @param data Data allocated by av_malloc() to be used as packet data. If this* function returns successfully, the data is owned by the underlying AVBuffer.* The caller may not access the data through other means.* @param size size of data in bytes, without the padding. I.e. the full buffer* size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE.** @return 0 on success, a negative AVERROR on error*/
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);
代码实现,从实现上来看,会将 pkt->data指向传进来的data,大小为size,注意的 pkt的data 赋值并没有 copy,而是直接将指针赋值给了pkt的data,也就是说,在pkt 的data没有使用的时候,不要释放data空间,释放了意味着pkt的data也就变化了 ;;如果覆盖了传递进来的data空间,也意味着pkt的data的内容变化了。
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
{if (size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)return AVERROR(EINVAL);pkt->buf = av_buffer_create(data, size + AV_INPUT_BUFFER_PADDING_SIZE,av_buffer_default_free, NULL, 0);if (!pkt->buf)return AVERROR(ENOMEM);pkt->data = data;pkt->size = size;return 0;
}