能否在新线程中加载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
相关产品推荐
相关产品推荐

