FFmpeg 中AVPacket的使用

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的值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章