- Add GDI video consumer

- Auto-detect support for D3D9
This commit is contained in:
bossiel 2014-09-25 09:15:19 +00:00
parent 144e6da994
commit 8d4e3a181b
15 changed files with 716 additions and 13 deletions

View File

@ -23,6 +23,8 @@
#include "tsk_plugin.h"
#include "tsk_debug.h"
#include "internals/DSUtils.h"
#include <streams.h>
#if !defined(ENABLE_SCREENCAST)
@ -87,7 +89,7 @@ tsk_plugin_def_type_t __plugin_get_def_type_at(int index)
{
switch(index){
case PLUGIN_INDEX_VIDEO_CONSUMER:
return tsk_plugin_def_type_consumer;
return IsD3D9Supported() ? tsk_plugin_def_type_consumer : tsk_plugin_def_type_none;
case PLUGIN_INDEX_VIDEO_PRODUCER:
#if ENABLE_SCREENCAST
case PLUGIN_INDEX_SCREENCAST_PRODUCER:
@ -105,6 +107,9 @@ tsk_plugin_def_media_type_t __plugin_get_def_media_type_at(int index)
{
switch(index){
case PLUGIN_INDEX_VIDEO_CONSUMER:
{
return IsD3D9Supported() ? tsk_plugin_def_media_type_video : tsk_plugin_def_media_type_none;
}
case PLUGIN_INDEX_VIDEO_PRODUCER:
{
return tsk_plugin_def_media_type_video;
@ -128,7 +133,7 @@ tsk_plugin_def_ptr_const_t __plugin_get_def_at(int index)
switch(index){
case PLUGIN_INDEX_VIDEO_CONSUMER:
{
return plugin_video_dshow_consumer_plugin_def_t;
return IsD3D9Supported() ? plugin_video_dshow_consumer_plugin_def_t : tsk_null;
}
case PLUGIN_INDEX_VIDEO_PRODUCER:
{

View File

@ -19,6 +19,7 @@
#include <atlbase.h>
#include <atlstr.h>
#include <d3d9.h>
#include "tsk_debug.h"
@ -46,6 +47,74 @@ bool IsMainThread()
return false;
}
bool IsD3D9Supported()
{
static bool g_bChecked = false;
static bool g_bSupported = false;
if (g_bChecked) {
return g_bSupported;
}
g_bChecked = true;
HRESULT hr = S_OK;
IDirect3D9* pD3D = NULL;
D3DDISPLAYMODE mode = { 0 };
D3DPRESENT_PARAMETERS pp = {0};
IDirect3DDevice9* pDevice = NULL;
if (!(pD3D = Direct3DCreate9(D3D_SDK_VERSION))) {
hr = E_OUTOFMEMORY;
goto bail;
}
hr = pD3D->GetAdapterDisplayMode(
D3DADAPTER_DEFAULT,
&mode
);
if (FAILED(hr)) {
goto bail;
}
hr = pD3D->CheckDeviceType(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
mode.Format,
D3DFMT_X8R8G8B8,
TRUE // windowed
);
if (FAILED(hr)) {
goto bail;
}
pp.BackBufferFormat = D3DFMT_X8R8G8B8;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
pp.Windowed = TRUE;
pp.hDeviceWindow = GetDesktopWindow();
hr = pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
pp.hDeviceWindow,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&pp,
&pDevice
);
if (FAILED(hr)) {
goto bail;
}
// Everythings is OK
g_bSupported = TRUE;
TSK_DEBUG_INFO("D3D9 supported");
bail:
if (!g_bSupported) {
TSK_DEBUG_WARN("D3D9 not supported");
}
SAFE_RELEASE(pDevice);
SAFE_RELEASE(pD3D);
return g_bSupported;
}
IPin *GetPin(IBaseFilter *filter, PIN_DIRECTION direction)
{
IEnumPins *enumPins = NULL;

View File

@ -64,6 +64,8 @@ HWND GetMainWindow();
bool IsMainThread();
bool IsD3D9Supported();
IPin *GetPin(IBaseFilter *pFilter, PIN_DIRECTION dir);
HRESULT ConnectFilters(IGraphBuilder *graphBuilder, IBaseFilter *source, IBaseFilter *destination, AM_MEDIA_TYPE *mediaType = NULL);

View File

@ -132,9 +132,12 @@ tsk_plugin_def_type_t __plugin_get_def_type_at(int index)
#endif
#if PLUGIN_MF_ENABLE_VIDEO_IO
case PLUGIN_INDEX_VIDEO_CONSUMER:
{
return MFUtils::IsD3D9Supported() ? tsk_plugin_def_type_consumer : tsk_plugin_def_type_none;
}
case PLUGIN_INDEX_VIDEO_PRODUCER:
{
return (index == PLUGIN_INDEX_VIDEO_CONSUMER) ? tsk_plugin_def_type_consumer : tsk_plugin_def_type_producer;
return tsk_plugin_def_type_producer;
}
#endif
#if PLUGIN_MF_ENABLE_VIDEO_CONVERTER
@ -168,6 +171,9 @@ tsk_plugin_def_media_type_t __plugin_get_def_media_type_at(int index)
#endif
#if PLUGIN_MF_ENABLE_VIDEO_IO
case PLUGIN_INDEX_VIDEO_CONSUMER:
{
return MFUtils::IsD3D9Supported() ? tsk_plugin_def_media_type_video : tsk_plugin_def_media_type_none;
}
case PLUGIN_INDEX_VIDEO_PRODUCER:
{
return tsk_plugin_def_media_type_video;
@ -202,7 +208,7 @@ tsk_plugin_def_ptr_const_t __plugin_get_def_at(int index)
}
case PLUGIN_INDEX_VIDEO_CONSUMER:
{
return plugin_win_mf_consumer_video_plugin_def_t;
return MFUtils::IsD3D9Supported() ? plugin_win_mf_consumer_video_plugin_def_t : tsk_null;
}
#endif
#if PLUGIN_MF_ENABLE_AUDIO_IO

View File

@ -25,12 +25,14 @@
#include <initguid.h>
#include <wmcodecdsp.h>
#include <d3d9.h>
#include <assert.h>
#ifdef _MSC_VER
#pragma comment(lib, "strmiids.lib")
#pragma comment(lib, "wmcodecdspuuid.lib")
#pragma comment(lib, "d3d9")
#endif
#if !defined(PLUGIN_MF_DISABLE_CODECS)
@ -60,6 +62,9 @@ DWORD MFUtils::g_dwMinorVersion = -1;
BOOL MFUtils::g_bLowLatencyH264Checked = FALSE;
BOOL MFUtils::g_bLowLatencyH264Supported = FALSE;
BOOL MFUtils::g_bD3D9Checked = FALSE;
BOOL MFUtils::g_bD3D9Supported = FALSE;
const TOPOID MFUtils::g_ullTopoIdSinkMain = 111;
const TOPOID MFUtils::g_ullTopoIdSinkPreview = 222;
const TOPOID MFUtils::g_ullTopoIdSource = 333;
@ -134,6 +139,77 @@ HRESULT MFUtils::Shutdown()
return S_OK;
}
BOOL MFUtils::IsD3D9Supported()
{
if (MFUtils::g_bD3D9Checked)
{
return MFUtils::g_bD3D9Supported;
}
MFUtils::g_bD3D9Checked = TRUE;
HRESULT hr = S_OK;
IDirect3D9* pD3D = NULL;
D3DDISPLAYMODE mode = { 0 };
D3DPRESENT_PARAMETERS pp = {0};
IDirect3DDevice9* pDevice = NULL;
CHECK_HR(hr = MFUtils::Startup());
if (!(pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
{
CHECK_HR(hr = E_OUTOFMEMORY);
}
hr = pD3D->GetAdapterDisplayMode(
D3DADAPTER_DEFAULT,
&mode
);
if (FAILED(hr))
{
goto bail;
}
hr = pD3D->CheckDeviceType(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
mode.Format,
D3DFMT_X8R8G8B8,
TRUE // windowed
);
if (FAILED(hr))
{
goto bail;
}
pp.BackBufferFormat = D3DFMT_X8R8G8B8;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
pp.Windowed = TRUE;
pp.hDeviceWindow = GetDesktopWindow();
hr = pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
pp.hDeviceWindow,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&pp,
&pDevice
);
if (FAILED(hr))
{
goto bail;
}
// Everythings is OK
MFUtils::g_bD3D9Supported = TRUE;
TSK_DEBUG_INFO("D3D9 supported");
bail:
if (!MFUtils::g_bD3D9Supported) {
TSK_DEBUG_WARN("D3D9 not supported");
}
SafeRelease(&pDevice);
SafeRelease(&pD3D);
return MFUtils::g_bD3D9Supported;
}
BOOL MFUtils::IsLowLatencyH264Supported()
{
if(MFUtils::g_bLowLatencyH264Checked)

View File

@ -55,6 +55,7 @@ public:
static HRESULT Startup();
static HRESULT Shutdown();
static BOOL IsD3D9Supported();
static BOOL IsLowLatencyH264Supported();
static HRESULT IsAsyncMFT(
@ -244,6 +245,9 @@ private:
static BOOL g_bLowLatencyH264Checked;
static BOOL g_bLowLatencyH264Supported;
static BOOL g_bD3D9Checked;
static BOOL g_bD3D9Supported;
public:
static const TOPOID g_ullTopoIdSinkMain;
static const TOPOID g_ullTopoIdSinkPreview;

View File

@ -137,9 +137,7 @@ static int plugin_win_mf_consumer_video_set(tmedia_consumer_t *self, const tmedi
hr = ResetDevice(pSelf);
}
tsk_safeobj_unlock(pSelf); // unblock consumer thread
}
}
}
}
else if(param->value_type == tmedia_pvt_int32)
@ -1536,6 +1534,8 @@ static tsk_object_t* plugin_win_mf_consumer_video_ctor(tsk_object_t * self, va_l
TMEDIA_CONSUMER(pSelf)->video.display.width = 0; // use codec value
TMEDIA_CONSUMER(pSelf)->video.display.height = 0; // use codec value
TMEDIA_CONSUMER(pSelf)->video.display.auto_resize = tsk_true;
TSK_DEBUG_INFO("Create WinMF video consumer");
}
return self;
}

View File

@ -386,6 +386,7 @@ static inline const GUID& _plugin_win_mf_converter_video_ms_get_pixfmt(tmedia_ch
{
switch(chroma){
case tmedia_chroma_rgb24:
case tmedia_chroma_bgr24:
return MFVideoFormat_RGB24;
case tmedia_chroma_rgb565le:
return MFVideoFormat_RGB565;

View File

@ -625,6 +625,8 @@ static tsk_object_t* plugin_win_mf_producer_video_ctor(tsk_object_t * self, va_l
TMEDIA_PRODUCER(pSelf)->video.fps = 15;
TMEDIA_PRODUCER(pSelf)->video.width = 352;
TMEDIA_PRODUCER(pSelf)->video.height = 288;
TSK_DEBUG_INFO("Create WinMF video producer");
}
return self;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011-2014 Doubango Telecom <http://www.doubango.org>
/* Copyright (C) 2014 Mamadou DIOP
*
* This file is part of Open Source Doubango Framework.
*
@ -26,7 +26,7 @@
TDAV_BEGIN_DECLS
TINYDAV_GEXTERN const tmedia_consumer_plugin_def_t *tdav_consumer_gdi_plugin_def_t;
TINYDAV_GEXTERN const tmedia_consumer_plugin_def_t *tdav_consumer_video_gdi_plugin_def_t;
TDAV_END_DECLS

View File

@ -105,6 +105,7 @@ static const tsk_size_t __codec_plugins_all_count = sizeof(__codec_plugins_all)/
#include "tinydav/audio/wasapi/tdav_consumer_wasapi.h"
#include "tinydav/video/winm/tdav_consumer_winm.h"
#include "tinydav/video/mf/tdav_consumer_video_mf.h"
#include "tinydav/video/gdi/tdav_consumer_video_gdi.h"
#include "tinydav/t140/tdav_consumer_t140.h"
// Producers
@ -351,6 +352,9 @@ int tdav_init()
#elif HAVE_WASAPI
tmedia_consumer_plugin_register(tdav_consumer_wasapi_plugin_def_t);
#endif
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows GDI
tmedia_consumer_plugin_register(tdav_consumer_video_gdi_plugin_def_t);
#endif
#if HAVE_WINM // Windows Media (WP8)
tmedia_consumer_plugin_register(tdav_consumer_winm_plugin_def_t);
#endif
@ -588,6 +592,9 @@ int tdav_deinit()
#if HAVE_WASAPI
tmedia_consumer_plugin_unregister(tdav_consumer_wasapi_plugin_def_t);
#endif
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows GDI
tmedia_consumer_plugin_unregister(tdav_consumer_video_gdi_plugin_def_t);
#endif
#if HAVE_WINM // Windows Media (WP8)
tmedia_consumer_plugin_unregister(tdav_consumer_winm_plugin_def_t);
#endif

View File

@ -0,0 +1,525 @@
/* Copyright (C) 2014 Mamadou DIOP
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*/
#include "tinydav/video/gdi/tdav_consumer_video_gdi.h"
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT
#include <windows.h>
#include "tsk_memory.h"
#include "tsk_string.h"
#include "tsk_safeobj.h"
#include "tsk_debug.h"
#define CHECK_HR(x) { HRESULT __hr__ = (x); if (FAILED(__hr__)) { TSK_DEBUG_ERROR("Operation Failed (%08x)", __hr__); goto bail; } }
static HRESULT HookWindow(struct tdav_consumer_video_gdi_s *p_gdi, HWND hWnd, BOOL bFullScreenWindow);
static HRESULT UnhookWindow(struct tdav_consumer_video_gdi_s *p_gdi, BOOL bFullScreenWindow);
static HRESULT SetFullscreen(struct tdav_consumer_video_gdi_s *p_gdi, BOOL bFullScreen);
static HWND CreateFullScreenWindow(struct tdav_consumer_video_gdi_s *p_gdi);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
typedef struct tdav_consumer_video_gdi_s
{
TMEDIA_DECLARE_CONSUMER;
BOOL bStarted, bPrepared, bPaused, bFullScreen, bWindowHooked, bWindowHookedFullScreen;
HWND hWindow;
WNDPROC wndProc;
HWND hWindowFullScreen;
WNDPROC wndProcFullScreen;
BITMAPINFO bitmapInfo;
void* pBuffer;
TSK_DECLARE_SAFEOBJ;
}
tdav_consumer_video_gdi_t;
/* ============ Media Consumer Interface ================= */
static int tdav_consumer_video_gdi_set(tmedia_consumer_t *self, const tmedia_param_t* param)
{
int ret = 0;
tdav_consumer_video_gdi_t* p_gdi = (tdav_consumer_video_gdi_t*)self;
HRESULT hr = S_OK;
if (!self || !param) {
TSK_DEBUG_ERROR("Invalid parameter");
CHECK_HR(hr = E_POINTER);
}
if (param->value_type == tmedia_pvt_int64) {
if (tsk_striequals(param->key, "remote-hwnd")) {
HWND hWnd = ((HWND)*((int64_t*)param->value));
if (hWnd != p_gdi->hWindow) {
tsk_safeobj_lock(p_gdi); // block consumer thread
UnhookWindow(p_gdi, FALSE);
p_gdi->hWindow = hWnd;
tsk_safeobj_unlock(p_gdi); // unblock consumer thread
}
}
}
else if(param->value_type == tmedia_pvt_int32) {
if(tsk_striequals(param->key, "fullscreen")) {
BOOL bFullScreen = !!*((int32_t*)param->value);
// FIXME: full screen not supported yet
TSK_DEBUG_INFO("[GDI video consumer] Full Screen = %d", bFullScreen);
CHECK_HR(hr = SetFullscreen(p_gdi, bFullScreen));
}
}
CHECK_HR(hr);
bail:
return SUCCEEDED(hr) ? 0 : -1;
}
static int tdav_consumer_video_gdi_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec)
{
tdav_consumer_video_gdi_t* p_gdi = (tdav_consumer_video_gdi_t*)self;
if (!p_gdi || !codec && codec->plugin) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
TMEDIA_CONSUMER(p_gdi)->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps;
TMEDIA_CONSUMER(p_gdi)->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width;
TMEDIA_CONSUMER(p_gdi)->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height;
if (!TMEDIA_CONSUMER(p_gdi)->video.display.width) {
TMEDIA_CONSUMER(p_gdi)->video.display.width = TMEDIA_CONSUMER(p_gdi)->video.in.width;
}
if (!TMEDIA_CONSUMER(p_gdi)->video.display.height) {
TMEDIA_CONSUMER(p_gdi)->video.display.height = TMEDIA_CONSUMER(p_gdi)->video.in.height;
}
ZeroMemory(&p_gdi->bitmapInfo, sizeof(p_gdi->bitmapInfo));
p_gdi->bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
p_gdi->bitmapInfo.bmiHeader.biPlanes = 1;
p_gdi->bitmapInfo.bmiHeader.biBitCount = 24; // RGB24
p_gdi->bitmapInfo.bmiHeader.biCompression = BI_RGB;
p_gdi->bitmapInfo.bmiHeader.biWidth = TMEDIA_CONSUMER(p_gdi)->video.in.width;
p_gdi->bitmapInfo.bmiHeader.biHeight = TMEDIA_CONSUMER(p_gdi)->video.in.height; // do not MULT(-1), already flipped
p_gdi->bitmapInfo.bmiHeader.biSizeImage = TMEDIA_CONSUMER(p_gdi)->video.in.width * TMEDIA_CONSUMER(p_gdi)->video.in.height *
(p_gdi->bitmapInfo.bmiHeader.biBitCount >> 3);
return 0;
}
static int tdav_consumer_video_gdi_start(tmedia_consumer_t* self)
{
tdav_consumer_video_gdi_t* p_gdi = (tdav_consumer_video_gdi_t*)self;
if (!p_gdi) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(p_gdi);
p_gdi->bPaused = FALSE;
p_gdi->bStarted = TRUE;
tsk_safeobj_unlock(p_gdi);
return 0;
}
static int tdav_consumer_video_gdi_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr)
{
tdav_consumer_video_gdi_t* p_gdi = (tdav_consumer_video_gdi_t*)self;
int ret = 0;
HWND* p_Window;
BOOL* p_bWindowHooked;
if (!p_gdi) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(p_gdi);
if (!p_gdi->bStarted || p_gdi->bPaused) {
TSK_DEBUG_INFO("GDI consumer stopped or paused");
goto bail;
}
if (p_gdi->bitmapInfo.bmiHeader.biSizeImage != size) {
tsk_size_t xNewSize = TMEDIA_CONSUMER(p_gdi)->video.in.width * TMEDIA_CONSUMER(p_gdi)->video.in.height * (p_gdi->bitmapInfo.bmiHeader.biBitCount >> 3);
TSK_DEBUG_INFO("GDI input size changed: %u->%u", p_gdi->bitmapInfo.bmiHeader.biSizeImage, size);
if (xNewSize != size) {
TSK_DEBUG_ERROR("GDI consumer: chroma issue?");
ret = -1;
goto bail;
}
p_gdi->bitmapInfo.bmiHeader.biWidth = TMEDIA_CONSUMER(p_gdi)->video.in.width;
p_gdi->bitmapInfo.bmiHeader.biHeight = TMEDIA_CONSUMER(p_gdi)->video.in.height; // do not MULT(-1), already flipped
p_gdi->bitmapInfo.bmiHeader.biSizeImage = xNewSize;
p_gdi->pBuffer = tsk_realloc(p_gdi->pBuffer, p_gdi->bitmapInfo.bmiHeader.biSizeImage);
}
p_Window = p_gdi->bFullScreen ? &p_gdi->hWindowFullScreen : &p_gdi->hWindow;
p_bWindowHooked = p_gdi->bFullScreen ? &p_gdi->bWindowHookedFullScreen : &p_gdi->bWindowHooked;
if (*p_Window) {
if (!*p_bWindowHooked) {
// Do not hook "hWnd" as it could be the fullscreen handle which is always hooked.
CHECK_HR(HookWindow(p_gdi, *p_Window, p_gdi->bFullScreen));
}
if (!p_gdi->pBuffer) {
p_gdi->pBuffer = tsk_realloc(p_gdi->pBuffer, p_gdi->bitmapInfo.bmiHeader.biSizeImage);
}
if (p_gdi->pBuffer) {
memcpy(p_gdi->pBuffer, buffer, size);
InvalidateRect(*p_Window, NULL, TRUE);
}
}
bail:
tsk_safeobj_unlock(p_gdi);
return ret;
}
static int tdav_consumer_video_gdi_pause(tmedia_consumer_t* self)
{
tdav_consumer_video_gdi_t* p_gdi = (tdav_consumer_video_gdi_t*)self;
if (!p_gdi) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(p_gdi);
p_gdi->bPaused = TRUE;
tsk_safeobj_unlock(p_gdi);
return 0;
}
static int tdav_consumer_video_gdi_stop(tmedia_consumer_t* self)
{
tdav_consumer_video_gdi_t* p_gdi = (tdav_consumer_video_gdi_t*)self;
if (!p_gdi) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(p_gdi);
p_gdi->bStarted = FALSE;
p_gdi->bPaused = FALSE;
SetFullscreen(p_gdi, FALSE);
UnhookWindow(p_gdi, TRUE);
UnhookWindow(p_gdi, FALSE);
tsk_safeobj_unlock(p_gdi);
return 0;
}
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
case WM_SIZE:
case WM_MOVE:
{
struct tdav_consumer_video_gdi_s* p_gdi = ((struct tdav_consumer_video_gdi_s*)GetPropA(hWnd, "Self"));
if (p_gdi) {
}
break;
}
case WM_PAINT:
{
struct tdav_consumer_video_gdi_s* p_gdi = ((struct tdav_consumer_video_gdi_s*)GetPropA(hWnd, "Self"));
if (p_gdi) {
tsk_safeobj_lock(p_gdi);
if (p_gdi->bStarted && !p_gdi->bPaused && p_gdi->pBuffer) {
PAINTSTRUCT ps;
HDC hdc;
RECT rc, logical_rect;
int height, width, i, x, y;
HDC dc_mem, all_dc[2];
HBITMAP bmp_mem;
HGDIOBJ bmp_old;
POINT logical_area;
HBRUSH brush;
if (!(hdc = BeginPaint(hWnd, &ps))) {
goto paint_done;
}
if (!GetClientRect(hWnd, &rc)) {
EndPaint(hWnd, &ps);
goto paint_done;
}
height = abs(p_gdi->bitmapInfo.bmiHeader.biHeight);
width = p_gdi->bitmapInfo.bmiHeader.biWidth;
dc_mem = CreateCompatibleDC(ps.hdc);
SetStretchBltMode(dc_mem, HALFTONE);
// Set the map mode so that the ratio will be maintained for us.
all_dc[0] = ps.hdc, all_dc[1] = dc_mem;
for (i = 0; i < sizeof(all_dc)/sizeof(all_dc[0]); ++i) {
SetMapMode(all_dc[i], MM_ISOTROPIC);
SetWindowExtEx(all_dc[i], width, height, NULL);
SetViewportExtEx(all_dc[i], rc.right, rc.bottom, NULL);
}
bmp_mem = CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom);
bmp_old = SelectObject(dc_mem, bmp_mem);
logical_area.x = rc.right, logical_area.y = rc.bottom;
DPtoLP(ps.hdc, &logical_area, 1);
brush = CreateSolidBrush(RGB(0, 0, 0));
logical_rect.left = 0, logical_rect.top = 0, logical_rect.right = logical_area.x, logical_rect.bottom = logical_area.y;
FillRect(dc_mem, &logical_rect, brush);
DeleteObject(brush);
x = (logical_area.x / 2) - (width / 2);
y = (logical_area.y / 2) - (height / 2);
StretchDIBits(dc_mem, x, y, width, height,
0, 0, width, height, p_gdi->pBuffer, &p_gdi->bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
BitBlt(ps.hdc, 0, 0, logical_area.x, logical_area.y,
dc_mem, 0, 0, SRCCOPY);
// Cleanup.
SelectObject(dc_mem, bmp_old);
DeleteObject(bmp_mem);
DeleteDC(dc_mem);
EndPaint(hWnd, &ps);
}
paint_done:
tsk_safeobj_unlock(p_gdi);
}
break;
}
case WM_ERASEBKGND:
{
return TRUE; // avoid background erasing.
}
case WM_CHAR:
case WM_KEYUP:
{
struct tdav_consumer_video_gdi_s* p_gdi = ((struct tdav_consumer_video_gdi_s*)GetPropA(hWnd, "Self"));
if (p_gdi)
{
SetFullscreen(p_gdi, FALSE);
}
break;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
static HRESULT HookWindow(struct tdav_consumer_video_gdi_s *p_gdi, HWND hWnd, BOOL bFullScreenWindow)
{
HRESULT hr = S_OK;
HWND* p_Window = bFullScreenWindow ? &p_gdi->hWindowFullScreen : &p_gdi->hWindow;
WNDPROC* p_wndProc = bFullScreenWindow ? &p_gdi->wndProcFullScreen : &p_gdi->wndProc;
BOOL* p_bWindowHooked = bFullScreenWindow ? &p_gdi->bWindowHookedFullScreen : &p_gdi->bWindowHooked;
tsk_safeobj_lock(p_gdi);
CHECK_HR(hr = UnhookWindow(p_gdi, bFullScreenWindow));
if ((*p_Window = hWnd)) {
*p_wndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG)WndProc);
if (!*p_wndProc) {
TSK_DEBUG_ERROR("HookWindowLongPtr() failed with errcode=%d", GetLastError());
CHECK_HR(hr = E_FAIL);
}
*p_bWindowHooked = TRUE;
SetPropA(*p_Window, "Self", p_gdi);
}
bail:
tsk_safeobj_unlock(p_gdi);
return S_OK;
}
static HRESULT UnhookWindow(struct tdav_consumer_video_gdi_s *p_gdi, BOOL bFullScreenWindow)
{
HWND* p_Window = bFullScreenWindow ? &p_gdi->hWindowFullScreen : &p_gdi->hWindow;
WNDPROC* p_wndProc = bFullScreenWindow ? &p_gdi->wndProcFullScreen : &p_gdi->wndProc;
BOOL* p_bWindowHooked = bFullScreenWindow ? &p_gdi->bWindowHookedFullScreen : &p_gdi->bWindowHooked;
tsk_safeobj_lock(p_gdi);
if (*p_Window && *p_wndProc) {
SetWindowLongPtr(*p_Window, GWL_WNDPROC, (LONG)*p_wndProc);
*p_wndProc = NULL;
}
if (*p_Window) {
if (p_gdi->pBuffer) {
memset(p_gdi->pBuffer, 0, p_gdi->bitmapInfo.bmiHeader.biSizeImage);
}
InvalidateRect(*p_Window, NULL, FALSE);
}
*p_bWindowHooked = FALSE;
tsk_safeobj_unlock(p_gdi);
return S_OK;
}
static HRESULT SetFullscreen(struct tdav_consumer_video_gdi_s *p_gdi, BOOL bFullScreen)
{
HRESULT hr = S_OK;
if (!p_gdi) {
CHECK_HR(hr = E_POINTER);
}
if (p_gdi->bFullScreen != bFullScreen) {
tsk_safeobj_lock(p_gdi);
if (bFullScreen) {
HWND hWnd = CreateFullScreenWindow(p_gdi);
if (hWnd) {
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
HookWindow(p_gdi, hWnd, TRUE);
}
}
else if(p_gdi->hWindowFullScreen) {
ShowWindow(p_gdi->hWindowFullScreen, SW_HIDE);
UnhookWindow(p_gdi, TRUE);
}
p_gdi->bFullScreen = bFullScreen;
tsk_safeobj_unlock(p_gdi);
CHECK_HR(hr);
}
bail:
return hr;
}
static HWND CreateFullScreenWindow(struct tdav_consumer_video_gdi_s *p_gdi)
{
HRESULT hr = S_OK;
if(!p_gdi) {
return NULL;
}
if (!p_gdi->hWindowFullScreen) {
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClass(&wc);
p_gdi->hWindowFullScreen = CreateWindowEx(
0,
wc.lpszClassName,
L"Doubango's Video Consumer Fullscreen",
WS_EX_TOPMOST | WS_POPUP,
0, 0,
GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
NULL,
NULL,
GetModuleHandle(NULL),
NULL);
SetPropA(p_gdi->hWindowFullScreen, "Self", p_gdi);
}
return p_gdi->hWindowFullScreen;
}
//
// GDI video consumer object definition
//
/* constructor */
static tsk_object_t* tdav_consumer_video_gdi_ctor(tsk_object_t * self, va_list * app)
{
tdav_consumer_video_gdi_t *p_gdi = (tdav_consumer_video_gdi_t *)self;
if (p_gdi) {
/* init base */
tmedia_consumer_init(TMEDIA_CONSUMER(p_gdi));
TMEDIA_CONSUMER(p_gdi)->video.display.chroma = tmedia_chroma_bgr24;
/* init self */
TMEDIA_CONSUMER(p_gdi)->video.fps = 15;
TMEDIA_CONSUMER(p_gdi)->video.display.width = 352;
TMEDIA_CONSUMER(p_gdi)->video.display.height = 288;
TMEDIA_CONSUMER(p_gdi)->video.display.auto_resize = tsk_true;
}
return self;
}
/* destructor */
static tsk_object_t* tdav_consumer_video_gdi_dtor(tsk_object_t * self)
{
tdav_consumer_video_gdi_t *p_gdi = (tdav_consumer_video_gdi_t *)self;
if (p_gdi) {
/* stop */
tdav_consumer_video_gdi_stop((tmedia_consumer_t*)self);
/* deinit base */
tmedia_consumer_deinit(TMEDIA_CONSUMER(p_gdi));
/* deinit self */
TSK_FREE(p_gdi->pBuffer);
tsk_safeobj_deinit(p_gdi);
}
return self;
}
/* object definition */
static const tsk_object_def_t tdav_consumer_video_gdi_def_s =
{
sizeof(tdav_consumer_video_gdi_t),
tdav_consumer_video_gdi_ctor,
tdav_consumer_video_gdi_dtor,
tsk_null,
};
/* plugin definition*/
static const tmedia_consumer_plugin_def_t tdav_consumer_video_gdi_plugin_def_s =
{
&tdav_consumer_video_gdi_def_s,
tmedia_video,
"Microsoft DirectShow consumer (using custom source)",
tdav_consumer_video_gdi_set,
tdav_consumer_video_gdi_prepare,
tdav_consumer_video_gdi_start,
tdav_consumer_video_gdi_consume,
tdav_consumer_video_gdi_pause,
tdav_consumer_video_gdi_stop
};
const tmedia_consumer_plugin_def_t *tdav_consumer_video_gdi_plugin_def_t = &tdav_consumer_video_gdi_plugin_def_s;
#endif /* TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT */

View File

@ -132,8 +132,6 @@ static inline enum FourCC _tdav_converter_video_libyuv_get_pixfmt(tmedia_chroma_
}
}
static int tdav_converter_video_libyuv_init(tmedia_converter_video_t* self, tsk_size_t srcWidth, tsk_size_t srcHeight, tmedia_chroma_t srcChroma, tsk_size_t dstWidth, tsk_size_t dstHeight, tmedia_chroma_t dstChroma)
{
TSK_DEBUG_INFO("Initializing new LibYUV Video Converter src=(%dx%d@%d) dst=(%dx%d@%d)", srcWidth, srcHeight, srcChroma, dstWidth, dstHeight, dstChroma);

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Version="9,00"
Name="tinyDAV"
ProjectGUID="{8E2F0B2E-2596-4010-BF4A-2F688975B5C1}"
RootNamespace="tinyDAV"
@ -522,6 +522,10 @@
<Filter
Name="gdi"
>
<File
RelativePath=".\include\tinydav\video\gdi\tdav_consumer_video_gdi.h"
>
</File>
<File
RelativePath=".\include\tinydav\video\gdi\tdav_producer_screencast_gdi.h"
>
@ -918,6 +922,10 @@
<Filter
Name="gdi"
>
<File
RelativePath=".\src\video\gdi\tdav_consumer_video_gdi.c"
>
</File>
<File
RelativePath=".\src\video\gdi\tdav_producer_screencast_gdi.c"
>

View File

@ -829,7 +829,7 @@ int tnet_getbestsource(const char* destination, tnet_port_t port, tnet_socket_ty
}
if ((rlen = write(s, rtm, l)) < 0) {
printf("writing to routing socket");
TSK_DEBUG_INFO("writing to routing socket");
// TODO
}
do {