文章

学习 AV_CODEC_FLAG_COPY_OPAQUE 解决 AVFrame pkt_pos 警告

学习 AV_CODEC_FLAG_COPY_OPAQUE 解决 AVFrame pkt_pos 警告

将 FFmpeg 升级到 6 代的时候,av_frame_get_pkt_pos 方法已经删除了,改成了直接访问 frame->pkt_pos 属性,但是会有产生一个警告:‘pkt_pos’ is deprecated,下面介绍下如何去掉这个警告。

在 FFmpeg 开发过程中,我们经常会遇到需要在编解码阶段传递私有数据的场景,AV_CODEC_FLAG_COPY_OPAQUE 标志便应运而生了。它能帮助开发者在解码时保留和传递私有数据,本文将详细介绍该标志的使用方法、适用场景及注意事项。

一、AV_CODEC_FLAG_COPY_OPAQUE 是什么

AV_CODEC_FLAG_COPY_OPAQUE 是 FFmpeg 中用于编解码器的一个标志。当设置该标志后,解码器会在输出的 AVFrame 中保留输入 AVPacket 的 opaque 和 opaque_ref 字段。这使得开发者可以将自定义的私有数据(如元数据、上下文指针等)在数据包和帧之间进行传递。

二、适用场景

  • 传递自定义元数据:例如在视频处理过程中,传递时间戳偏移、用户标记等特殊信息。
  • 多线程解码上下文关联:在多线程环境下,保证私有数据能够准确传递到对应的输出帧。
  • 私有指针传递:当需要在编解码流程中传递自定义的上下文指针时,该标志能确保数据的完整性和有效性。

接下来就以传递时间戳为例学习如何使用这个标记。

三、使用方法

1、设置标志位

在打开解码器之前,通过 flags 设置 AV_CODEC_FLAG_COPY_OPAQUE 标志:

1
2
3
4
5
6
7
8
AVCodecContext *codec_ctx = ...;
// 启用标志
codec_ctx->flags |= AV_CODEC_FLAG_COPY_OPAQUE;

// 打开解码器
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {

}

2、在输入数据包中设置 opaque

在调用 avcodec_send_packet 向解码器发送数据包之前,给 AVPacket 的 opaque 或 opaque_ref 字段赋值。这里有两种常用方式:

  • 直接设置指针:
1
2
3
AVPacket *pkt = ...;
// 直接设置指针(需确保生命周期)
pkt->opaque = my_private_data;  // 自定义数据指针
  • 使用引用计数(更推荐):
1
2
3
4
5
6
7
8
9
10
AVPacket *pkt = ...;
AVBufferRef *buf_ref = av_buffer_create(my_data, size, free_callback, NULL, 0);
pkt->opaque_ref = av_buffer_ref(buf_ref);
//或者
FrameData *fd;
d->pkt->opaque_ref = av_buffer_allocz(sizeof(*fd));
if (!d->pkt->opaque_ref)
    return AVERROR(ENOMEM);
fd = (FrameData*)d->pkt->opaque_ref->data;
fd->pkt_pos = d->pkt->pos;

其中 FrameData 是自定义的结构体:

1
2
3
typedef struct FrameData {
    int64_t pkt_pos;
} FrameData;

3、在 avcodec_receive_frame 收到帧后从 AVFrame 中获取保留的 opaque 数据:

1
2
3
4
5
6
7
8
9
AVFrame *frame = av_frame_alloc();
while (avcodec_receive_frame(codec_ctx, frame) == 0) {
    // 获取保留的 opaque 数据
    void *private_data = frame->opaque;
    FrameData *fd = frame->opaque_ref ? (FrameData*)frame->opaque_ref->data : NULL;
    // 使用数据...
    int64_t pts = fd ? fd->pkt_pos : -1;
    av_frame_unref(frame);
}

四、注意事项

  1. 生命周期管理:
    • 如果直接使用 opaque 设置指针,必须管理好内存,确保数据在帧处理完成前不会被释放。
    • 荐使用 opaque_ref(引用计数),FFmpeg 会自动管理好内存引用计数,避免内存泄漏。
  2. 兼容性:并非所有解码器都支持 AV_CODEC_FLAG_COPY_OPAQUE 标志,使用前需检查解码器文档或通过 codec->capabilities 判断。
  3. 多线程场景:在多线程环境下,opaque 数据虽然会被正确传递到对应的输出帧,但要确保数据可安全地被多线程访问,必要时需添加锁机制。 通过学习 AV_CODEC_FLAG_COPY_OPAQUE 的使用方法,开发者可以更灵活地应对编解码过程中的私有数据传递问题,也为音视频处理项目带来更多的扩展性和实用性。
本文由作者按照 CC BY 4.0 进行授权