• 3.AVPacket使用


    结构体如下:

    typedef struct AVPacket{
    /**
    * A reference to the reference-counted buffer where the packet data is
    * stored.
    * May be NULL, then the packet data is not reference-counted.
    */
    AVBufferRef *buf;    
    //用来管理data指针引用的数据缓存,通过av_packet_ref() 和 av_packet_unref()
    //来使buf->buffer->refcount成员引用计数+-,如果引用计数为0,则释放buffer. 
    /**
    * Presentation timestamp in AVStream->time_base units; the time at which
    * the decompressed packet will be presented to the user.
    * Can be AV_NOPTS_VALUE if it is not stored in the file.
    * pts MUST be larger or equal to dts as presentation cannot happen before
    * decompression, unless one wants to view hex dumps. Some formats misuse
    * the terms dts and pts/cts to mean something different. Such timestamps
    * must be converted to true pts/dts before they are stored in AVPacket.
    */
    int64_t pts;    
    //显示时间戳,需要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒)
    //比如dpts = av_q2d(AVStream->time_base) * AVPacket->pts;
    
    int64_t dts;       //解码时间戳,需要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒)
    uint8_t *data;    //压缩编码的数据。
    int size;     //data的大小
    int stream_index;    //标识该AVPacket所属的视频/音频流
    
    int flags;    //标识,结合AV_PKT_FLAG使用,比如:
    //#define AV_PKT_FLAG_KEY 0x0001 //关键帧
    //#define AV_PKT_FLAG_CORRUPT 0x0002 //损坏的数据
    //#define AV_PKT_FLAG_DISCARD 0x0004 /丢弃的数据
    
    /**
    * Additional packet data that can be provided by the container.
    * Packet can contain several types of side information.
    */
    AVPacketSideData *side_data;    //容器提供的一些附加数据
    int side_data_elems;         //边缘数据元数个数
    
    /**
    * Duration of this packet in AVStream->time_base units, 0 if unknown.
    * Equals next_pts - this_pts in presentation order.
    */
    int64_t duration;    //数据的时长,需要所属媒体流AVStream的time_base时基来换算出当前的标准时间,未知则值为默认值0
    
    int64_t pos;        //数据在流媒体中的位置,未知则值为默认值-1
    
    }AVPacket;

    AVPacket常用函数如下:

    AVPacket *av_packet_alloc(void)
    {
       AVPacket *pkt = av_mallocz(sizeof(AVPacket));
       if (!pkt)
        return pkt;
    
       av_packet_unref(pkt);
    
       return pkt;
    }

    创建一个AVPacket的实例,但该函数并不会为数据分配空间,其指向数据域的指针为NULL。

    void av_packet_free(AVPacket **pkt)
    {
      if (!pkt || !*pkt)
        return;
    
      av_packet_unref(*pkt);
      av_freep(pkt);
    }

    首先将AVPacket->buf->buffer->refcount成员减1(数据域的引用技术减为0时会自动释放),然后再释放为AVPacket分配的空间。

    int av_packet_ref(AVPacket *dst, const AVPacket *src)
    {
      int ret;
    
      ret = av_packet_copy_props(dst, src); //复制部分成员(比如:pts,dts,pos,duration,side_data)到dst
      if (ret < 0)
        return ret;
    
      if (!src->buf) { //如果src->buf为空,则为dst新分配一个数据域,并将src->data复制到dst->buf->data
        ret = packet_alloc(&dst->buf, src->size);
      if (ret < 0)
       goto fail;
      av_assert1(!src->size || src->data);
      if (src->size)
        memcpy(dst->buf->data, src->data, src->size);
    
      dst->data = dst->buf->data;
     } else { //不为空,则调用av_buffer_ref()来使引用+1,并将dst->buf指向src->buf,
      dst->buf = av_buffer_ref(src->buf);
      if (!dst->buf) {
      ret = AVERROR(ENOMEM);
      goto fail;
     }
      dst->data = src->data;    //然后将src->data复制到dst->data中
     }
    
      dst->size = src->size;
    
      return 0;
      fail:
        av_packet_free_side_data(dst);
      return ret;
    }

    av_packet_ref根据src来创建一个新的AVPacket

    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;
    }

    将AVPacket->buf->buffer->refcount成员减1(数据域的引用技术减为0时会自动释放),替代了旧api(av_free_packet)

    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); // 也可以使用旧api:av_free_packet
    }
    av_packet_free(packet);    //释放packet,如果还想使用,则需要重新alloc
  • 相关阅读:
    文档加载完后执行相关事件
    流程步骤(备用)
    浏览器常见内核
    修改!important定义的样式(2)
    样式被!important 后修改的方法
    产生BFC环境的几种方式
    当我们访问一个网址后发生了什么?
    Java并发基础--线程通信
    Java 集合学习--ArrayList
    Java并发基础--线程安全
  • 原文地址:https://www.cnblogs.com/lifexy/p/13232299.html
Copyright © 2020-2023  润新知