View
230
Download
4
Category
Preview:
Citation preview
Windows Multimedia TechniquesWindows Multimedia Techniques
- Video Capture- Video Capture
井民全製作
為何要使用 為何要使用 Video For WindowsVideo For Windows
• 簡單就是美 : – 你不需要知道 COM 的原理 , 就能寫影像處理
程式 ( 相對於 DirectX)
• 開發容易 : – 你不用下載 數百 M 的 DirectX SDK
Video for Windows Video for Windows 的缺點的缺點• doesn't handle audio/video synchronization • doesn't support variable-length frames
• 基於以上缺點– 目前 Microsoft 使用 DirectShow 與 WDM Stream Class
來解決這個問題
• Driver 開發– 請使用 WDM Stream Class 取代 VFW architecture
IntroductionIntroduction
• using the AVICap window class to enable video capture– Simple– message-based interface
• Access the hardware• Control the stream to disk
IntroductionIntroduction
• Streaming video capture & single-frame capture in real-time
• Using Media Control Interface (MCI)– You can control the start and stop positions of
a video source
The tasks of the AVICap window classThe tasks of the AVICap window class
• Capture audio & video stream AVI file• Connect and Disconnect the devices
dynamically.• View a live incoming video signal • Set the capture rate• Display dialog boxes that control the video
source and format• Capture and save a single image as a device-
independent bitmap (DIB)
Previewing Video DemoPreviewing Video Demo
• 必要 include 檔 : vfw.h
• Library : vfw32.lib
#include <vfw.h>#pragma comment( lib, "Vfw32.lib" )
#include <vfw.h>#pragma comment( lib, "Vfw32.lib" )
Creating a Capture WindowCreating a Capture Window
HWND hwndParent=this->m_hWnd;HWND hWndC = capCreateCaptureWindow ( "Capture Window",
WS_CHILD | WS_VISIBLE , 0, 0, 160, 120, hwndParent, 0);if(hWndC==NULL) ShowError();
HWND hwndParent=this->m_hWnd;HWND hWndC = capCreateCaptureWindow ( "Capture Window",
WS_CHILD | WS_VISIBLE , 0, 0, 160, 120, hwndParent, 0);if(hWndC==NULL) ShowError();
你要顯示畫面的視窗 Handle
capDriverConnect (hWndC, 0); capDriverConnect (hWndC, 0);
Connecting to a Capture Driver
Obtaining the Status of a Capture WindowObtaining the Status of a Capture Window
CAPSTATUS CapStatus;BOOL bOK;bOK=capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));
::SetWindowPos(hWndC, NULL, 0, 0, CapStatus.uiImageWidth, \
CapStatus.uiImageHeight,\ SWP_NOZORDER | SWP_NOMOVE);
CAPSTATUS CapStatus;BOOL bOK;bOK=capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));
::SetWindowPos(hWndC, NULL, 0, 0, CapStatus.uiImageWidth, \
CapStatus.uiImageHeight,\ SWP_NOZORDER | SWP_NOMOVE);
調整 Capture Window 大小
得到 Frame 的大小
Previewing VideoPreviewing Video
capPreviewRate(hWndC, 66); // rate, in millisecondscapPreview(hWndC, TRUE); // starts preview
capPreviewRate(hWndC, 66); // rate, in millisecondscapPreview(hWndC, TRUE); // starts preview
完整程式完整程式#include <vfw.h>#pragma comment( lib, "Vfw32.lib" ) // 使用 Video For Window 32 libraryvoid CSimpleVideoDlg::OnBnClickedOk() {
// 建立 Capture 視窗HWND hwndParent=this->m_hWnd;HWND hWndC = capCreateCaptureWindow ( "Capture Window", WS_CHILD | WS_VISIBLE , 0, 0, 160, 120,
hwndParent, 0); // 與 Device Driver 連線
capDriverConnect (hWndC, 0); // 讀取一張 frame 的大小
CAPSTATUS CapStatus;BOOL bOK=capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS)); ::SetWindowPos(hWndC, NULL, 0, 0,
CapStatus.uiImageWidth, CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE);
// 設定 Preview Rate 並且 顯示出來capPreviewRate(hWndC, 66); // rate, in millisecondscapPreview(hWndC, TRUE); // starts preview
} Simple Video
更多的選項更多的選項 :: 列舉出目前系統所擁有的 列舉出目前系統所擁有的 Capture DriverCapture Driver
char szDeviceName[80];char szDeviceVersion[80];CString DeviceList;for (int wIndex = 0; wIndex < 10; wIndex++) {
if (capGetDriverDescription (wIndex, szDeviceName, \sizeof (szDeviceName), szDeviceVersion, \sizeof (szDeviceVersion)))
{// Append name to list of installed capture drivers// and then let the user select a driver to use.DeviceList.Append(szDeviceName);
}} MessageBox(DeviceList," 系統中 Capture Driver 描述 ");
char szDeviceName[80];char szDeviceVersion[80];CString DeviceList;for (int wIndex = 0; wIndex < 10; wIndex++) {
if (capGetDriverDescription (wIndex, szDeviceName, \sizeof (szDeviceName), szDeviceVersion, \sizeof (szDeviceVersion)))
{// Append name to list of installed capture drivers// and then let the user select a driver to use.DeviceList.Append(szDeviceName);
}} MessageBox(DeviceList," 系統中 Capture Driver 描述 ");
• 使用 capGetDriverDescription 函式
可以 0 ~ 9
傳回的 Capture Driver 描述
傳回的 版本資訊
印出來
更多的選項更多的選項 :: 選擇 選擇 Video SourceVideo Source
CAPDRIVERCAPS CapDriverCaps; ::SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS, \ sizeof (CAPDRIVERCAPS), (LONG) (LPVOID) &CapDriverCaps);
if (CapDriverCaps.fHasDlgVideoSource) capDlgVideoSource(hWndC);
CAPDRIVERCAPS CapDriverCaps; ::SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS, \ sizeof (CAPDRIVERCAPS), (LONG) (LPVOID) &CapDriverCaps);
if (CapDriverCaps.fHasDlgVideoSource) capDlgVideoSource(hWndC);
傳回的硬體裝置的基本能力描述
顯示 Video Source 對話框由使用者選擇
看看是否支援 Video Source Dialog
更多的選項更多的選項 :: 如何得知抓到的如何得知抓到的影像格式影像格式呢呢 ? ?
現在是 RGB 24
// Video format dialog box. if (CapDriverCaps. fHasDlgVideoFormat){ capDlgVideoFormat (hWndC);
// Are there new image dimensions? capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));
}
// Video format dialog box. if (CapDriverCaps. fHasDlgVideoFormat){ capDlgVideoFormat (hWndC);
// Are there new image dimensions? capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));
}
顯示 Video Format 對話框 , 供使用者設定
更多的選項更多的選項 :: 調整輸出影像的調整輸出影像的對比亮度對比亮度等屬性等屬性• 注意 : 不會影響 video data
// Video display dialog box. if (CapDriverCaps.fHasDlgVideoDisplay)
capDlgVideoDisplay(hWndC);
// Video display dialog box. if (CapDriverCaps.fHasDlgVideoDisplay)
capDlgVideoDisplay(hWndC);
更多的選項更多的選項 :: 傳回目前正在使用的 傳回目前正在使用的 video formatvideo format
DWORD dwSize;dwSize = capGetVideoFormatSize(hWndC);
lpbi = (LPBITMAPINFO) GlobalAllocPtr(GHND, dwSize);capGetVideoFormat(hWndC, lpbi, dwSize);
DWORD dwSize;dwSize = capGetVideoFormatSize(hWndC);
lpbi = (LPBITMAPINFO) GlobalAllocPtr(GHND, dwSize);capGetVideoFormat(hWndC, lpbi, dwSize);
Step 1: 先計算 Video Format 所需的 大小
Step 2: 取出 Video Format
LPBITMAPINFO lpbi;
Video Format 用 BITMAPINFO 結構表示
影像資料的擷取影像資料的擷取• 我們利用 capSetCallbackOnFrame 函式
– 當一張 frame 填滿後 , 會呼叫你的 fucntion
BOOL bOk= capSetCallbackOnFrame(hWndC, \ capVideoStreamCallback);
BOOL bOk= capSetCallbackOnFrame(hWndC, \ capVideoStreamCallback);
LRESULT CALLBACK capVideoStreamCallback (HWND hWnd , \ LPVIDEOHDR lpVHdr) { …}
填滿後 , 自動呼叫
全部合在一起全部合在一起#include "Vfw.h"#include <windowsx.h> // for GlobalAllocPtr#pragma comment( lib, "Vfw32.lib" ) // 使用 Video For Window 32 library
LRESULT CALLBACK capVideoStreamCallback(HWND hWnd,LPVIDEOHDR lpVHdr);HWND hMyWnd;LPBITMAPINFO lpbi; // for video format
void CWin32VideoCaptureDlg::OnBnClickedOk(){
hMyWnd=this->m_hWnd; // Step 1. 建立 Capture Window 並且把這個 Window 貼在 Dialog 上
HWND hWndC = capCreateCaptureWindow ( (LPSTR) "My Capture Window", // window name if pop-up WS_CHILD | WS_VISIBLE, // window style 0, 0, 160, 120, // window position and dimensions
this->m_hWnd, // 不能給 NULL, 否則會失敗 0 /* child ID */); // Step 2. 與硬體驅動程式連線 LRESULT fOK = ::SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0, 0L);
接下頁 VFW Demo
// Step 3. 列舉出目前系統所擁有的 Capture Driverchar szDeviceName[80];char szDeviceVersion[80];CString DeviceList;for (int wIndex = 0; wIndex < 10; wIndex++) {
if (capGetDriverDescription (wIndex, szDeviceName, \sizeof (szDeviceName), szDeviceVersion, \sizeof (szDeviceVersion))) {// Append name to list of installed capture drivers// and then let the user select a driver to use.DeviceList.Append(szDeviceName);
}} // end of listMessageBox(DeviceList," 系統中 Capture Driver 描述 ");
// Step 4. 取得目前 Capture 的功能 // ( 我們藉此判斷使用者是否可以設定 Video Source 與 Video Format) CAPDRIVERCAPS CapDriverCaps; ::SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS, \
sizeof (CAPDRIVERCAPS), (LONG) (LPVOID) &CapDriverCaps);
// Step 5: 讓使用者使用者選定的 Video Sourceif (CapDriverCaps.fHasDlgVideoSource)
capDlgVideoSource(hWndC); 接下頁
選擇 video source 部分
系統中是否有 Capture
Driver
// Step 6: 讓使用者調整的 Video Format CAPSTATUS CapStatus;
if (CapDriverCaps.fHasDlgVideoFormat){capDlgVideoFormat(hWndC); // Are there new image dimensions?capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));// If so, notify the parent of a size change.
} // Step 7: 讓使用者調整影像的輸出屬性 ( 亮度 , 對比 , 彩度 )
if (CapDriverCaps.fHasDlgVideoDisplay)capDlgVideoDisplay(hWndC);
// Step 8: 得到最後的硬體狀態BOOL bOK=capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));
// Step 9: 調整 Capture 視窗的大小 ,::SetWindowPos(hWndC, NULL, 0, 0, CapStatus.uiImageWidth, \ CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE);
// Step 10. Obtaining and Setting the Video FormatDWORD dwSize;dwSize = capGetVideoFormatSize(hWndC);lpbi = (LPBITMAPINFO) GlobalAllocPtr(GHND, dwSize);capGetVideoFormat(hWndC, lpbi, dwSize);
接下頁
由 lpbi 可以得知一張 frame 的寬與高
// Step 11. Previewing VideocapPreviewRate(hWndC, 66); // rate, in millisecondscapPreview(hWndC, TRUE); // starts preview
// Step 12. 當一張 frame 填滿後 , 呼叫登記的 function 處理BOOL bOk= capSetCallbackOnFrame(hWndC, capVideoStreamCallback);
} // end of OnBnClickedOk
int gdwFrameNum=0;char *gachBuffer=new char[100];LRESULT CALLBACK capVideoStreamCallback(HWND hWnd,LPVIDEOHDR lpVHdr){ if (!hWnd) return FALSE; // 若你的 video format 為 RGB24, 注意 : DIB 左下角 = (0,0) wsprintf(gachBuffer, "Preview frame# %ld 一個 pixel=%d bits; 寬 =%d; 高 =%d; (RGB)=(%d,%d,%d) 使用的長度 =%d" ,\
gdwFrameNum++, lpbi->bmiHeader.biBitCount,\ lpbi->bmiHeader.biWidth, lpbi->bmiHeader.biHeight,\
(int)*(lpVHdr->lpData),\ (int)*(lpVHdr->lpData+1),\ (int)*(lpVHdr->lpData+2),\ lpVHdr->dwBytesUsed );
SetWindowText(hMyWnd, (LPSTR)gachBuffer); return (LRESULT) TRUE ; }
Call Back Function
目前發展近況目前發展近況• Microsoft 使用新架構取代 VFW
– WDM Stream class and Microsoft DirectShow
• End
Recommended