FFMPEG AVPacket

本文深入探讨了FFMPEG中AVPacket结构的用途,解释了其关键属性如dts、pts、stream_index等,并阐述了如何在FFMPEG中正确使用AVPacket来管理解复用后的媒体数据。文章还详细介绍了AVPacket结构的生命周期管理,包括数据缓冲区的创建、使用和释放。最后,提供了避免内存泄漏的实用建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FFMPEG使用AVPacket来暂存解复用之后、解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等)。其中:

  • dts表示解码时间戳,pts表示显示时间戳,它们的单位是所属媒体流的时间基准。
  • stream_index给出所属媒体流的索引;
  • data为数据缓冲区指针,size为长度;
  • duration为数据的时长,也是以所属媒体流的时间基准为单位;
  • pos表示该数据在媒体流中的字节偏移量;
  • destruct为用于释放数据缓冲区的函数指针;
  • flags为标志域,其中,最低为置1表示该数据是一个关键帧。

AVPacket结构本身只是个容器,它使用data成员引用实际的数据缓冲区。这个缓冲区通常是由av_new_packet创建的,但也可能由 FFMPEG的API创建(如av_read_frame)。当某个AVPacket结构的数据缓冲区不再被使用时,要需要通过调用 av_free_packet释放。av_free_packet调用的是结构体本身的destruct函数,它的值有两种情 况:1)av_destruct_packet_nofree或0;2)av_destruct_packet,其中,情况1)仅仅是将data和 size的值清0而已,情况2)才会真正地释放缓冲区。

FFMPEG内部使用AVPacket结构建立缓冲区装载数据,同时提供destruct函数,如果FFMPEG打算自己维护缓冲区,则将 destruct设为av_destruct_packet_nofree,用户调用av_free_packet清理缓冲区时并不能够将其释放;如果 FFMPEG打算将该缓冲区彻底交给调用者,则将destruct设为av_destruct_packet,表示它能够被释放。安全起见,如果用户希望 自由地使用一个FFMPEG内部创建的AVPacket结构,最好调用av_dup_packet进行缓冲区的克隆,将其转化为缓冲区能够被释放的 AVPacket,以免对缓冲区的不当占用造成异常错误。av_dup_packet会为destruct指针为 av_destruct_packet_nofree的AVPacket新建一个缓冲区,然后将原缓冲区的数据拷贝至新缓冲区,置data的值为新缓冲区 的地址,同时设destruct指针为av_destruct_packet。

### FFmpeg AVPacket 使用说明 #### 初始化和读取 AVPacketFFmpeg 中,`AVPacket` 是用于存储编码后的音视频帧的数据结构。初始化 `AVPacket` 并从中读取数据的过程如下: ```c #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> // 创建并初始化 AVPacket 结构体 AVPacket* packet = av_packet_alloc(); if (!packet) { fprintf(stderr, "Failed to allocate AVPacket\n"); exit(1); } // 打开输入文件并获取格式上下文 AVFormatContext *fmt_ctx; const char *input_filename = "input.mp4"; if (avformat_open_input(&fmt_ctx, input_filename, NULL, NULL) != 0) { fprintf(stderr, "Could not open source file %s\n", input_filename); exit(1); } if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { fprintf(stderr, "Could not find stream information\n"); exit(1); } int ret; while ((ret = av_read_frame(fmt_ctx, packet)) >= 0) { // 处理每一个 AVPacket... // 清空当前使用的 AVPacket 数据以便下次使用 av_packet_unref(packet); } ``` 上述代码展示了如何创建一个 `AVPacket` 实例以及通过 `av_read_frame()` 函数来不断从媒体文件中读取出新的包[^1]。 #### 正确管理内存防止泄漏 当不再需要某个特定的 `AVPacket` 或者结束程序运行前应当确保正确释放其占用资源以免造成内存泄露现象发生: ```c // 当完成所有操作之后记得释放分配给 AVPacket 的空间 av_packet_free(&packet); // 关闭输入文件句柄 avformat_close_input(&fmt_ctx); ``` 注意这里不仅有对自定义指针对象进行了销毁(`av_packet_free`)还包含了对于外部依赖项如文件描述符等也做了清理工作(`avformat_close_input`). 这样可以有效避免潜在的风险问题[^2]. #### 编解码过程中利用 AVPacket 通常情况下,在实际应用里我们会把接收到的数据先保存成 `AVPacket`,再传递给相应的编解码函数去做进一步处理. ```c for (;;) { int got_output; // 假设已经有一个有效的 AVCodecContext *dec_ctx 和 AVFrame *frame /* 获取下一个压缩过的视频帧 */ if (av_read_frame(fmt_ctx, packet) < 0) break; /* 发送该数据包至解码器 */ if (avcodec_send_packet(dec_ctx, packet) == AVERROR(EAGAIN)) continue; while (got_output = 0, !avcodec_receive_frame(dec_ctx, frame)) { // 对解码出来的原始图像做些事情... // 将已处理完毕的数据标记为空闲状态供后续重用 av_frame_unref(frame); } // 同步清零本次循环所涉及的对象属性值以防干扰下一轮迭代过程. av_packet_unref(packet); } ``` 此片段体现了完整的从读入到最终显示或另存为其他形式之间的转换链路[^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值