1 SetCallback(即,註冊回調)的實現
1.1 函數簽名
int MV_CC_RegisterImageCallBackEx( void* handle, // 相機設備句柄 void (__stdcall *pCallBack)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), // 回調函數指針 void* pUser // 用户自定義數據 );
參數説明:
-
handle:相機設備句柄,用於標識具體的相機設備 -
pCallBack:回調函數指針,使用__stdcall調用約定 -
pUser:用户數據(即,上下文指針),會在回調時原樣傳回
1.2 內部實現
// 內部數據結構 struct CameraDevice { void* hardwareHandle; // 硬件設備句柄 void* userCallback; // 用户回調函數指針 void* userData; // 用户數據 std::thread* captureThread; // 採集線程 bool isGrabbing; // 採集狀態 // ... 其他成員 }; // 函數實現 int MV_CC_RegisterImageCallBackEx(void* handle, void (__stdcall *pCallBack)(unsigned char *, MV_FRAME_OUT_INFO_EX*, void*), void* pUser) { // 1. 參數驗證 if (!handle || !pCallBack) { return MV_E_PARAMETER; // 參數錯誤 } // 2. 獲取設備對象 CameraDevice* device = static_cast<CameraDevice*>(handle); // 3. 保存回調函數和用户數據 device->userCallback = reinterpret_cast<void*>(pCallBack); device->userData = pUser; // 4. 返回成功 return MV_OK; }
2 回調觸發機制
// 採集線程 void CaptureThreadProc(CameraDevice* device) { while (device->isGrabbing) { // 1. 從硬件獲取圖像數據 unsigned char* imageData = nullptr; MV_FRAME_OUT_INFO_EX frameInfo = {0}; int result = GetImageFromHardware(device->hardwareHandle, &imageData, &frameInfo); if (result == MV_OK && imageData != nullptr) { // 2. 檢查是否有註冊的回調函數 if (device->userCallback) { // 3. 調用用户回調函數 auto callback = reinterpret_cast<void (__stdcall *)(unsigned char *, MV_FRAME_OUT_INFO_EX*, void*)> (device->userCallback); // 4. 在單獨的線程或當前線程中執行回調 callback(imageData, &frameInfo, device->userData); } } // 5. 短暫休眠,避免過度佔用CPU std::this_thread::sleep_for(std::chrono::microseconds(100)); } } int MV_CC_StartGrabbing(void* handle) { CameraDevice* device = static_cast<CameraDevice*>(handle); if (device->isGrabbing) { return MV_E_CALLORDER; // 已經在採集中 } // 啓動採集線程 device->isGrabbing = true; device->captureThread = new std::thread(CaptureThreadProc, device); return MV_OK; }
3. 關鍵設計要點
-
函數指針存儲:SDK內部保存用户提供的回調函數指針
-
用户數據傳遞:將用户數據原樣保存,回調時傳回
-
線程安全:在採集線程中調用回調,需要考慮線程安全
-
異常處理:回調執行異常不應影響採集線程的正常運行
4 實際應用中的考慮
4.1 性能考慮
// 回調應該快速執行,避免阻塞採集線程 void ImageCB(...) { // 快速處理或提交到線程池 // 避免在回調中執行耗時操作 }
4.2 錯誤處理
// SDK應該處理回調中的異常 void CaptureThreadProc(CameraDevice* device) { try { if (device->userCallback) { callback(imageData, &frameInfo, device->userData); } } catch (...) { // 記錄錯誤,但不影響採集線程 LogError("Callback execution failed"); } }
4.3 資源管理
// 確保回調中正確管理資源 void ImageCB(...) { // 使用智能指針或RAII管理臨時資源 std::unique_ptr<unsigned char[]> buffer(pData); // ... 處理邏輯 ... // 自動釋放內存 }
5 最佳實踐的建議
class Camera { private: // 1. 靜態橋接函數 static void __stdcall CallbackBridge(/* 參數 */, void* userData) { // 參數驗證 if (!userData) return; // 恢復對象指針 Camera* self = static_cast<Camera*>(userData); // 異常處理 try { self->HandleCallback(/* 參數 */); } catch (...) { // 錯誤處理 } } // 2. 實際處理函數(非靜態) void HandleCallback(/* 參數 */) { // 直接訪問成員變量 // 實現業務邏輯 } // 3. 註冊回調 void RegisterCallback() { SDK_RegisterCallback(CallbackBridge, this); } };
這種設計既保持了與C風格API的兼容性,又能在實際處理函數(即,HandleCallback)中,獲得面向對象編程的便利性。
6 相關設計模式
6.1 觀察者模式(Observer Pattern)
回調機制本質上是觀察者模式的簡化版本:
-
Subject:相機SDK
-
Observer:用户回調函數
-
通知機制:函數指針調用
6.2 策略模式(Strategy Pattern)
回調函數可以看作是可替換的算法策略:
-
Context:相機採集過程
-
Strategy:用户提供的處理函數
-
執行時機:圖像採集完成時
6.3 模板方法模式(Template Method)
SDK定義了採集的算法骨架,用户定義具體的處理步驟:
-
模板方法:採集流程
-
鈎子方法:回調函數
7 總結
回調機制:
-
註冊機制:SDK保存用户提供的函數指針和上下文數據
-
觸發機制:在特定事件發生時調用保存的函數指針
-
數據傳遞:通過參數將事件相關數據傳遞給回調函數
-
上下文恢復:通過用户數據參數恢復調用上下文
回調機制在設備驅動、GUI框架、網絡庫,等領域廣泛應用,是實現鬆耦合、事件驅動的重要工具。