cpp
s32 CFFMpegVidDecoder::Destroy()
{
//在FFmpeg中,这些资源的释放确实有隐含的依赖关系,需要按照正确的顺序进行。
//正确顺序:frame → packet → context → codec
if (m_ptAVframe)
{
av_frame_free(&m_ptAVframe);
m_ptAVframe = NULL;
}
if (m_ptAVsw_frame)
{
av_frame_free(&m_ptAVsw_frame);
m_ptAVsw_frame = NULL;
}
if(m_ptPacket)
{
av_packet_free(&m_ptPacket);
m_ptPacket = NULL;
}
if (m_pAVdecoder_ctx)
{
avcodec_free_context(&m_pAVdecoder_ctx);
m_pAVdecoder_ctx = NULL;
}
if(m_pthw_device_ctx)
{
av_buffer_unref(&m_pthw_device_ctx);
m_pthw_device_ctx = NULL;
}
m_ptAVdecoder = NULL;
m_bCreate = FALSE;
return 0;
}
硬解时,销毁解码器时,这些资源的释放有先后顺序要求吗?
在硬解场景下,资源释放的顺序更加重要,因为涉及到硬件设备的依赖关系。你的当前顺序基本正确,但可以进一步优化。
硬解资源释放的正确顺序
cpp
s32 CFFMpegVidDecoder::Destroy()
{
// 第1步:先释放软件帧 (与硬件资源无关)
if (m_ptAVframe)
{
av_frame_free(&m_ptAVframe);
m_ptAVframe = NULL;
}
if (m_ptAVsw_frame)
{
av_frame_free(&m_ptAVsw_frame);
m_ptAVsw_frame = NULL;
}
// 第2步:释放数据包 (与硬件资源无关)
if(m_ptPacket)
{
av_packet_free(&m_ptPacket);
m_ptPacket = NULL;
}
// 第3步:关键步骤 - 先解除硬件设备与解码器的关联
if (m_pAVdecoder_ctx && m_pAVdecoder_ctx->hw_device_ctx)
{
// 重要:在释放解码器上下文前,先解除硬件设备关联
av_buffer_unref(&m_pAVdecoder_ctx->hw_device_ctx);
}
// 第4步:释放解码器上下文 (此时已解除硬件关联)
if (m_pAVdecoder_ctx)
{
avcodec_free_context(&m_pAVdecoder_ctx);
m_pAVdecoder_ctx = NULL;
}
// 第5步:最后释放硬件设备上下文
if(m_pthw_device_ctx)
{
av_buffer_unref(&m_pthw_device_ctx);
m_pthw_device_ctx = NULL;
}
// 第6步:清理编解码器指针 (静态数据,无需释放)
m_ptAVdecoder = NULL;
m_bCreate = FALSE;
return 0;
}
为什么需要这个顺序?
硬件解码的特殊依赖关系
硬件设备上下文 (m_pthw_device_ctx)
↑
| 被引用
解码器上下文 (m_pAVdecoder_ctx)
↑
| 可能引用
帧数据 (m_ptAVframe, m_ptAVsw_frame)
关键点说明
- 先释放帧数据:避免帧引用已释放的硬件资源
- 解除硬件关联:在释放解码器前,必须先解除硬件设备引用
- 最后释放硬件设备:确保没有解码器再引用硬件资源
更安全的完整实现
cpp
s32 CFFMpegVidDecoder::Destroy()
{
// 步骤1:保存到局部变量并清空成员,避免重复释放
AVFrame* frame_to_free = m_ptAVframe;
AVFrame* sw_frame_to_free = m_ptAVsw_frame;
AVPacket* packet_to_free = m_ptPacket;
AVCodecContext* context_to_free = m_pAVdecoder_ctx;
AVBufferRef* hw_device_to_free = m_pthw_device_ctx;
// 立即清空成员变量
m_ptAVframe = NULL;
m_ptAVsw_frame = NULL;
m_ptPacket = NULL;
m_pAVdecoder_ctx = NULL;
m_pthw_device_ctx = NULL;
m_ptAVdecoder = NULL;
m_bCreate = FALSE;
// 步骤2:按正确顺序释放资源
if (frame_to_free) {
av_frame_free(&frame_to_free);
}
if (sw_frame_to_free) {
av_frame_free(&sw_frame_to_free);
}
if (packet_to_free) {
av_packet_free(&packet_to_free);
}
// 关键:先解除硬件关联
if (context_to_free && context_to_free->hw_device_ctx) {
av_buffer_unref(&context_to_free->hw_device_ctx);
}
if (context_to_free) {
avcodec_free_context(&context_to_free);
}
// 最后释放硬件设备
if (hw_device_to_free) {
av_buffer_unref(&hw_device_to_free);
}
return 0;
}
硬件解码资源依赖图
m_ptAVframe ─────┐
│ 可能包含硬件帧
m_ptAVsw_frame ─┼─→ m_pAVdecoder_ctx ───→ m_pthw_device_ctx
│ ↑
m_ptPacket ─────┘ │
hw_device_ctx (内部引用)
总结
正确的硬解释放顺序:
- ✅ 帧数据 (AVFrame)
- ✅ 数据包 (AVPacket)
- ✅ 关键:解除解码器与硬件的关联
- ✅ 解码器上下文 (AVCodecContext)
- ✅ 硬件设备上下文 (AVBufferRef)
- ✅ 编解码器指针 (置NULL)
你的原始代码缺少了第3步解除硬件关联,这可能导致资源泄漏或程序崩溃。