📄 vfw.cxx
字号:
PSyncPoint m_started;
BITMAPINFO m_bitmap;
bool m_flipped;
int m_lastX;
int m_lastY;
};
#define DEFAULT_STYLE (WS_POPUP|WS_BORDER|WS_SYSMENU|WS_CAPTION)
#define DEFAULT_TITLE "Video Output"
static bool ParseWindowDeviceName(const PString & deviceName, DWORD * dwStylePtr = NULL, HWND * hWndParentPtr = NULL)
{
if (deviceName.Find("MSWIN") != 0)
return false;
PINDEX pos = deviceName.Find("STYLE=");
DWORD dwStyle = pos == P_MAX_INDEX ? DEFAULT_STYLE : strtoul(((const char *)deviceName)+pos+6, NULL, 0);
if ((dwStyle&(WS_POPUP|WS_CHILD)) == 0) {
PTRACE(1, "VidOut\tWindow must be WS_POPUP or WS_CHILD window.");
return false;
}
HWND hWndParent = NULL;
pos = deviceName.Find("PARENT=");
if (pos != P_MAX_INDEX) {
hWndParent = (HWND)strtoul(((const char *)deviceName)+pos+7, 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 (hWndParent == NULL && (dwStyle&WS_POPUP) == 0) {
PTRACE(1, "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 PNEW PVideoOutputDevice_Window; }
virtual PStringArray 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 = PFalse;
m_lastX = 0;
m_lastY = 0;
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();
}
PStringArray PVideoOutputDevice_Window::GetOutputDeviceNames()
{
return psprintf("MSWIN STYLE=0x%08X TITLE=\"%s\"", DEFAULT_STYLE, DEFAULT_TITLE);
}
PBoolean PVideoOutputDevice_Window::Open(const PString & name, PBoolean startImmediate)
{
Close();
m_openCloseMutex.Wait();
deviceName = name;
m_thread = PThread::Create(PCREATE_NOTIFIER(HandleDisplay), 0,
PThread::NoAutoDeleteThread, PThread::NormalPriority,
"VidOut:%x");
m_openCloseMutex.Signal();
m_started.Wait();
PWaitAndSignal m(m_openCloseMutex);
return startImmediate ? Start() : m_hWnd != NULL;
}
PBoolean PVideoOutputDevice_Window::IsOpen()
{
return m_hWnd != NULL;
}
PBoolean PVideoOutputDevice_Window::Close()
{
PWaitAndSignal m(m_openCloseMutex);
if (m_hWnd == NULL)
return PFalse;
SendMessage(m_hWnd, WM_CLOSE, 0, 0);
m_thread->WaitForTermination(3000);
delete m_thread;
m_thread = NULL;
return PTrue;
}
PBoolean PVideoOutputDevice_Window::Start()
{
PWaitAndSignal m(m_openCloseMutex);
if (m_hWnd == NULL)
return PFalse;
ShowWindow(m_hWnd, SW_SHOW);
return PTrue;
}
PBoolean PVideoOutputDevice_Window::Stop()
{
PWaitAndSignal m(m_openCloseMutex);
if (m_hWnd != NULL)
return ShowWindow(m_hWnd, SW_HIDE);
return PFalse;
}
PBoolean 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 PTrue;
}
return PFalse;
}
PBoolean PVideoOutputDevice_Window::GetVFlipState()
{
return m_flipped;
}
PBoolean PVideoOutputDevice_Window::SetVFlipState(PBoolean newVFlip)
{
m_flipped = newVFlip;
m_bitmap.bmiHeader.biHeight = m_flipped ? frameHeight : -(int)frameHeight;
return PTrue;
}
PBoolean PVideoOutputDevice_Window::SetFrameSize(unsigned width, unsigned height)
{
{
PWaitAndSignal m(mutex);
if (width == frameWidth && height == frameHeight)
return PTrue;
if (!PVideoOutputDeviceRGB::SetFrameSize(width, height))
return PFalse;
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;
::AdjustWindowRectEx(&rect, GetWindowLong(m_hWnd, GWL_STYLE), PFalse, 0L);
::SetWindowPos(m_hWnd, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE|SWP_NOZORDER);
}
return PTrue;
}
PBoolean PVideoOutputDevice_Window::FrameComplete()
{
PWaitAndSignal m(mutex);
if (m_hWnd == NULL)
return PFalse;
HDC hDC = GetDC(m_hWnd);
Draw(hDC);
ReleaseDC(m_hWnd, hDC);
return PTrue;
}
PBoolean PVideoOutputDevice_Window::GetPosition(int & x, int & y) const
{
x = m_lastX;
y = m_lastY;
return PTrue;
}
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)
{
#ifndef _WIN32_WCE
static const char wndClassName[] = "PVideoOutputDevice_Window";
#else
static LPCWSTR wndClassName = L"PVideoOutputDevice_Window";
#endif
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.lpszClassName = wndClassName;
wndClass.lpfnWndProc = ::WndProc;
wndClass.cbWndExtra = sizeof(this);
PAssertOS(RegisterClass(&wndClass));
}
DWORD dwStyle;
HWND hParent;
if (ParseWindowDeviceName(deviceName, &dwStyle, &hParent)) {
PString title = DEFAULT_TITLE;
PINDEX pos = deviceName.Find("TITLE=\"");
if (pos != P_MAX_INDEX) {
pos += 6;
PINDEX quote = deviceName.FindLast('"');
PString quotedTitle = deviceName(pos, quote > pos ? quote : P_MAX_INDEX);
title = PString(PString::Literal, quotedTitle);
}
pos = deviceName.Find("X=");
m_lastX = pos != P_MAX_INDEX ? atoi(&deviceName[pos+2]) : CW_USEDEFAULT;
pos = deviceName.Find("Y=");
m_lastY = pos != P_MAX_INDEX ? atoi(&deviceName[pos+2]) : CW_USEDEFAULT;
PVarString windowTitle = title;
m_hWnd = CreateWindow(wndClassName,
windowTitle,
dwStyle,
m_lastX, m_lastY, 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_MOVE :
if (m_hWnd != NULL) {
RECT rect;
GetWindowRect(m_hWnd, &rect);
m_lastX = rect.left;
m_lastY = rect.top;
}
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);
}
#endif // P_VIDEO
// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -