📄 vfw.cxx
字号:
/**Set the colour format to be used.
Note that this function does not do any conversion. If it returns TRUE
then the video device does the colour format in native mode.
To utilise an internal converter use the SetColourFormatConverter()
function.
Default behaviour sets the value of the colourFormat variable and then
returns TRUE.
*/
virtual BOOL SetColourFormat(
const PString & colourFormat // New colour format for device.
);
/**Get the video conversion vertical flip state.
Default action is to return FALSE.
*/
virtual BOOL GetVFlipState();
/**Set the video conversion vertical flip state.
Default action is to return FALSE.
*/
virtual BOOL SetVFlipState(
BOOL newVFlipState /// New vertical flip state
);
/**Set the frame size to be used.
Note that devices may not be able to produce the requested size, and
this function will fail. See SetFrameSizeConverter().
Default behaviour sets the frameWidth and frameHeight variables and
returns TRUE.
*/
virtual BOOL SetFrameSize(
unsigned width, /// New width of frame
unsigned height /// New height of frame
);
/**Set a section of the output frame buffer.
*/
virtual BOOL FrameComplete();
LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
PDECLARE_NOTIFIER(PThread, PVideoOutputDevice_Window, HandleDisplay);
void Draw(HDC hDC);
HWND m_hWnd;
PThread * m_thread;
PSyncPoint m_started;
BITMAPINFO m_bitmap;
bool m_flipped;
};
static bool ParseWindowDeviceName(const PString & deviceName, DWORD * dwStylePtr = NULL, HWND * hWndParentPtr = NULL)
{
if (deviceName.Find("MSWIN") != 0)
return false;
PINDEX pos = deviceName.Find("STYLE=");
if (pos == P_MAX_INDEX) {
PTRACE(2, "VidOut\tDevice name must specify STYLE=.");
return false;
}
DWORD dwStyle = strtoul(((const char *)deviceName)+pos+6, NULL, 0);
HWND hWndParent = NULL;
pos = deviceName.Find("PARENT=");
if (pos != P_MAX_INDEX) {
hWndParent = (HWND)strtoul(((const char *)deviceName)+pos+5, NULL, 0);
if (!::IsWindow(hWndParent)) {
PTRACE(2, "VidOut\tIllegal parent window " << hWndParent << " specified.");
hWndParent = NULL;
}
}
// Have parsed out style & parent, see if legal combination
if ((dwStyle&(WS_POPUP|WS_CHILD)) == 0) {
PTRACE(2, "VidOut\tWindow must be WS_POPUP or WS_CHILD window.");
return false;
}
if (hWndParent == NULL && (dwStyle&WS_POPUP) == 0) {
PTRACE(2, "VidOut\tWindow must be WS_POPUP if parent window not specified.");
return false;
}
if (dwStylePtr != NULL)
*dwStylePtr = dwStyle;
if (hWndParentPtr != NULL)
*hWndParentPtr = hWndParent;
return true;
}
class PVideoOutputDevice_Window_PluginServiceDescriptor : public PDevicePluginServiceDescriptor
{
public:
virtual PObject * CreateInstance(int /*userData*/) const { return new PVideoOutputDevice_Window; }
virtual PStringList GetDeviceNames(int /*userData*/) const { return PVideoOutputDevice_Window::GetOutputDeviceNames(); }
virtual bool ValidateDeviceName(const PString & deviceName, int /*userData*/) const { return ParseWindowDeviceName(deviceName); }
} PVideoOutputDevice_Window_descriptor;
PCREATE_PLUGIN(Window, PVideoOutputDevice, &PVideoOutputDevice_Window_descriptor);
///////////////////////////////////////////////////////////////////////////////
// PVideoOutputDeviceRGB
PVideoOutputDevice_Window::PVideoOutputDevice_Window()
{
m_hWnd = NULL;
m_thread = NULL;
m_flipped = FALSE;
m_bitmap.bmiHeader.biSize = sizeof(m_bitmap.bmiHeader);
m_bitmap.bmiHeader.biWidth = frameWidth;
m_bitmap.bmiHeader.biHeight = -(int)frameHeight;
m_bitmap.bmiHeader.biPlanes = 1;
m_bitmap.bmiHeader.biBitCount = 32;
m_bitmap.bmiHeader.biCompression = BI_RGB;
m_bitmap.bmiHeader.biXPelsPerMeter = 0;
m_bitmap.bmiHeader.biYPelsPerMeter = 0;
m_bitmap.bmiHeader.biClrImportant = 0;
m_bitmap.bmiHeader.biClrUsed = 0;
m_bitmap.bmiHeader.biSizeImage = frameStore.GetSize();
}
PVideoOutputDevice_Window::~PVideoOutputDevice_Window()
{
Close();
}
PStringList PVideoOutputDevice_Window::GetOutputDeviceNames()
{
PStringList deviceList;
deviceList.AppendString(psprintf("MSWIN STYLE=0x%08X TITLE=\"Video Output\"", WS_POPUP|WS_BORDER|WS_SYSMENU|WS_CAPTION));
return deviceList;
}
BOOL PVideoOutputDevice_Window::Open(const PString & name, BOOL /*startImmediate*/)
{
Close();
deviceName = name;
m_thread = PThread::Create(PCREATE_NOTIFIER(HandleDisplay), 0,
PThread::NoAutoDeleteThread, PThread::NormalPriority,
"VidOut:%x");
m_started.Wait();
return m_hWnd != NULL;
}
BOOL PVideoOutputDevice_Window::IsOpen()
{
return m_hWnd != NULL;
}
BOOL PVideoOutputDevice_Window::Close()
{
HWND hWnd;
{
PWaitAndSignal m(mutex);
if (m_hWnd == NULL)
return FALSE;
hWnd = m_hWnd;
m_hWnd = NULL;
}
SendMessage(hWnd, WM_CLOSE, 0, 0);
m_thread->WaitForTermination(3000);
delete m_thread;
return TRUE;
}
BOOL PVideoOutputDevice_Window::Start()
{
if (m_hWnd == NULL)
return FALSE;
ShowWindow(m_hWnd, SW_SHOW);
return TRUE;
}
BOOL PVideoOutputDevice_Window::Stop()
{
if (m_hWnd != NULL)
return ShowWindow(m_hWnd, SW_HIDE);
return FALSE;
}
BOOL PVideoOutputDevice_Window::SetColourFormat(const PString & colourFormat)
{
PWaitAndSignal m(mutex);
if (((colourFormat *= "BGR24") || (colourFormat *= "BGR32")) &&
PVideoOutputDeviceRGB::SetColourFormat(colourFormat)) {
m_bitmap.bmiHeader.biBitCount = (WORD)(bytesPerPixel*8);
m_bitmap.bmiHeader.biSizeImage = frameStore.GetSize();
return TRUE;
}
return FALSE;
}
BOOL PVideoOutputDevice_Window::GetVFlipState()
{
return m_flipped;
}
BOOL PVideoOutputDevice_Window::SetVFlipState(BOOL newVFlip)
{
m_flipped = newVFlip;
m_bitmap.bmiHeader.biHeight = m_flipped ? frameHeight : -(int)frameHeight;
return TRUE;
}
BOOL PVideoOutputDevice_Window::SetFrameSize(unsigned width, unsigned height)
{
{
PWaitAndSignal m(mutex);
if (width == frameWidth && height == frameHeight)
return TRUE;
if (!PVideoOutputDeviceRGB::SetFrameSize(width, height))
return FALSE;
m_bitmap.bmiHeader.biWidth = frameWidth;
m_bitmap.bmiHeader.biHeight = m_flipped ? frameHeight : -(int)frameHeight;
m_bitmap.bmiHeader.biSizeImage = frameStore.GetSize();
}
// Must be outside of mutex
if (m_hWnd != NULL) {
RECT rect;
rect.top = 0;
rect.left = 0;
rect.bottom = frameHeight;
rect.right = frameWidth;
AdjustWindowRect(&rect, GetWindowLong(m_hWnd, GWL_STYLE), FALSE);
::SetWindowPos(m_hWnd, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE|SWP_NOZORDER);
}
return TRUE;
}
BOOL PVideoOutputDevice_Window::FrameComplete()
{
PWaitAndSignal m(mutex);
if (m_hWnd == NULL)
return FALSE;
HDC hDC = GetDC(m_hWnd);
Draw(hDC);
ReleaseDC(m_hWnd, hDC);
return TRUE;
}
void PVideoOutputDevice_Window::Draw(HDC hDC)
{
RECT rect;
GetClientRect(m_hWnd, &rect);
int result;
if (frameWidth == (unsigned)rect.right && frameHeight == (unsigned)rect.bottom)
result = SetDIBitsToDevice(hDC,
0, 0, frameWidth, frameHeight,
0, 0, 0, frameHeight,
frameStore.GetPointer(), &m_bitmap, DIB_RGB_COLORS);
else
result = StretchDIBits(hDC,
0, 0, rect.right, rect.bottom,
0, 0, frameWidth, frameHeight,
frameStore.GetPointer(), &m_bitmap, DIB_RGB_COLORS, SRCCOPY);
if (result == 0) {
lastError = ::GetLastError();
PTRACE(2, "VidOut\tDrawing image failed, error=" << lastError);
}
}
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CREATE)
SetWindowLong(hWnd, 0, (LONG)((LPCREATESTRUCT)lParam)->lpCreateParams);
PVideoOutputDevice_Window * vodw = (PVideoOutputDevice_Window *)GetWindowLong(hWnd, 0);
if (vodw != NULL)
return vodw->WndProc(uMsg, wParam, lParam);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void PVideoOutputDevice_Window::HandleDisplay(PThread &, INT)
{
static const char wndClassName[] = "PVideoOutputDevice_Window";
static bool needRegistration = true;
if (needRegistration) {
needRegistration = false;
WNDCLASS wndClass;
memset(&wndClass, 0, sizeof(wndClass));
wndClass.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
wndClass.lpszClassName = wndClassName;
wndClass.lpfnWndProc = ::WndProc;
wndClass.cbWndExtra = sizeof(this);
PAssertOS(RegisterClass(&wndClass));
}
DWORD dwStyle;
HWND hParent;
if (ParseWindowDeviceName(deviceName, &dwStyle, &hParent)) {
PString title;
PINDEX pos = deviceName.Find("TITLE=");
if (pos != P_MAX_INDEX)
title = PString(PString::Literal, &deviceName[pos+6]);
int x = CW_USEDEFAULT;
pos = deviceName.Find("X=");
if (pos != P_MAX_INDEX)
x = atoi(&deviceName[pos+2]);
int y = CW_USEDEFAULT;
pos = deviceName.Find("Y=");
if (pos != P_MAX_INDEX)
y = atoi(&deviceName[pos+2]);
m_hWnd = CreateWindow(wndClassName, title, dwStyle,
x, y, frameWidth, frameHeight,
hParent, NULL, GetModuleHandle(NULL), this);
}
m_started.Signal();
if (m_hWnd != NULL) {
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
DispatchMessage(&msg);
}
}
LRESULT PVideoOutputDevice_Window::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PWaitAndSignal m(mutex);
switch (uMsg) {
case WM_PAINT :
{
PAINTSTRUCT paint;
HDC hDC = BeginPaint(m_hWnd, &paint);
Draw(hDC);
EndPaint(m_hWnd, &paint);
break;
}
case WM_CLOSE :
DestroyWindow(m_hWnd);
m_hWnd = NULL;
break;
case WM_DESTROY:
PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0, 0);
break;
}
return DefWindowProc(m_hWnd, uMsg, wParam, lParam);
}
// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -