中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

駿域網(wǎng)站建設(shè)專家品牌網(wǎng)站建設(shè)公司

駿域網(wǎng)站建設(shè)專家,品牌網(wǎng)站建設(shè)公司,網(wǎng)站開發(fā)項目預(yù)算表,做網(wǎng)站 做app如下圖的解碼流程,AVPacket中的位置 FFmpeg源碼中通過AVPacket存儲壓縮后的音視頻數(shù)據(jù)。它通常由解復(fù)用器(demuxers)輸出,然后作為輸入傳遞給解碼器。 或者從編碼器作為輸出接收,然后傳遞給多路復(fù)用器(mux…

如下圖的解碼流程,AVPacket中的位置

FFmpeg源碼中通過AVPacket存儲壓縮后的音視頻數(shù)據(jù)。它通常由解復(fù)用器(demuxers)輸出,然后作為輸入傳遞給解碼器。

或者從編碼器作為輸出接收,然后傳遞給多路復(fù)用器(muxers)。

對于視頻,它通常包含一個壓縮幀;對于音頻,它可能包含幾個壓縮幀。編碼器允許輸出不包含壓縮音視頻數(shù)據(jù)、只包含side data(邊數(shù)據(jù):例如,在編碼結(jié)束時更新一些流參數(shù))的空的數(shù)據(jù)包( empty packets)。

AVPacket 結(jié)構(gòu)體?所在的文件名 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結(jié)構(gòu)體

AVPacket結(jié)構(gòu)體聲明在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(一個數(shù)據(jù)包的壓縮后的音視頻)數(shù)據(jù)的引用計數(shù)緩沖區(qū)”。如果為NULL,表示該packet數(shù)據(jù)未被引用計數(shù)。AVPacket通過AVBufferRef來管理引用計數(shù)緩沖區(qū)。通過AVBufferRef結(jié)構(gòu)體里面的AVBuffer里面的成員變量refcount記錄資源使用的次數(shù),控制資源的釋放。可以通過av_buffer_get_ref_count(const AVBufferRef *buf);方法得到引用計數(shù)

關(guān)于AVBufferRef類型可以參考:FFmpeg引用計數(shù)數(shù)據(jù)緩沖區(qū)相關(guān)的結(jié)構(gòu)體:AVBuffer、AVBufferRef。-CSDN博客

成員變量pts:

顯示時間戳(presentation time stamp)。即幀顯示的時間刻度,用來告訴播放器在哪個時間點顯示此幀(可以簡單理解為這幀視頻或音頻數(shù)據(jù)的播放時間)。其單位不是秒,而是以AVStream->time_base為單位。pts必須大于或等于dts,因為一幀視頻或音頻數(shù)據(jù)必須在解碼后才能播放,所以一幀視頻或音頻數(shù)據(jù)的顯示/播放時間必須大于或等于解碼時間。

avpacket中,pts 并不由我們寫入,這是因為 pts 的顯示時間,那么最初的原始數(shù)據(jù)YUV在存儲到avframe的時候,就需要寫入pts,不然后面的avpacket怎么知道呢?

成員變量dts:

解碼時間戳(Decompression timestamp)。即幀解碼的時間刻度,用來告訴播放器在哪個時間點解碼此幀。其單位不是秒,而是以AVStream->time_base為單位。

如果解碼 和顯示都是按照順序的,那么dts和pts都是一樣的,只有當(dāng)視頻中含有B幀的時候,pts 和dts 會有不同的時候,這是因為B幀會參考 前后的幀顯示,因此解碼的時候先要解碼前面的幀,然后解碼后面的幀,才能解碼自己,但是顯示的時候順序還是一樣的,前面一幀--->自己---》后面一幀

dts是由具體的解碼器內(nèi)部生成的,這也很好理解,例如你用的 H264的解碼器,或者H265的解碼器,那么不同的解碼器算法肯定不同,怎么壓縮,那一幀是關(guān)鍵幀,后面的哪些幀依賴于這個關(guān)鍵幀,是不是弄成B幀呀,都是不一樣的,因此 解碼的順序也是由具體的解碼器說的算的

成員變量data:

指針,指向“存放壓縮后的一幀(對于視頻通常包含一個壓縮幀,對于音頻可能包含幾個壓縮幀)音視頻數(shù)據(jù)的緩沖區(qū)”。?

成員變量size:

成員變量data指向的緩沖區(qū)的大小,單位為字節(jié)。

成員變量stream_index:

索引,用來標(biāo)識該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:數(shù)據(jù)包包含一個關(guān)鍵幀,即當(dāng)前AVPacket是關(guān)鍵幀??梢元?dú)立顯示出來的一張圖片,當(dāng)然一般情況下,這張圖片是有做 幀內(nèi)編碼的(參考視頻編碼原理那一節(jié)),這個很重要,在seekg的時候,一定要移動到 關(guān)鍵幀

AV_PKT_FLAG_CORRUPT:數(shù)據(jù)包內(nèi)容已損壞。

AV_PKT_FLAG_DISCARD:用于丟棄需要保持有效解碼器狀態(tài)但不需要輸出的數(shù)據(jù)包,并且在解碼后應(yīng)該丟棄。帶有該標(biāo)志的AVPacket所攜帶的數(shù)據(jù)為解碼器相關(guān)的信息,不會被解碼出一幅圖像。

AV_PKT_FLAG_TRUSTED:該數(shù)據(jù)包來自一個可信的源。

AV_PKT_FLAG_DISPOSABLE:用于指示包含可以被解碼器丟棄的幀的數(shù)據(jù)包。也就是非參考幀。

成員變量side_data:

存放“容器可以提供的額外數(shù)據(jù)包數(shù)據(jù)”的數(shù)組的首地址。數(shù)據(jù)包可以包含多種類型的邊信息,比如,在編碼結(jié)束的時候更新一些流的參數(shù)。指針side_data指向的空間存儲了用于解碼、展現(xiàn)或處理編碼流的輔助信息,它通常由解復(fù)用器和編碼器導(dǎo)出,可以以分組為單位提供給解碼器和復(fù)用器,也可以作為全局側(cè)數(shù)據(jù)(應(yīng)用于整個編碼流)。

成員變量side_data_elems:

side_data的數(shù)量。

成員變量duration:

該數(shù)據(jù)包的持續(xù)時間,以AVStream->time_base為單位。值為下一個數(shù)據(jù)包的pts減去當(dāng)前數(shù)據(jù)包的pts。如果值為0表示未知。

成員變量pos:

該數(shù)據(jù)包在流中的位置,單位為字節(jié)。值為-1表示未知。

成員變量opaque:

指針,指向“存放用戶使用的私有數(shù)據(jù)的緩沖區(qū)”。

成員變量time_base:

AVRational類型,數(shù)據(jù)包時間戳的時間基準(zhǔn),即pts和dts的時間基。

例如對于視頻來說,這個值可能是 1,25 也就是說,1秒鐘我們顯示

AVPacket 相關(guān)函數(shù)說明

av_packet_alloc函數(shù)

av_packet_alloc函數(shù)定義在源文件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自己,里面有寫內(nèi)容給了默認(rèn)值,有些給了特殊值,//調(diào)用 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);

實現(xiàn)

AVPacket *av_packet_alloc(void)
{AVPacket *pkt = av_malloc(sizeof(AVPacket));if (!pkt)return pkt;get_packet_defaults(pkt);return pkt;
}//調(diào)用 get_packet_defaults(AVPacket *pkt)出了默認(rèn)值 的有pts,dts,pos,time_base
static void get_packet_defaults(AVPacket *pkt)
{// 清空值,都是0,這意味著后面學(xué)習(xí)的 av_init_packet(AVPacket * pkt)方法作用不大,因此在ffmpeg5.0之后,將av_init_packet這個方法 標(biāo)志成了 過時的。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自己有值外,里面的數(shù)據(jù)都是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 是先調(diào)用了av_packet_alloc();然后再調(diào)用 av_init_packet,就會顯得很 冗余,這可能也是ffmpeg在5.0上將此方法標(biāo)識為過時的原因。

那么這個方法到底有沒有應(yīng)用場景呢?應(yīng)該是有的,當(dāng)我們不通過 av_packet_alloc()去 create一個AVPacket *的時候,而是直接在 棧上使用一個 AVPacket,那么這個方法就可以初始化avpacket的內(nèi)容。

#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

實現(xiàn)

#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的區(qū)別是?

初始化的區(qū)別在于沒有給size賦值。

我們再來回顧一下前面關(guān)于 這個 size是啥?

成員變量size:成員變量data指向的緩沖區(qū)的大小,單位為字節(jié)。

有啥用? 在后面 av_packet_clone函數(shù)中就可以看到,如果這個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);

實現(xiàn)

從實現(xiàn)可以看到,這個不管是不ptk 是不是nullptr,都不會有錯誤

void av_packet_free(AVPacket **pkt)
{if (!pkt || !*pkt)return;av_packet_unref(*pkt);av_freep(pkt);
}

從這個方法來看,是將pkt的內(nèi)部數(shù)據(jù)都釋放了,并且給內(nèi)部數(shù)據(jù)重新給了默認(rèn)值

    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。

為什么寫的這么復(fù)雜呢?

直接free &pkt 不行嗎? 這個好處是啥呢?知道的童鞋可以回復(fù)一下,感謝!!!

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);

實現(xiàn)可以看到 :是先 ret = av_packet_alloc,然后調(diào)用?(av_packet_ref(ret, src)),最后返回 新建的這個ret。

這里的關(guān)鍵是?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

/***
* 
* 實驗測試當(dāng) AVPacket 沒有賦值的時候,使用 av_packet_clone會報error
***/
void avpacketclone() {AVPacket avpacket1 ;//實驗測試當(dāng) AVPacket 沒有賦值的時候,使用 av_packet_clone會報errorAVPacket* newavpacket = av_packet_clone(&avpacket1);if (newavpacket == nullptr) {cout << "newavpacket = nullptr" << endl;}cout << "debug point" << endl;
}

實驗測試2:

* 實驗測試當(dāng) AVPacket 在??臻g,且通過 av_init_packet初始化,
* 返回的newavpacket是nullptr
* root case 是 av_packet_ref(ret, src) ,packet_alloc(&dst->buf, src->size) ;src->size 的值是 < 0的,因此返回nullptr
?

/***
*
* 實驗測試當(dāng) 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;//實驗測試當(dāng) 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 為一個默認(rèn)值,很大的負(fù)數(shù),沒有被賦值為0或者其他值
/// 那我們下來手動的將這個 size這個值設(shè)置為 一個具體的數(shù),行不行呢?
/// 如何設(shè)置這個值,我們查看 .h文件,發(fā)現(xiàn)有一個api說明比較像
/// int av_new_packet(AVPacket *pkt, int size);
/// 先來測試一下,我們再來研究這個 av_new_packet 函數(shù)
?

/// <summary>
/// 上述 通過 av_packet_clone方法 不是有 runtime exception就是 clone出來的newpacket為nullpptr
/// ?clone出來的newpacket 為nullptr 的root case 是 因為size 為一個默認(rèn)值,很大的負(fù)數(shù),沒有被賦值為0或者其他值
/// 那我們下來手動的將這個 size這個值設(shè)置為 一個具體的數(shù),行不行呢?
/// 如何設(shè)置這個值,我們查看 .h文件,發(fā)現(xiàn)有一個api說明比較像
/// int av_new_packet(AVPacket *pkt, int size);
/// 先來測試一下,我們再來研究這個 av_new_packet 函數(shù)
/// </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;
}

結(jié)論是:成功,且兩個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就很關(guān)鍵了,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的值是符合預(yù)期的,分配的大小 還要加上一個 AV_INPUT_BUFFER_PADDING_SIZE(64)
//為啥要多弄出來一個64 呢?這是因為有些解碼器,編碼器為了算法優(yōu)化,會有一些多余的buffer(這個buffer一般都是小于等于64的),因此ffmpeg在設(shè)計的時候,就多加了個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 方法的詳細(xì)說明
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的開發(fā)者 這么寫是為了保證這個值最少是1,可能是為了某個bug,也可能是為了保證這個值的必須 >0.void * _aligned_realloc(void *memblock,size_t size,size_t alignment
);memblock
當(dāng)前的內(nèi)存塊指針。size
請求的內(nèi)存分配的大小。alignment
對齊值,必須是 2 的整數(shù)次冪。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使用的時機(jī)是什么嗎?

猜測是我們知道了要傳入的packet 的data 大小,可以提前設(shè)定這個大小?

void av_shrink_packet(AVPacket *pkt, int size);

成員變量data:

指針,指向“存放壓縮后的一幀(對于視頻通常包含一個壓縮幀,對于音頻可能包含幾個壓縮幀)音視頻數(shù)據(jù)的緩沖區(qū)”。

成員變量size:

成員變量data指向的緩沖區(qū)的大小,單位為字節(jié)。

shrink 是收縮,縮小的意思,從字面意思來是,是將pkt data 的size 變成現(xiàn)在的值。

將當(dāng)前pkt 中的 data的大小變成size,如果當(dāng)前pkt->size本身就比要設(shè)置的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);

實現(xiàn)

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);
}

問題是:在哪里使用呢?什么時機(jī)使用呢?

int av_grow_packet(AVPacket* pkt, int grow_by);

增加數(shù)據(jù)包大小,正確歸零填充

/*** 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);

實現(xiàn):

從實現(xiàn)來看,

增加數(shù)據(jù)包(pkt->data指向的緩沖區(qū))的大小,讓該大小增至(pkt->size + grow_by)字節(jié)。讓地址為(pkt->data + pkt->size + grow_by)后的數(shù)據(jù)字節(jié)歸零。執(zhí)行該函數(shù)后,pkt->size會增至(pkt->size + grow_by)字節(jié)。返回0表示成功,返回負(fù)數(shù)表示失敗。

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)

使用已經(jīng)分配好的buffer初始化一個AVPacket,會設(shè)置AVPacket的data和size成員。傳入的size參數(shù)是減去了AV_INPUT_BUFFER_PADDING_SIZE的,也就是size + AV_INPUT_BUFFER_PADDING_SIZE等于buffer總的大小。

代碼實現(xiàn),從實現(xiàn)上來看,會將 pkt->data指向傳進(jìn)來的data,大小為size,注意的 pkt的data 賦值并沒有 copy,而是直接將指針賦值給了pkt的data,也就是說,在pkt 的data沒有使用的時候,不要釋放data空間,釋放了意味著pkt的data也就變化了 ;;如果覆蓋了傳遞進(jìn)來的data空間,也意味著pkt的data的內(nèi)容變化了。

/*** 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);

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;
}

int av_buffer_get_ref_count(const AVBufferRef *buf);

得到avpacket或者 avframe的 引用計數(shù)

int av_buffer_get_ref_count(const AVBufferRef *buf)
{return atomic_load(&buf->buffer->refcount);
}

?? ?cout<<av_buffer_get_ref_count(avpacket->buf)<<endl;

?? ?cout<<av_buffer_get_ref_count(avframe->buf)<<endl;

uint8_t* av_packet_new_side_data(AVPacket* pkt, enum AVPacketSideDataType type, size_t size);

返回值是要存儲的 size_data的指針。

AVPacket->side_data是AVPacket攜帶的side數(shù)據(jù)數(shù)組,AVPacket->side_data_elems是數(shù)組的長度。av_packet_new_side_dataav_packet_add_side_data函數(shù)都提供了向AVPacket添加指定類型side data的能力,只是參數(shù)略有差異,每次都會把新side data添加到數(shù)組的尾部。?av_packet_get_side_data函數(shù)提供了從AVPacket獲取指定類型side data的能力。

/*** 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);

uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,size_t size)
{int ret;uint8_t *data;if (size > SIZE_MAX - AV_INPUT_BUFFER_PADDING_SIZE)return NULL;data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);if (!data)return NULL;ret = av_packet_add_side_data(pkt, type, data, size);if (ret < 0) {av_freep(&data);return NULL;}return data;
}

int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, uint8_t *data, 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);

int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,uint8_t *data, size_t size)
{AVPacketSideData *tmp;int i, elems = pkt->side_data_elems;for (i = 0; i < elems; i++) {AVPacketSideData *sd = &pkt->side_data[i];if (sd->type == type) {av_free(sd->data);sd->data = data;sd->size = size;return 0;}}if ((unsigned)elems + 1 > AV_PKT_DATA_NB)return AVERROR(ERANGE);tmp = av_realloc(pkt->side_data, (elems + 1) * sizeof(*tmp));if (!tmp)return AVERROR(ENOMEM);pkt->side_data = tmp;pkt->side_data[elems].data = data;pkt->side_data[elems].size = size;pkt->side_data[elems].type = type;pkt->side_data_elems++;return 0;
}

參考ffmpeg源碼中的一些使用。

如下的例子都是ffmpeg在編碼的時候用到,再回看關(guān)于 字段size_data的說明: 存放“容器可以提供的額外數(shù)據(jù)包數(shù)據(jù)”的數(shù)組的首地址。數(shù)據(jù)包可以包含多種類型的邊信息,比如,在編碼結(jié)束的時候更新一些流的參數(shù)。指針side_data指向的空間存儲了用于解碼、展現(xiàn)或處理編碼流的輔助信息,它通常由解復(fù)用器和編碼器導(dǎo)出,可以以分組為單位提供給解碼器和復(fù)用器,也可以作為全局側(cè)數(shù)據(jù)(應(yīng)用于整個編碼流)。

flac.enc中的使用

static int flac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,const AVFrame *frame, int *got_packet_ptr)
{FlacEncodeContext *s;int frame_bytes, out_bytes, ret;s = avctx->priv_data;/* when the last block is reached, update the header in extradata */if (!frame) {s->max_framesize = s->max_encoded_framesize;av_md5_final(s->md5ctx, s->md5sum);write_streaminfo(s, avctx->extradata);if (!s->flushed) {uint8_t *side_data = av_packet_new_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA,avctx->extradata_size);if (!side_data)return AVERROR(ENOMEM);memcpy(side_data, avctx->extradata, avctx->extradata_size);avpkt->pts = s->next_pts;*got_packet_ptr = 1;s->flushed = 1;}return 0;}

從img2dec.c中看到

要結(jié)合 av_packet_pack_dictionary方法使用

static int add_filename_as_pkt_side_data(char *filename, AVPacket *pkt) {AVDictionary *d = NULL;char *packed_metadata = NULL;size_t metadata_len;int ret;av_dict_set(&d, "lavf.image2dec.source_path", filename, 0);av_dict_set(&d, "lavf.image2dec.source_basename", av_basename(filename), 0);packed_metadata = av_packet_pack_dictionary(d, &metadata_len);av_dict_free(&d);if (!packed_metadata)return AVERROR(ENOMEM);ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,packed_metadata, metadata_len);if (ret < 0) {av_freep(&packed_metadata);return ret;}return 0;
}

總結(jié)一下:一般這玩意在 特定的編碼器的時候使用,表明我們要給avpacket中添加一些特殊的信息,信息的類型由?AVPacketSideDataType 決定,那么?AVPacketSideDataType 有哪些?這些翻譯出來也不知道真正的意思是啥,應(yīng)該是對于 每一種特殊的編碼學(xué)習(xí)的時候,會用到這個,我們假設(shè)mp4編碼器有特殊的值,那么就在這個?AVPacketSideDataType 里面找。

size_t size : 應(yīng)該是 要設(shè)置的AVPacket->side_data的大小。在實際開發(fā)中遇到后,應(yīng)該多測試,看是否要減去這個?AV_INPUT_BUFFER_PADDING_SIZE

uint8_t* av_packet_get_side_data(const AVPacket* pkt, enum AVPacketSideDataType type, size_t* size);

這個看起來就在解碼的時候用到,得到avpacket中存儲的值

/*** 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);

源碼實現(xiàn)

uint8_t *av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type,size_t *size)
{int i;for (i = 0; i < pkt->side_data_elems; i++) {if (pkt->side_data[i].type == type) {if (size)*size = pkt->side_data[i].size;return pkt->side_data[i].data;}}if (size)*size = 0;return NULL;
}

源碼中的使用

static int h264_decode_frame(AVCodecContext *avctx, AVFrame *pict,int *got_frame, AVPacket *avpkt)
{const uint8_t *buf = avpkt->data;int buf_size       = avpkt->size;H264Context *h     = avctx->priv_data;int buf_index;int ret;h->flags = avctx->flags;h->setup_finished = 0;h->nb_slice_ctx_queued = 0;ff_h264_unref_picture(h, &h->last_pic_for_ec);/* end of stream, output what is still in the buffers */if (buf_size == 0)return send_next_delayed_frame(h, pict, got_frame, 0);if (av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, NULL)) {size_t side_size;uint8_t *side = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);ff_h264_decode_extradata(side, side_size,&h->ps, &h->is_avc, &h->nal_length_size,avctx->err_recognition, avctx);}if (h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC) {if (is_avcc_extradata(buf, buf_size))return ff_h264_decode_extradata(buf, buf_size,&h->ps, &h->is_avc, &h->nal_length_size,avctx->err_recognition, avctx);}buf_index = decode_nal_units(h, buf, buf_size);if (buf_index < 0)return AVERROR_INVALIDDATA;if (!h->cur_pic_ptr && h->nal_unit_type == H264_NAL_END_SEQUENCE) {av_assert0(buf_index <= buf_size);return send_next_delayed_frame(h, pict, got_frame, buf_index);}if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS) && (!h->cur_pic_ptr || !h->has_slice)) {if (avctx->skip_frame >= AVDISCARD_NONREF ||buf_size >= 4 && !memcmp("Q264", buf, 4))return buf_size;av_log(avctx, AV_LOG_ERROR, "no frame!\n");return AVERROR_INVALIDDATA;}if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS) ||(h->mb_y >= h->mb_height && h->mb_height)) {if ((ret = ff_h264_field_end(h, &h->slice_ctx[0], 0)) < 0)return ret;/* Wait for second field. */if (h->next_output_pic) {ret = finalize_frame(h, pict, h->next_output_pic, got_frame);if (ret < 0)return ret;}}av_assert0(pict->buf[0] || !*got_frame);ff_h264_unref_picture(h, &h->last_pic_for_ec);return get_consumed_bytes(buf_index, buf_size);
}

int av_packet_shrink_side_data(AVPacket* pkt, enum AVPacketSideDataType type, 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);

源碼

int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,size_t size)
{int i;for (i = 0; i < pkt->side_data_elems; i++) {if (pkt->side_data[i].type == type) {if (size > pkt->side_data[i].size)return AVERROR(ENOMEM);pkt->side_data[i].size = size;return 0;}}return AVERROR(ENOENT);
}

使用,看到只有在mpegvideo_enc.c中有使用,應(yīng)該和上述的 av_packet_new_side_data和 av_packet_add_side_data 相關(guān),

int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt,const AVFrame *pic_arg, int *got_packet)
{MpegEncContext *s = avctx->priv_data;int i, stuffing_count, ret;int context_count = s->slice_context_count;s->vbv_ignore_qmax = 0;s->picture_in_gop_number++;if (load_input_picture(s, pic_arg) < 0)return -1;if (select_input_picture(s) < 0) {return -1;}/* output? */if (s->new_picture->data[0]) {int growing_buffer = context_count == 1 && !s->data_partitioning;size_t pkt_size = 10000 + s->mb_width * s->mb_height *(growing_buffer ? 64 : (MAX_MB_BYTES + 100));if (CONFIG_MJPEG_ENCODER && avctx->codec_id == AV_CODEC_ID_MJPEG) {ret = ff_mjpeg_add_icc_profile_size(avctx, s->new_picture, &pkt_size);if (ret < 0)return ret;}if ((ret = ff_alloc_packet(avctx, pkt, pkt_size)) < 0)return ret;pkt->size = avctx->internal->byte_buffer_size - AV_INPUT_BUFFER_PADDING_SIZE;if (s->mb_info) {s->mb_info_ptr = av_packet_new_side_data(pkt,AV_PKT_DATA_H263_MB_INFO,s->mb_width*s->mb_height*12);s->prev_mb_info = s->last_mb_info = s->mb_info_size = 0;}for (i = 0; i < context_count; i++) {int start_y = s->thread_context[i]->start_mb_y;int   end_y = s->thread_context[i]->  end_mb_y;int h       = s->mb_height;uint8_t *start = pkt->data + (size_t)(((int64_t) pkt->size) * start_y / h);uint8_t *end   = pkt->data + (size_t)(((int64_t) pkt->size) *   end_y / h);init_put_bits(&s->thread_context[i]->pb, start, end - start);}s->pict_type = s->new_picture->pict_type;//emms_c();ret = frame_start(s);if (ret < 0)return ret;
vbv_retry:ret = encode_picture(s);if (growing_buffer) {av_assert0(s->pb.buf == avctx->internal->byte_buffer);pkt->data = s->pb.buf;pkt->size = avctx->internal->byte_buffer_size;}if (ret < 0)return -1;frame_end(s);if ((CONFIG_MJPEG_ENCODER || CONFIG_AMV_ENCODER) && s->out_format == FMT_MJPEG)ff_mjpeg_encode_picture_trailer(&s->pb, s->header_bits);if (avctx->rc_buffer_size) {RateControlContext *rcc = &s->rc_context;int max_size = FFMAX(rcc->buffer_index * avctx->rc_max_available_vbv_use, rcc->buffer_index - 500);int hq = (avctx->mb_decision == FF_MB_DECISION_RD || avctx->trellis);int min_step = hq ? 1 : (1<<(FF_LAMBDA_SHIFT + 7))/139;if (put_bits_count(&s->pb) > max_size &&s->lambda < s->lmax) {s->next_lambda = FFMAX(s->lambda + min_step, s->lambda *(s->qscale + 1) / s->qscale);if (s->adaptive_quant) {int i;for (i = 0; i < s->mb_height * s->mb_stride; i++)s->lambda_table[i] =FFMAX(s->lambda_table[i] + min_step,s->lambda_table[i] * (s->qscale + 1) /s->qscale);}s->mb_skipped = 0;        // done in frame_start()// done in encode_picture() so we must undo itif (s->pict_type == AV_PICTURE_TYPE_P) {if (s->flipflop_rounding          ||s->codec_id == AV_CODEC_ID_H263P ||s->codec_id == AV_CODEC_ID_MPEG4)s->no_rounding ^= 1;}if (s->pict_type != AV_PICTURE_TYPE_B) {s->time_base       = s->last_time_base;s->last_non_b_time = s->time - s->pp_time;}for (i = 0; i < context_count; i++) {PutBitContext *pb = &s->thread_context[i]->pb;init_put_bits(pb, pb->buf, pb->buf_end - pb->buf);}s->vbv_ignore_qmax = 1;av_log(avctx, AV_LOG_VERBOSE, "reencoding frame due to VBV\n");goto vbv_retry;}av_assert0(avctx->rc_max_rate);}if (avctx->flags & AV_CODEC_FLAG_PASS1)ff_write_pass1_stats(s);for (i = 0; i < 4; i++) {avctx->error[i] += s->encoding_error[i];}ff_side_data_set_encoder_stats(pkt, s->current_picture.f->quality,s->encoding_error,(avctx->flags&AV_CODEC_FLAG_PSNR) ? MPEGVIDEO_MAX_PLANES : 0,s->pict_type);if (avctx->flags & AV_CODEC_FLAG_PASS1)assert(put_bits_count(&s->pb) == s->header_bits + s->mv_bits +s->misc_bits + s->i_tex_bits +s->p_tex_bits);flush_put_bits(&s->pb);s->frame_bits  = put_bits_count(&s->pb);stuffing_count = ff_vbv_update(s, s->frame_bits);s->stuffing_bits = 8*stuffing_count;if (stuffing_count) {if (put_bytes_left(&s->pb, 0) < stuffing_count + 50) {av_log(avctx, AV_LOG_ERROR, "stuffing too large\n");return -1;}switch (s->codec_id) {case AV_CODEC_ID_MPEG1VIDEO:case AV_CODEC_ID_MPEG2VIDEO:while (stuffing_count--) {put_bits(&s->pb, 8, 0);}break;case AV_CODEC_ID_MPEG4:put_bits(&s->pb, 16, 0);put_bits(&s->pb, 16, 0x1C3);stuffing_count -= 4;while (stuffing_count--) {put_bits(&s->pb, 8, 0xFF);}break;default:av_log(avctx, AV_LOG_ERROR, "vbv buffer overflow\n");s->stuffing_bits = 0;}flush_put_bits(&s->pb);s->frame_bits  = put_bits_count(&s->pb);}/* update MPEG-1/2 vbv_delay for CBR */if (avctx->rc_max_rate                          &&avctx->rc_min_rate == avctx->rc_max_rate &&s->out_format == FMT_MPEG1                     &&90000LL * (avctx->rc_buffer_size - 1) <=avctx->rc_max_rate * 0xFFFFLL) {AVCPBProperties *props;size_t props_size;int vbv_delay, min_delay;double inbits  = avctx->rc_max_rate *av_q2d(avctx->time_base);int    minbits = s->frame_bits - 8 *(s->vbv_delay_pos - 1);double bits    = s->rc_context.buffer_index + minbits - inbits;uint8_t *const vbv_delay_ptr = s->pb.buf + s->vbv_delay_pos;if (bits < 0)av_log(avctx, AV_LOG_ERROR,"Internal error, negative bits\n");av_assert1(s->repeat_first_field == 0);vbv_delay = bits * 90000 / avctx->rc_max_rate;min_delay = (minbits * 90000LL + avctx->rc_max_rate - 1) /avctx->rc_max_rate;vbv_delay = FFMAX(vbv_delay, min_delay);av_assert0(vbv_delay < 0xFFFF);vbv_delay_ptr[0] &= 0xF8;vbv_delay_ptr[0] |= vbv_delay >> 13;vbv_delay_ptr[1]  = vbv_delay >> 5;vbv_delay_ptr[2] &= 0x07;vbv_delay_ptr[2] |= vbv_delay << 3;props = av_cpb_properties_alloc(&props_size);if (!props)return AVERROR(ENOMEM);props->vbv_delay = vbv_delay * 300;ret = av_packet_add_side_data(pkt, AV_PKT_DATA_CPB_PROPERTIES,(uint8_t*)props, props_size);if (ret < 0) {av_freep(&props);return ret;}}s->total_bits     += s->frame_bits;pkt->pts = s->current_picture.f->pts;pkt->duration = s->current_picture.f->duration;if (!s->low_delay && s->pict_type != AV_PICTURE_TYPE_B) {if (!s->current_picture.coded_picture_number)pkt->dts = pkt->pts - s->dts_delta;elsepkt->dts = s->reordered_pts;s->reordered_pts = pkt->pts;} elsepkt->dts = pkt->pts;// the no-delay case is handled in generic codeif (avctx->codec->capabilities & AV_CODEC_CAP_DELAY) {ret = ff_encode_reordered_opaque(avctx, pkt, s->current_picture.f);if (ret < 0)return ret;}if (s->current_picture.f->key_frame)pkt->flags |= AV_PKT_FLAG_KEY;if (s->mb_info)av_packet_shrink_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, s->mb_info_size);} else {s->frame_bits = 0;}/* release non-reference frames */for (i = 0; i < MAX_PICTURE_COUNT; i++) {if (!s->picture[i].reference)ff_mpeg_unref_picture(avctx, &s->picture[i]);}av_assert1((s->frame_bits & 7) == 0);pkt->size = s->frame_bits / 8;*got_packet = !!pkt->size;return 0;
}

const char *av_packet_side_data_name(enum AVPacketSideDataType type);

const char *av_packet_side_data_name(enum AVPacketSideDataType type);

實現(xiàn):

const char *av_packet_side_data_name(enum AVPacketSideDataType type)
{switch(type) {case AV_PKT_DATA_PALETTE:                    return "Palette";case AV_PKT_DATA_NEW_EXTRADATA:              return "New Extradata";case AV_PKT_DATA_PARAM_CHANGE:               return "Param Change";case AV_PKT_DATA_H263_MB_INFO:               return "H263 MB Info";case AV_PKT_DATA_REPLAYGAIN:                 return "Replay Gain";case AV_PKT_DATA_DISPLAYMATRIX:              return "Display Matrix";case AV_PKT_DATA_STEREO3D:                   return "Stereo 3D";case AV_PKT_DATA_AUDIO_SERVICE_TYPE:         return "Audio Service Type";case AV_PKT_DATA_QUALITY_STATS:              return "Quality stats";case AV_PKT_DATA_FALLBACK_TRACK:             return "Fallback track";case AV_PKT_DATA_CPB_PROPERTIES:             return "CPB properties";case AV_PKT_DATA_SKIP_SAMPLES:               return "Skip Samples";case AV_PKT_DATA_JP_DUALMONO:                return "JP Dual Mono";case AV_PKT_DATA_STRINGS_METADATA:           return "Strings Metadata";case AV_PKT_DATA_SUBTITLE_POSITION:          return "Subtitle Position";case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL:   return "Matroska BlockAdditional";case AV_PKT_DATA_WEBVTT_IDENTIFIER:          return "WebVTT ID";case AV_PKT_DATA_WEBVTT_SETTINGS:            return "WebVTT Settings";case AV_PKT_DATA_METADATA_UPDATE:            return "Metadata Update";case AV_PKT_DATA_MPEGTS_STREAM_ID:           return "MPEGTS Stream ID";case AV_PKT_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata";case AV_PKT_DATA_CONTENT_LIGHT_LEVEL:        return "Content light level metadata";case AV_PKT_DATA_SPHERICAL:                  return "Spherical Mapping";case AV_PKT_DATA_A53_CC:                     return "A53 Closed Captions";case AV_PKT_DATA_ENCRYPTION_INIT_INFO:       return "Encryption initialization data";case AV_PKT_DATA_ENCRYPTION_INFO:            return "Encryption info";case AV_PKT_DATA_AFD:                        return "Active Format Description data";case AV_PKT_DATA_PRFT:                       return "Producer Reference Time";case AV_PKT_DATA_ICC_PROFILE:                return "ICC Profile";case AV_PKT_DATA_DOVI_CONF:                  return "DOVI configuration record";case AV_PKT_DATA_S12M_TIMECODE:              return "SMPTE ST 12-1:2014 timecode";case AV_PKT_DATA_DYNAMIC_HDR10_PLUS:         return "HDR10+ Dynamic Metadata (SMPTE 2094-40)";}return NULL;
}

uint8_t* av_packet_pack_dictionary(AVDictionary* dict, size_t* size);

AVDictioary中的數(shù)據(jù)放到一整塊內(nèi)存并返回;

返回值是 avpacket->data_side_data 的指針。

實際開發(fā)中 需要再給返回值 copy 數(shù)據(jù)才算完成

/*** 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);

源碼實現(xiàn)

uint8_t *av_packet_pack_dictionary(AVDictionary *dict, size_t *size)
{uint8_t *data = NULL;*size = 0;if (!dict)return NULL;for (int pass = 0; pass < 2; pass++) {const AVDictionaryEntry *t = NULL;size_t total_length = 0;while ((t = av_dict_iterate(dict, t))) {for (int i = 0; i < 2; i++) {const char  *str = i ? t->value : t->key;const size_t len = strlen(str) + 1;if (pass)memcpy(data + total_length, str, len);else if (len > SIZE_MAX - total_length)return NULL;total_length += len;}}if (pass)break;data = av_malloc(total_length);if (!data)return NULL;*size = total_length;}return data;
}

參考 av_packet_add_side_data 中例子。

int av_packet_unpack_dictionary(const uint8_t* data, size_t size,
? ? AVDictionary** dict);

從一整塊數(shù)據(jù)中解析出一個AVDictionary

實際上主要是給?dict 中傳遞數(shù)據(jù)解析 AVDictionary中 。

/*** 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);

int av_packet_unpack_dictionary(const uint8_t *data, size_t size,AVDictionary **dict)
{const uint8_t *end;int ret;if (!dict || !data || !size)return 0;end = data + size;if (size && end[-1])return AVERROR_INVALIDDATA;while (data < end) {const uint8_t *key = data;const uint8_t *val = data + strlen(key) + 1;if (val >= end || !*key)return AVERROR_INVALIDDATA;ret = av_dict_set(dict, key, val, 0);if (ret < 0)return ret;data = val + strlen(val) + 1;}return 0;
}

void av_packet_free_side_data(AVPacket* pkt);

/*** 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);

實現(xiàn)

void av_packet_free_side_data(AVPacket *pkt)
{int i;for (i = 0; i < pkt->side_data_elems; i++)av_freep(&pkt->side_data[i].data);av_freep(&pkt->side_data);pkt->side_data_elems = 0;
}

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

引用計數(shù)加一

/*** 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);

源碼

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;
}

void av_packet_unref(AVPacket* pkt);

引用計數(shù)減一

/*** 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);

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);
}

void av_packet_move_ref(AVPacket* dst, AVPacket* src);

引用計數(shù)不變,將src 的所有東西都轉(zhuǎn)移給dst,然后將src 的值都恢復(fù)成默認(rèn)值

那么move 之后,src就不能使用了

/*** 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);

void av_packet_move_ref(AVPacket *dst, AVPacket *src)
{*dst = *src;get_packet_defaults(src);
}

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

將src 中 "properties" 的字段拷貝給 dst,那么哪些屬于是?"properties"呢?---》參考源碼

/*** 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);

實現(xiàn):

int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
{int i, ret;dst->pts                  = src->pts;dst->dts                  = src->dts;dst->pos                  = src->pos;dst->duration             = src->duration;dst->flags                = src->flags;dst->stream_index         = src->stream_index;dst->opaque               = src->opaque;dst->time_base            = src->time_base;dst->opaque_ref           = NULL;dst->side_data            = NULL;dst->side_data_elems      = 0;ret = av_buffer_replace(&dst->opaque_ref, src->opaque_ref);if (ret < 0)return ret;for (i = 0; i < src->side_data_elems; i++) {enum AVPacketSideDataType type = src->side_data[i].type;size_t size = src->side_data[i].size;uint8_t *src_data = src->side_data[i].data;uint8_t *dst_data = av_packet_new_side_data(dst, type, size);if (!dst_data) {av_buffer_unref(&dst->opaque_ref);av_packet_free_side_data(dst);return AVERROR(ENOMEM);}memcpy(dst_data, src_data, size);}return 0;
}

?int av_packet_make_writable(AVPacket *pkt);

從實現(xiàn)來看:如果傳遞的參數(shù)pkt? 的 字段 ------ AVBufferRef *buf 不為null 且是可以寫的,則直接返回0. AVPacket是否可寫:對應(yīng)的flags 非AV_BUFFER_FLAG_READONLY

如果buf 是null 或者不可寫,則重新 alloc buf,并且傳遞給 pkt,總的來說,這個函數(shù)就是讓 你傳進(jìn)來的pkt 的 buf字段變成可寫的,將引用計數(shù)變?yōu)?

/*** 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);

實現(xiàn)

int av_packet_make_writable(AVPacket *pkt)
{AVBufferRef *buf = NULL;int ret;if (pkt->buf && av_buffer_is_writable(pkt->buf))return 0;ret = packet_alloc(&buf, pkt->size);if (ret < 0)return ret;av_assert1(!pkt->size || pkt->data);if (pkt->size)memcpy(buf->data, pkt->data, pkt->size);av_buffer_unref(&pkt->buf);pkt->buf  = buf;pkt->data = buf->data;return 0;
}


?

int av_packet_make_refcounted(AVPacket* pkt);

如果沒有buf字段為null,則根據(jù)size 重新create buf,并將這個buf賦值給pkt的字段,最后將將引用計數(shù)變?yōu)?

/*** 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);

int av_packet_make_refcounted(AVPacket *pkt)
{int ret;if (pkt->buf)return 0;ret = packet_alloc(&pkt->buf, pkt->size);if (ret < 0)return ret;av_assert1(!pkt->size || pkt->data);if (pkt->size)memcpy(pkt->buf->data, pkt->data, pkt->size);pkt->data = pkt->buf->data;return 0;
}

void av_packet_rescale_ts(AVPacket* pkt, AVRational tb_src, AVRational tb_dst);

/*** 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);

實現(xiàn):

void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
{if (pkt->pts != AV_NOPTS_VALUE)pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);if (pkt->dts != AV_NOPTS_VALUE)pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);if (pkt->duration > 0)pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
}

?參考

從零到一學(xué)FFmpeg:av_packet_rescale_ts 函數(shù)詳析與實戰(zhàn)_avpacket 時間戳-CSDN博客

av_packet_rescale_ts是FFmpeg庫中的一個函數(shù),用于重新縮放或轉(zhuǎn)換媒體流中的時間戳(timestamp),以適配不同的時間基(timebase)。
在處理多媒體數(shù)據(jù)時,特別是當(dāng)數(shù)據(jù)在不同組件間傳遞,或者在編碼、解碼、轉(zhuǎn)封裝等操作中,時間戳經(jīng)常需要調(diào)整以匹配當(dāng)前上下文的時間基。

參數(shù)說明

pkt: 指向AVPacket結(jié)構(gòu)體的指針,該結(jié)構(gòu)體包含了要調(diào)整時間戳的媒體數(shù)據(jù)包。
tb_src: 原始時間基,即pkt中時間戳所依據(jù)的時間基。
?? ?通常,這來自于數(shù)據(jù)包來源的AVStream的time_base。
tb_dst: 目標(biāo)時間基,即你想將時間戳轉(zhuǎn)換到的時間基。
?? ?這通常與你打算將數(shù)據(jù)包發(fā)送到的目標(biāo)組件(如解碼器、輸出格式上下文等)的時間基相匹配。

二、功能描述
時間戳轉(zhuǎn)換: 該函數(shù)通過計算兩個時間基之間的比例,對AVPacket中的pts(顯示時間戳)和dts(解碼時間戳)進(jìn)行相應(yīng)的縮放。這對于確保媒體處理管道中各環(huán)節(jié)的時間戳一致性至關(guān)重要。

同步與播放: 時間戳的正確調(diào)整對于視頻和音頻的同步播放非常重要,尤其是在涉及不同速率或格式轉(zhuǎn)換的場景下。

三、使用實例
僅調(diào)整時間戳,不對數(shù)據(jù)包內(nèi)的數(shù)據(jù)進(jìn)行任何修改。
確保tb_src和tb_dst都是有效的AVRational結(jié)構(gòu)體,避免除以零的錯誤。
在進(jìn)行解復(fù)用、編碼、解碼或復(fù)用等操作前后,通常需要調(diào)用此函數(shù)來適配不同的時間基需求。

AVPacket pkt;
// 假設(shè)pkt是從某個輸入流中獲取的,已帶有基于該流時間基的時間戳
AVRational in_timebase = (AVRational){1, 25}; // 假設(shè)輸入時間基為25fps
AVRational out_timebase = (AVRational){1, 1000}; // 假設(shè)目標(biāo)時間基為毫秒單位// 調(diào)整時間戳
av_packet_rescale_ts(&pkt, in_timebase, out_timebase);// 現(xiàn)在pkt的時間戳已轉(zhuǎn)換為目標(biāo)時間基,可以安全地用于輸出或進(jìn)一步處理

http://m.risenshineclean.com/news/60984.html

相關(guān)文章:

  • 簡述網(wǎng)站內(nèi)容管理流程程序員培訓(xùn)機(jī)構(gòu)排名前十
  • 企業(yè)做一個網(wǎng)站多少錢網(wǎng)易企業(yè)郵箱
  • 石家莊做網(wǎng)站制作公司重慶百度推廣開戶
  • 中國疫情最嚴(yán)重的五個省排名湖北百度seo排名
  • 手機(jī)app網(wǎng)站模板余姚網(wǎng)站如何進(jìn)行優(yōu)化
  • 網(wǎng)站建設(shè)捌金手指花總十一整合網(wǎng)絡(luò)營銷是什么
  • 易支付做網(wǎng)站接口怎么賺錢網(wǎng)絡(luò)營銷策略理論
  • 一個網(wǎng)站怎么留住用戶專業(yè)網(wǎng)站建設(shè)公司
  • 你去湖北省住房城鄉(xiāng)建設(shè)廳網(wǎng)站查seo專員很難嗎
  • 動態(tài)ip上做網(wǎng)站網(wǎng)絡(luò)軟文是什么意思
  • 做網(wǎng)站 做好把我踢開長沙百度網(wǎng)站排名優(yōu)化
  • 建設(shè)網(wǎng)站需要哪些人獨(dú)立站seo推廣
  • 珠海市城市建設(shè)檔案館網(wǎng)站seo優(yōu)化標(biāo)題 關(guān)鍵詞
  • 我國現(xiàn)在疫情防控現(xiàn)狀搜索引擎優(yōu)化公司排行
  • 網(wǎng)站建設(shè)常見問題及解決辦法廈門網(wǎng)站建設(shè)
  • 攝影網(wǎng)頁設(shè)計方案win7優(yōu)化設(shè)置
  • 怎么創(chuàng)辦自己的網(wǎng)站云搜索網(wǎng)頁版入口
  • 設(shè)計好看的美食網(wǎng)站有哪些百度廣告投放收費(fèi)標(biāo)準(zhǔn)
  • 寧國市有做網(wǎng)站推廣賺傭金項目
  • 戈韋思網(wǎng)站建設(shè)優(yōu)化網(wǎng)站推廣教程排名
  • 上海網(wǎng)站建設(shè)公司四葉互聯(lián)網(wǎng)站運(yùn)營工作的基本內(nèi)容
  • 張家界網(wǎng)站建設(shè)多少錢大連網(wǎng)站排名推廣
  • 手機(jī)網(wǎng)站解析天津百度網(wǎng)站排名優(yōu)化
  • 我愛做媽媽網(wǎng)站磁力天堂
  • 黃山旅游攻略一日游最佳路線排名seo怎么樣
  • 網(wǎng)站難做嗎推動高質(zhì)量發(fā)展
  • 南聯(lián)網(wǎng)站建設(shè)哪家好seo是什么意思新手怎么做seo
  • 高端網(wǎng)站建設(shè)深圳寧德市屬于哪個省份
  • 網(wǎng)站方案策劃怎么寫免費(fèi)網(wǎng)站推廣軟件下載
  • 怎么樣提高網(wǎng)站點擊率高明公司搜索seo