• FFmpeg-AVPacket使用


    1.使用注意api

    •    AVPacket须要用户经过av_packet_allc()建立好空间后.才能供给fimpeg进行获取解码前帧数据,因为解码前帧数据大小是不固定的(好比I帧数据量最大)因此ffmpeg会在AVPacket的成员里动态进行建立空间.
    •   而且咱们每一次使用完AVPacket后(再次调用av_read_frame()读取新帧以前),必需要经过av_packet_unref()引用技术对AVPacket里的成员来手动清理.
    •   解码完成或者退出播放后,还要调用av_packet_free()来释放AVPacket自己.

    2.结构体以下:缓存

    1. typedef struct AVPacket{
    2. /**
    3. * A reference to the reference-counted buffer where the packet data is
    4. * stored.
    5. * May be NULL, then the packet data is not reference-counted.
    6. */
    7. AVBufferRef *buf;
    8. //用来管理data指针引用的数据缓存,经过av_packet_ref() 和 av_packet_unref()
    9. //来使buf->buffer->refcount成员引用计数+-,若是引用计数为0,则释放buffer.
    10. //而buf->buffer存储的则是ffmpeg读取出来的未解码数据
    11. /**
    12. * Presentation timestamp in AVStream->time_base units; the time at which
    13. * the decompressed packet will be presented to the user.
    14. * Can be AV_NOPTS_VALUE if it is not stored in the file.
    15. * pts MUST be larger or equal to dts as presentation cannot happen before
    16. * decompression, unless one wants to view hex dumps. Some formats misuse
    17. * the terms dts and pts/cts to mean something different. Such timestamps
    18. * must be converted to true pts/dts before they are stored in AVPacket.
    19. */
    20. int64_t pts;
    21. //显示时间戳,须要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒)
    22. //好比dpts = av_q2d(AVStream->time_base) * AVPacket->pts;
    23. int64_t dts; //解码时间戳,须要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒)
    24. uint8_t *data; //指向未解码数据(实际指向buf->buffer所指向的地址)
    25. int size; //data的大小
    26. int stream_index; //标识该AVPacket所属的视频/音频流
    27. int flags; //标识,结合AV_PKT_FLAG使用,好比:
    28. //#define AV_PKT_FLAG_KEY 0x0001 关键帧
    29. //#define AV_PKT_FLAG_CORRUPT 0x0002 损坏的数据
    30. //#define AV_PKT_FLAG_DISCARD 0x0004 丢弃的数据
    31. /**
    32. * Additional packet data that can be provided by the container.
    33. * Packet can contain several types of side information. */
    34. AVPacketSideData *side_data; //容器提供的一些附加数据
    35. int side_data_elems; //边缘数据元数个数
    36. /**
    37. * Duration of this packet in AVStream->time_base units, 0 if unknown.
    38. * Equals next_pts - this_pts in presentation order. */
    39. int64_t duration; //数据的时长,须要所属媒体流AVStream的time_base时基来换算出当前的标准时间,未知则值为默认值0
    40. int64_t pos; //数据在流媒体中的位置,未知则值为默认值-1
    41. }AVPacket;

    3.AVPacket经常使用函数以下:app

    • av_packet_alloc(): 初始化
    • av_packet_unref(): 引用减1.若为0则释放压缩数据
    • av_packet_free():释放AVPacket自己
    • av_packet_ref(): 从src复制到一个初始化好的dst中,并引用+1
    • av_packet_clone(): 建立并返回一个复制好的AVPacket(在音视频同步处理中用到该函数)
    • av_packet_from_data(AVPacket *pkt, uint8_t *data, int size): 经过压缩数据来初始化一个AVPacket(pkt必须是建立好的),通常在读取流媒体时使用,由于解码函数的参数必须是AVPacket.

     音视频免费学习资料包,在文章最后领取。

    4.AVPacket解码示例:less

    1. AVPacket *packet = av_packet_alloc(); // 建立一个packet
    2. while(av_read_frame(pFormatCtx,packet))
    3. {
    4. if(packet->stream_index == audio_index)
    5. {
    6. ...
    7. }
    8. else if(packet->stream_index == video_index)
    9. {
    10. ...
    11. }
    12. av_packet_unref(packet); // 引用计数-1,若是为0,则释放压缩数据所在的空间
    13. }
    14. av_packet_free(packet); //释放packet,若是还想使用,则须要从新alloc

    5.AVPacket函数分析ide

    av_packet_alloc():初始化函数

    1. AVPacket *av_packet_alloc(void)
    2. {
    3. AVPacket *pkt = av_mallocz(sizeof(AVPacket));
    4. if (!pkt)
    5. return pkt;
    6. av_packet_unref(pkt);
    7. return pkt;
    8. }

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

    av_packet_unref():引用减1.若为0则释放压缩数据this

    1. void av_packet_unref(AVPacket *pkt)
    2. {
    3. av_packet_free_side_data(pkt);
    4. av_buffer_unref(&pkt->buf);
    5. av_init_packet(pkt);
    6. pkt->data = NULL;
    7. pkt->size = 0;
    8. }

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

    av_packet_free():释放AVPacket自己指针

    1. void av_packet_free(AVPacket **pkt)
    2. {
    3. if (!pkt || !*pkt)
    4. return;
    5. av_packet_unref(*pkt);
    6. av_freep(pkt);
    7. }

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

    av_packet_ref():从src复制到一个初始化好的dst中,并引用+1

    1. int av_packet_ref(AVPacket *dst, const AVPacket *src)
    2. {
    3. int ret;
    4. ret = av_packet_copy_props(dst, src); //复制部分红员(好比:pts,dts,pos,duration,side_data)到dst
    5. if (ret < 0)
    6. return ret;
    7. if (!src->buf) { //若是src->buf为空,则为dst新分配一个数据域,并将src->data复制到dst->buf->data
    8. ret = packet_alloc(&dst->buf, src->size);
    9. if (ret < 0)
    10. goto fail;
    11. av_assert1(!src->size || src->data);
    12. if (src->size)
    13. memcpy(dst->buf->data, src->data, src->size);
    14. dst->data = dst->buf->data;
    15. } else { //不为空,则调用av_buffer_ref()来使引用+1,并将dst->buf指向src->buf,
    16. dst->buf = av_buffer_ref(src->buf);
    17. if (!dst->buf) {
    18. ret = AVERROR(ENOMEM);
    19. goto fail;
    20. }
    21. dst->data = src->data; //而后将src->data复制到dst->data
    22. }
    23. dst->size = src->size;
    24. return 0;
    25. fail:
    26. av_packet_free_side_data(dst);
    27. return ret;
    28. }

    av_packet_ref将src内容复制到一个建立好的dst中.须要注意: dst必须提早已经注册好

    av_packet_clone():建立并返回一个复制好的AVPacket(在音视频同步处理中用到该函数)

    1. AVPacket *av_packet_clone(const AVPacket *src)
    2. {
    3. AVPacket *ret = av_packet_alloc();
    4. if (!ret)
    5. return ret;
    6. if (av_packet_ref(ret, src))
    7. av_packet_free(&ret);
    8. return ret;
    9. }

    av_packet_from_data(AVPacket *pkt, uint8_t *data, int size): 经过压缩数据来初始化一个AVPacket(pkt必须是建立好的),通常在读取流媒体时使用,由于解码函数的参数必须是AVPacket.

    1. int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
    2. {
    3. if (size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
    4. return AVERROR(EINVAL);
    5. pkt->buf = av_buffer_create(data, size + AV_INPUT_BUFFER_PADDING_SIZE,
    6. av_buffer_default_free, NULL, 0); //建立新的AVBufferRef,并初始化
    7. if (!pkt->buf)
    8. return AVERROR(ENOMEM);
    9. pkt->data = data;
    10. pkt->size = size;
    11. return 0;
    12. }

  • 相关阅读:
    前端必读3.0:如何在 Angular 中使用SpreadJS实现导入和导出 Excel 文件
    小地图的生成
    Python Opencv实践 - 入门使用Tesseract识别图片中的文字
    OpenCV4.9.0开源计算机视觉库在 Linux 中安装
    内网穿透 | 推荐两个免费的内网穿透工具
    Swingbench 压力测试(超详细)
    New Maven Project
    C++复习题(二级)
    Docker
    42.(后端)更新用户信息
  • 原文地址:https://blog.csdn.net/yinshipin007/article/details/126413656