AVPacket
保存的是解碼前的數據,也就是壓縮后的數據。該結構本身不直接包含數據,其有一個指向數據域的指針,FFmpeg中很多的數據結構都使用這種方法來管理數據。
AVPacket
的使用通常離不開下面4個函數:
-
使用
av_packet_alloc
來創建一個AVPacket
的實例,但該函數並不會為數據分配空間,其指向數據域的指針為NULL。
通常調用av_read_frame
將流中的數據讀取到AVPacket
中。 -
av_packet_free
void av_packet_free(AVPacket **pkt)
{
if (!pkt || !*pkt)
return;
av_packet_unref(*pkt);
av_freep(pkt);
}
首先將AVPacket指向的數據域的引用技術減1(數據域的引用技術減為0時會自動釋放)
接着,釋放為AVPacket
分配的空間。
av_packet_ref
int av_packet_ref(AVPacket *dst, const AVPacket *src)
{
int ret;
ret = av_packet_copy_props(dst, src);
if (ret < 0)
return ret;
if (!src->buf) {
ret = packet_alloc(&dst->buf, src->size);
if (ret < 0)
goto fail;
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_free_side_data(dst);
return ret;
}
將src的字段值復制給dst,如果src的數據域是基於引用計數的,則dst也引用該數據域,並將引用計數+1;如果不是,則為dst新分配一個數據域,並將src數據域的值復制過去。dst的數據域是基於引用計數的。
av_packet_free
替代 已被廢棄的av_free_packet
,其功能是將packet指向的數據域的引用技術減1,並將packe的值設為默認值。該函數並不會釋放packet的空間,釋放不使用的packet需要調用av_packet_free
。
解碼時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); // 不要忘記減少引用技術
}
av_packet_free(packet);
在使用av_packet_alloc
創建packet的時候,並沒有給數據域分配空間,數據域的空間實在av_read_frame
內分配的,所以在每次循環的結束不能忘記調用av_packet_unref
減少數據域的引用技術,當引用技術減為0時,會自動釋放數據域所占用的空間。在循環結束后,調用av_packet_free
來釋放AVPacket
本身所占用的空間。
將數據從流中讀取到packet的時候,通常需要緩存AVPacket
,也就意味着要轉移AVPacket
本身的字段值以及其指向的數據域的引用。
AVPacket *pkt = av_packet_alloc();
if (av_packet_ref(pkt, packet) < 0)
return false;
queue.push(*pkt);
緩存AVPacket
時,可以新創建一個AVPacket
實例,然后調用av_packet_ref
復制目標packet的值。