parent
144e6da994
commit
8d4e3a181b
|
@ -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:
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue