结构体如下:
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; //用来管理data指针引用的数据缓存,通过av_packet_ref() 和 av_packet_unref() //来使buf->buffer->refcount成员引用计数+-,如果引用计数为0,则释放buffer. /** * 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; //显示时间戳,需要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒) //比如dpts = av_q2d(AVStream->time_base) * AVPacket->pts; int64_t dts; //解码时间戳,需要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒) uint8_t *data; //压缩编码的数据。 int size; //data的大小 int stream_index; //标识该AVPacket所属的视频/音频流 int flags; //标识,结合AV_PKT_FLAG使用,比如: //#define AV_PKT_FLAG_KEY 0x0001 //关键帧 //#define AV_PKT_FLAG_CORRUPT 0x0002 //损坏的数据 //#define AV_PKT_FLAG_DISCARD 0x0004 /丢弃的数据 /** * 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; //数据的时长,需要所属媒体流AVStream的time_base时基来换算出当前的标准时间,未知则值为默认值0 int64_t pos; //数据在流媒体中的位置,未知则值为默认值-1 }AVPacket;
AVPacket常用函数如下:
AVPacket *av_packet_alloc(void) { AVPacket *pkt = av_mallocz(sizeof(AVPacket)); if (!pkt) return pkt; av_packet_unref(pkt); return pkt; }
创建一个AVPacket的实例,但该函数并不会为数据分配空间,其指向数据域的指针为NULL。
void av_packet_free(AVPacket **pkt) { if (!pkt || !*pkt) return; av_packet_unref(*pkt); av_freep(pkt); }
首先将AVPacket->buf->buffer->refcount成员减1(数据域的引用技术减为0时会自动释放),然后再释放为AVPacket分配的空间。
int av_packet_ref(AVPacket *dst, const AVPacket *src) { int ret; ret = av_packet_copy_props(dst, src); //复制部分成员(比如:pts,dts,pos,duration,side_data)到dst if (ret < 0) return ret; if (!src->buf) { //如果src->buf为空,则为dst新分配一个数据域,并将src->data复制到dst->buf->data 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 { //不为空,则调用av_buffer_ref()来使引用+1,并将dst->buf指向src->buf, dst->buf = av_buffer_ref(src->buf); if (!dst->buf) { ret = AVERROR(ENOMEM); goto fail; } dst->data = src->data; //然后将src->data复制到dst->data中 } dst->size = src->size; return 0; fail: av_packet_free_side_data(dst); return ret; }
av_packet_ref根据src来创建一个新的AVPacket
void av_packet_unref(AVPacket *pkt) { av_packet_free_side_data(pkt); av_buffer_unref(&pkt->buf); av_init_packet(pkt); pkt->data = NULL; pkt->size = 0; }
将AVPacket->buf->buffer->refcount成员减1(数据域的引用技术减为0时会自动释放),替代了旧api(av_free_packet)
AVPacket解码示例:
AVPacket *packet = av_packet_alloc(); // 创建一个packet while(av_read_frame(pFormatCtx,packet)) { if(packet->stream_index == audio_index) { ... } else if(packet->stream_index == video_index) { ... } av_packet_unref(packet); // 也可以使用旧api:av_free_packet } av_packet_free(packet); //释放packet,如果还想使用,则需要重新alloc