星期二, 4月 26, 2011

Week 11: 預覽回呼函數實作

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];

  
 

沒有留言: