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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM