You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x64 Windows下memcpy写入av_malloc内存致av_free崩溃问题排查

问题分析与解决方案

核心原因:双重内存释放

你的程序崩溃和memcpy、内存对齐无关,是重复释放同一块内存导致的。avio_alloc_context会接管你传入的buffer内存所有权,当调用avformat_close_input时,FFmpeg内部会自动销毁AVIOContext并释放其关联的buffer。你后续手动调用av_free(buffer),就触发了双重释放,直接导致程序崩溃。

修复步骤

  1. 移除所有手动调用的av_free(buffer),让FFmpeg负责buffer的释放。
  2. 确保std::vector<uint8_t> data的生命周期覆盖FFmpeg读取数据的全过程(你的代码里这部分是正确的,data在main函数内,直到程序结束才会销毁)。

修复后的完整代码

#include<iostream>
#include<memory>
#include<vector>
extern "C"
{
#include <libavcodec/avcodec.h>
#include<libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include<libswscale/swscale.h>
#include<libswresample/swresample.h>
}

struct BufferData
{
    uint8_t* ptr;
    size_t size;
    size_t file_size;
};

int main()
{
    auto file=fopen("E:/test.jpg", "rb");
    fseek(file, 0, SEEK_END);
    auto fileSize = ftell(file);
    fseek(file, 0, SEEK_SET);
    auto data = std::vector<uint8_t>(fileSize);
    fread(data.data(), sizeof(uint8_t), fileSize, file);
    fclose(file);

    auto test = BufferData();
    test.ptr = data.data();
    test.size = data.size();
    test.file_size = data.size();
    auto buffer = (uint8_t*)av_malloc(4096 * 10);
    char errStr[128] = { 0 };

    auto avformatContext = avformat_alloc_context();
    auto avioContext = avio_alloc_context(buffer, 4096, 0, &test, [](void* opaque, uint8_t* buf, int buf_size)
        {
            BufferData* bd = (BufferData*)opaque;
            auto size = std::min(bd->size, (size_t)buf_size);

            if (!size)
            {
                return -1;
            }

            memcpy(buf, bd->ptr, size);
            bd->ptr += size;
            bd->size -= size;
            return (int)size;
        }, NULL, NULL);
    avformatContext->pb = avioContext;
    avformatContext->flags = AVFMT_FLAG_CUSTOM_IO;

    auto ret = avformat_open_input(&avformatContext, nullptr, nullptr, nullptr);
    if (ret != 0)
    {
        av_strerror(ret, errStr, sizeof(errStr));
        std::cout << errStr << std::endl;
        avformat_close_input(&avformatContext);
        return 0;
    }

    ret = avformat_find_stream_info(avformatContext, nullptr);
    if (ret < 0)
    {
        av_strerror(ret, errStr, sizeof(errStr));
        std::cout << errStr << std::endl;
        avformat_close_input(&avformatContext);
        return 0;
    }

    av_dump_format(avformatContext, 0, nullptr, 0);

    auto videoIndex = av_find_best_stream(avformatContext, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
    if (videoIndex == AVERROR_STREAM_NOT_FOUND)
    {
        avformat_close_input(&avformatContext);
        return 0;
    }
    else if (videoIndex == AVERROR_DECODER_NOT_FOUND)
    {
        avformat_close_input(&avformatContext);
        return 0;
    }

    auto videoCodecPar = avformatContext->streams[videoIndex]->codecpar;
    auto videoCodec = avcodec_find_decoder(videoCodecPar->codec_id);
    if (!videoCodec)
    {
        avformat_close_input(&avformatContext);
        return 0;
    }

    avformat_close_input(&avformatContext);
}

额外说明

  • 如果需要手动管理buffer内存,可以在调用avio_alloc_context时,将buffer参数设为NULL,然后通过自定义的read_packet回调自行处理内存,但这种场景下你当前的逻辑不需要这么做。
  • 测试时确保E:/test.jpg路径存在,避免因文件读取失败导致的其他问题。

内容的提问来源于stack exchange,提问作者PeacefulWindy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:40:15