每一个包是一个完整的数据帧,来暂存解复用之后、解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等)
//注意保存音视频数据包的内存
是 malloc 出来的,用完后应及时用 free 归还给系统
typedef struct AVPacket { int64_t pts; int64_t dts; int64_t pos; uint8_t *data;//数据首地址 int size; int stream_index; int flags;//flags为标志域,1表示该数据是一个关键帧 void(*destruct)(struct AVPacket*);//释放数据缓冲区的函数指针 } AVPacket;
AVPacket本身只是个容器,它data成员引用实际的数据缓冲区。这个缓冲区通常是由av_new_packet创建的,但也可能由 FFMPEG的API创建(如av_read_frame)。当某个AVPacket结构的数据缓冲区不再被使用时,要需要通过调用 av_free_packet释放
而av_new_packet实现如下:(也有 av_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->convergence_duration = 0; pkt->flags = 0; pkt->stream_index = 0; #if FF_API_DESTRUCT_PACKET pkt->destruct = NULL; #endif pkt->buf = NULL; // 数据域没有, 为空 pkt->side_data = NULL; pkt->side_data_elems = 0; } int av_new_packet(AVPacket *pkt, int size) { AVBufferRef *buf = NULL; //判断size是否正确 if ((unsigned)size >= (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE) return AVERROR(EINVAL); //分配size大小 av_buffer_realloc(&buf, size + FF_INPUT_BUFFER_PADDING_SIZE); if (!buf) return AVERROR(ENOMEM); memset(buf->data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); av_init_packet(pkt); pkt->buf = buf; pkt->data = buf->data; //data域大小 pkt->size = size; #if FF_API_DESTRUCT_PACKET pkt->destruct = dummy_destruct_packet; #endif return 0; }
av_free_packet实现:
static inline void av_free_packet(AVPacket *pkt) { if (pkt && pkt->destruct) pkt->destruct(pkt); }
AVPacketList 仅含有一个 AVPacket,和传统的很多很多节点的 list
不同,不要被 list 名字迷惑。
typedef struct AVPacketList { AVPacket pkt; struct AVPacketList *next; // 用于把各个 AVPacketList 串联起来。 } AVPacketList;