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

能否在新线程中加载FFmpeg DLL以优化VICE模拟器录屏性能?

解决VICE模拟器FFmpeg录屏卡顿问题的方案

首先明确:不需要专门在新线程加载FFmpeg DLL——LoadLibrary是进程级操作,DLL加载后全进程所有线程都能调用其导出函数。核心优化点是把录屏的耗时逻辑(编码、文件写入)放到独立线程,主线程只负责采集屏幕帧,避免阻塞模拟器运行。

具体实现步骤

1. 初始化阶段加载FFmpeg DLL(主线程执行)

在模拟器启动或录屏功能开启时,在主线程加载所有需要的FFmpeg DLL,同时通过GetProcAddress获取所需导出函数的指针。这些指针全进程可见,录屏线程可以直接使用。

示例代码片段:

// 加载FFmpeg核心DLL
HMODULE hAvFormat = LoadLibrary(L"avformat-59.dll");
HMODULE hAvCodec = LoadLibrary(L"avcodec-59.dll");
HMODULE hAvUtil = LoadLibrary(L"avutil-57.dll");
HMODULE hSwScale = LoadLibrary(L"swscale-6.dll");
HMODULE hAvDevice = LoadLibrary(L"avdevice-59.dll");

// 获取关键函数指针(以格式上下文初始化为例)
typedef int(*AVFormatAllocOutputCtxFn)(AVFormatContext**, const AVOutputFormat*, const char*, const char*);
AVFormatAllocOutputCtxFn avformat_alloc_output_context2 = 
    (AVFormatAllocOutputCtxFn)GetProcAddress(hAvFormat, "avformat_alloc_output_context2");

// 其他FFmpeg函数指针(如avcodec_send_frame、av_write_frame等)同理获取

2. 创建独立录屏线程

使用CreateThread创建专门的录屏线程,线程函数负责FFmpeg的录屏逻辑:初始化输出上下文、编码器,接收主线程传递的屏幕帧,执行编码和文件写入操作。

3. 主线程与录屏线程的同步机制

为了安全传递屏幕帧并避免线程冲突,需要实现线程安全的帧队列和事件通知:

  • 用CRITICAL_SECTION保护帧队列,确保主线程入队和录屏线程出队的操作互斥。
  • 用CreateEvent创建事件对象,主线程采集到帧后触发事件,通知录屏线程处理新帧。

示例线程函数框架:

// 自定义线程参数结构体
typedef struct {
    BOOL isRunning;
    CRITICAL_SECTION* frameQueueCS;
    std::queue<ScreenFrame>* frameQueue;
    HANDLE hasNewFrameEvent;
} RecordThreadParams;

DWORD WINAPI RecordThreadProc(LPVOID lpParam) {
    RecordThreadParams* params = (RecordThreadParams*)lpParam;
    AVFormatContext* fmtCtx = NULL;
    AVCodecContext* codecCtx = NULL;

    // 初始化FFmpeg输出格式、编码器(仅在录屏线程内执行)
    avformat_alloc_output_context2(&fmtCtx, NULL, "mp4", "c64_recording.mp4");
    // ... 省略编码器初始化、流添加等步骤

    while (params->isRunning) {
        // 等待新帧事件触发
        WaitForSingleObject(params->hasNewFrameEvent, INFINITE);

        // 线程安全地取出队列中的帧
        EnterCriticalSection(params->frameQueueCS);
        ScreenFrame frame = params->frameQueue->front();
        params->frameQueue->pop();
        LeaveCriticalSection(params->frameQueueCS);

        // 执行FFmpeg编码、写入操作(耗时逻辑,不阻塞主线程)
        // ... 帧格式转换、发送到编码器、写入输出文件
    }

    // 清理FFmpeg资源
    avformat_close_input(&fmtCtx);
    avcodec_free_context(&codecCtx);
    return 0;
}

4. 关键注意事项

  • FFmpeg的上下文对象(如AVFormatContext、AVCodecContext)不能跨线程操作,所有对同一上下文的调用必须在录屏线程内完成。
  • 屏幕帧的内存管理要谨慎:要么在主线程拷贝帧数据后传递给队列,要么使用引用计数确保录屏线程处理完前不释放内存。
  • 录屏结束时,要先通知线程停止运行,等待线程退出后再调用FreeLibrary卸载FFmpeg DLL(如果后续不再使用)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 15:10:31