文章目录
知识准备
AVPacket:存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据),简单来说就是携带一个NAL视频单元,或者多个NAL音频单元。 AVPacket保存一个NAL单元的解码前数据,该结构本身不直接包含数据,其有一个指向数据域的指针。传递给avcodec_send_packet函数的AVPacket结构体data中的数据前面是00 00 00 01开头,说明是NALU格式的数据
重要结构体成员分析
AVBufferRef *buf; //当前AVPacket中压缩数据的引用计数,以及保存压缩数据的指针地址(压缩数据申请的空间在这里)
uint8_t *data;//保存压缩数据的指针地址(data同时指向了buf中的data)
int size;//压缩数据的长度
int stream_index;//视频还是音频的索引
实战(构建包含一个NAL单元(长度为nLen)的AVPacket)
AVPacket pkt1, *packet = &pkt1;
//nLen压缩数据长度
av_new_packet(packet, nLen); //已经为packet->buf申请内存,而data和buf指向同一片内存
memcpy(packet->data, data, nLen);
packet->size = nLen;
packet->stream_index = 0;
然后就可以将packet加入链表等待解码出一帧数据,或者调用avcodec_decode_video2进行解码,解码之后,可以调用av_free_packet或者 av_packet_unref释放资源
释疑
1)为什么不直接对packet->data申请内存,然后进行数据的拷贝?按结构体中定义说明 AVBufferRef只是数据的引用计数,可以为NULL,代表没有任何的引用
所以上面的代码修改(不推荐
):
av_init_packet(packet);//初始化结构体,尤其是AVBufferRef *buf,避免
packet->data = (uint8_t *)malloc(sizeof(uint8_t)* nByte);
memcpy(packet->data, data, nLen);
packet->size = nLen;
packet->stream_index = 0;
注意:av_init_packet(packet);//初始化结构体,尤其是AVBufferRef *buf,避免在解码的时候,访问到非法的指针地址。
不推荐原因
:无法使用av_free_packet或者 av_packet_unref进行资源的释放,必须手动释放掉packet->data申请的内存,因为这两个函数释放资源针对的都是AVPacket结构体中的buf,而不是data
void av_free_packet(AVPacket *pkt)
{
if (pkt) {
if (pkt->buf)
av_buffer_unref(&pkt->buf);
pkt->data = NULL;
pkt->size = 0;
av_packet_free_side_data(pkt);
}
}
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;
}