1. 預覽回呼函數 preview callback function
當視訊擷取驅動程式接收到來自視訊裝置的畫面(frame), 在 preview 模式之下, 將此畫面顯示所連結的視訊視窗之中。
我們可以透過 capSetCallbackOnFrame 這個函數來指定當發生 frame preview 之前, 先執行一個特定的 callback function, 即預覽回呼函數。這個預覽回呼函數的名稱可以由我們自由命名, 但是傳入的參數個數與其資料型態則必須符合 VFW 的規定。
// 使用者自行寫的預覽回呼函數必須在公用變數宣告區宣告
LRESULT CALLBACK FrameCallBack( HWND hwndCapture, PVIDEOHDR lpvhdr );
// 設定 callback function 與視訊擷取視窗之間的連結,
// 請將此行放到開啟視訊擷取視窗, 並開始 preview 的指令後
capSetCallbackOnFrame(hwndCapture, &FrameCallBack);
2. 實驗: 當程式開啟視訊擷取視窗後, 顯示預覽的畫面總數到 Label 上。
實驗目的: 了解視訊擷取視窗之預覽回呼函數的設定與使用方法。
範例程式: W11-SP
3. 如何關閉預覽回呼函數?
capSetCallbackOnFrame(hwndVideo, NULL);
4. 預覽回呼函數可以做些什麼?
好處: 就是我們可以在畫面預覽之前, 先對畫面資料做預先處理, 例如: 加入文字、物件或特效等等。
這段影片就是利用預覽回呼函數, 將龍珠放置到畫面之中, 再與攝影機所拍攝的手進行互動...
但, 問題是這些畫面資料到底怎麼存取呢?
5. 如何從記憶體直接擷取視訊畫面?
透過 capSetCallbackOnFrame 這個函式設定: 當視訊擷取視窗(代碼為 hwndViedo) 取得一個 frame 後, 必須執行我們所定義的 callback function: FrameCallBack,
capSetCallbackOnFrame(hwndVideo, &FrameCallBack);
LRESULT CALLBACK FrameCallBack( HWND hwndCapture, PVIDEOHDR lpvhdr );
在我們所自行定義的 FrameCallBack callback function 中, 有兩個輸入參數:
a. HWND hwndVideo,
指明哪一個視訊擷取視窗, 即該視訊擷取視窗的 handle。
b. PVIDEOHDR lpvhdr,
capSetCallbackOnFrame 這個函式會自動把視訊擷取視窗的相關資訊透過 PVIDEOHDR lpvhdr 這個結構變數, 讓 FrameCallBack callback function 來使用。
有關 PVIEDOHDR 這個結構的相關資訊, 可以在 vfw.h 中, 找到如下的結構定義:
/* video data block header */
typedef struct videohdr_tag {
LPBYTE lpData; /* pointer to locked data buffer */
DWORD dwBufferLength; /* Length of data buffer */
DWORD dwBytesUsed; /* Bytes actually used */
DWORD dwTimeCaptured; /* Milliseconds from start of stream */
DWORD_PTR dwUser; /* for client's use */
DWORD dwFlags; /* assorted flags (see defines) */
DWORD_PTR dwReserved[4]; /* reserved for driver */
} VIDEOHDR, NEAR *PVIDEOHDR, FAR * LPVIDEOHDR;
透過 結構 videohdr_tag 的宣告, 我們獲知擷取視窗的 data buffer 的指標可以用 lpData 這個變數來取得, 即
CaptureData = LPVIDEOHDR(lpvhdr);
ptrCapture = CaptureData->lpData;
// 全域變數宣告
LPVIDEOHDR CaptureData;
BYTE *ptrCapture, *ptrImage;
說明:
a. CaptureData 是全域結構變數, 其資料型態亦為 PVIDEOHDR。
b. *ptrCapture 與 *ptrImage 是兩個指向記憶體位址的全域指標變數。
6. 實驗: 將視訊擷取視窗的內容即時顯示於影像物件之中。
實驗目的: 了解視訊擷取視窗資料緩衝區的記憶體存取方法。
本實驗說穿了就是把某一塊記憶體(視訊擷取視窗資料緩衝區/data buffer) 複製到另一塊記憶體(影像物件存放色彩資料的記憶體) 之中。因此, 我們只要弄清楚兩個記憶體的起始位址, 自然可以輕鬆完成實驗。
透過 videohdr_tag 結構中的 lpData, 我們可以得到視訊擷取視窗的資料暫時存放區的起始位址。
CaptureData = LPVIDEOHDR(lpvhdr);
ptrCapture = CaptureData->lpData;
透過 TBitmap::ScanLine 這個 property 我們可以得到影像元件中, 每一列(row) 的影像資料存放的記憶體起始位置。
ptrImage = (BYTE *)Form1->imCW->Picture->Bitmap->ScanLine[i];
沒有留言:
張貼留言