diff options
Diffstat (limited to 'plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx')
-rwxr-xr-x | plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx | 1689 |
1 files changed, 808 insertions, 881 deletions
diff --git a/plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx b/plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx index dfd7e72..3d47f4c 100755 --- a/plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx +++ b/plugins/pluginDirectShow/plugin_video_dshow_consumer.cxx @@ -1,17 +1,17 @@ /* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org> -* +* * 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. */ @@ -55,33 +55,32 @@ const DWORD NUM_BACK_BUFFERS = 2; (*ppT)->Release(); \ *ppT = NULL; \ } \ -} +} #undef CHECK_HR // In CHECK_HR(x) When (x) is a function it will be executed twice when used in "TSK_DEBUG_ERROR(x)" and "If(x)" #define CHECK_HR(x) { HRESULT __hr__ = (x); if (FAILED(__hr__)) { TSK_DEBUG_ERROR("Operation Failed (%08x)", __hr__); goto bail; } } -typedef struct _DSRatio - { +typedef struct _DSRatio { DWORD Numerator; DWORD Denominator; - } DSRatio; +} DSRatio; static HRESULT CreateDeviceD3D9( - HWND hWnd, - IDirect3DDevice9** ppDevice, - IDirect3D9 **ppD3D, - D3DPRESENT_PARAMETERS &d3dpp - ); + HWND hWnd, + IDirect3DDevice9** ppDevice, + IDirect3D9 **ppD3D, + D3DPRESENT_PARAMETERS &d3dpp +); static HRESULT TestCooperativeLevel( - struct plugin_video_dshow_consumer_s *pSelf - ); + struct plugin_video_dshow_consumer_s *pSelf +); static HRESULT CreateSwapChain( - HWND hWnd, - UINT32 nFrameWidth, - UINT32 nFrameHeight, - IDirect3DDevice9* pDevice, - IDirect3DSwapChain9 **ppSwapChain); + HWND hWnd, + UINT32 nFrameWidth, + UINT32 nFrameHeight, + IDirect3DDevice9* pDevice, + IDirect3DSwapChain9 **ppSwapChain); static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -98,30 +97,29 @@ static HRESULT HookWindow(struct plugin_video_dshow_consumer_s *pSelf, HWND hWnd static HRESULT UnhookWindow(struct plugin_video_dshow_consumer_s *pSelf); -typedef struct plugin_video_dshow_consumer_s -{ - TMEDIA_DECLARE_CONSUMER; - - BOOL bStarted, bPrepared, bPaused, bFullScreen, bWindowHooked; - BOOL bPluginFireFox, bPluginWebRTC4All; - HWND hWindow; - WNDPROC wndProc; - HWND hWindowFullScreen; - RECT rcWindow; - RECT rcDest; - DSRatio pixelAR; - - UINT32 nNegWidth; - UINT32 nNegHeight; - UINT32 nNegFps; - - D3DLOCKED_RECT rcLock; - IDirect3DDevice9* pDevice; - IDirect3D9 *pD3D; - IDirect3DSwapChain9 *pSwapChain; - D3DPRESENT_PARAMETERS d3dpp; - - TSK_DECLARE_SAFEOBJ; +typedef struct plugin_video_dshow_consumer_s { + TMEDIA_DECLARE_CONSUMER; + + BOOL bStarted, bPrepared, bPaused, bFullScreen, bWindowHooked; + BOOL bPluginFireFox, bPluginWebRTC4All; + HWND hWindow; + WNDPROC wndProc; + HWND hWindowFullScreen; + RECT rcWindow; + RECT rcDest; + DSRatio pixelAR; + + UINT32 nNegWidth; + UINT32 nNegHeight; + UINT32 nNegFps; + + D3DLOCKED_RECT rcLock; + IDirect3DDevice9* pDevice; + IDirect3D9 *pD3D; + IDirect3DSwapChain9 *pSwapChain; + D3DPRESENT_PARAMETERS d3dpp; + + TSK_DECLARE_SAFEOBJ; } plugin_video_dshow_consumer_t; @@ -130,377 +128,345 @@ static int _plugin_video_dshow_consumer_unprepare(plugin_video_dshow_consumer_t* /* ============ Media Consumer Interface ================= */ static int plugin_video_dshow_consumer_set(tmedia_consumer_t *self, const tmedia_param_t* param) { - int ret = 0; - HRESULT hr = S_OK; - plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; - - 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 = reinterpret_cast<HWND>((INT64)*((int64_t*)param->value)); - if(hWnd != pSelf->hWindow) - { - tsk_safeobj_lock(pSelf); // block consumer thread - pSelf->hWindow = hWnd; - if(pSelf->bPrepared) - { - hr = ResetDevice(pSelf); - } - tsk_safeobj_unlock(pSelf); // unblock consumer thread - } - } - } - else if(param->value_type == tmedia_pvt_int32) - { - if(tsk_striequals(param->key, "fullscreen")) - { - BOOL bFullScreen = !!*((int32_t*)param->value); - TSK_DEBUG_INFO("[MF video consumer] Full Screen = %d", bFullScreen); - CHECK_HR(hr = SetFullscreen(pSelf, bFullScreen)); - } - else if(tsk_striequals(param->key, "create-on-current-thead")) - { - // DSCONSUMER(self)->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true; - } - else if(tsk_striequals(param->key, "plugin-firefox")) - { - pSelf->bPluginFireFox = (*((int32_t*)param->value) != 0); - } - else if(tsk_striequals(param->key, "plugin-webrtc4all")) - { - pSelf->bPluginWebRTC4All = (*((int32_t*)param->value) != 0); - } - } - - CHECK_HR(hr); + int ret = 0; + HRESULT hr = S_OK; + plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; + + 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 = reinterpret_cast<HWND>((INT64)*((int64_t*)param->value)); + if(hWnd != pSelf->hWindow) { + tsk_safeobj_lock(pSelf); // block consumer thread + pSelf->hWindow = hWnd; + if(pSelf->bPrepared) { + hr = ResetDevice(pSelf); + } + tsk_safeobj_unlock(pSelf); // unblock consumer thread + } + } + } + else if(param->value_type == tmedia_pvt_int32) { + if(tsk_striequals(param->key, "fullscreen")) { + BOOL bFullScreen = !!*((int32_t*)param->value); + TSK_DEBUG_INFO("[MF video consumer] Full Screen = %d", bFullScreen); + CHECK_HR(hr = SetFullscreen(pSelf, bFullScreen)); + } + else if(tsk_striequals(param->key, "create-on-current-thead")) { + // DSCONSUMER(self)->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true; + } + else if(tsk_striequals(param->key, "plugin-firefox")) { + pSelf->bPluginFireFox = (*((int32_t*)param->value) != 0); + } + else if(tsk_striequals(param->key, "plugin-webrtc4all")) { + pSelf->bPluginWebRTC4All = (*((int32_t*)param->value) != 0); + } + } + + CHECK_HR(hr); bail: - return SUCCEEDED(hr) ? 0 : -1; + return SUCCEEDED(hr) ? 0 : -1; } static int plugin_video_dshow_consumer_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { - plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; - - if(!pSelf || !codec && codec->plugin){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(pSelf->bPrepared){ - TSK_DEBUG_WARN("D3D9 video consumer already prepared"); - return -1; - } - - HRESULT hr = S_OK; - HWND hWnd = Window(pSelf); - - TMEDIA_CONSUMER(pSelf)->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps; - TMEDIA_CONSUMER(pSelf)->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width; - TMEDIA_CONSUMER(pSelf)->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height; - - if(!TMEDIA_CONSUMER(pSelf)->video.display.width){ - TMEDIA_CONSUMER(pSelf)->video.display.width = TMEDIA_CONSUMER(pSelf)->video.in.width; - } - if(!TMEDIA_CONSUMER(pSelf)->video.display.height){ - TMEDIA_CONSUMER(pSelf)->video.display.height = TMEDIA_CONSUMER(pSelf)->video.in.height; - } - - pSelf->nNegFps = (UINT32)TMEDIA_CONSUMER(pSelf)->video.fps; - pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.display.width; - pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.display.height; - - TSK_DEBUG_INFO("D3D9 video consumer: fps=%d, width=%d, height=%d", - pSelf->nNegFps, - pSelf->nNegWidth, - pSelf->nNegHeight); - - TMEDIA_CONSUMER(pSelf)->video.display.chroma = tmedia_chroma_rgb32; - TMEDIA_CONSUMER(pSelf)->decoder.codec_id = tmedia_codec_id_none; // means accept RAW fames - - // The window handle is not created until the call is connect (incoming only) - At least on Internet Explorer 10 - if(hWnd && !pSelf->bPluginWebRTC4All) - { - CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp)); - CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain)); - } - else - { - if(hWnd && pSelf->bPluginWebRTC4All) - { - TSK_DEBUG_INFO("[MF consumer] HWND is defined but we detected webrtc4all...delaying D3D9 device creating until session get connected"); - } - else - { - TSK_DEBUG_WARN("Delaying D3D9 device creation because HWND is not defined yet"); - } - } + plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; + + if(!pSelf || !codec && codec->plugin) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(pSelf->bPrepared) { + TSK_DEBUG_WARN("D3D9 video consumer already prepared"); + return -1; + } + + HRESULT hr = S_OK; + HWND hWnd = Window(pSelf); + + TMEDIA_CONSUMER(pSelf)->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps; + TMEDIA_CONSUMER(pSelf)->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width; + TMEDIA_CONSUMER(pSelf)->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height; + + if(!TMEDIA_CONSUMER(pSelf)->video.display.width) { + TMEDIA_CONSUMER(pSelf)->video.display.width = TMEDIA_CONSUMER(pSelf)->video.in.width; + } + if(!TMEDIA_CONSUMER(pSelf)->video.display.height) { + TMEDIA_CONSUMER(pSelf)->video.display.height = TMEDIA_CONSUMER(pSelf)->video.in.height; + } + + pSelf->nNegFps = (UINT32)TMEDIA_CONSUMER(pSelf)->video.fps; + pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.display.width; + pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.display.height; + + TSK_DEBUG_INFO("D3D9 video consumer: fps=%d, width=%d, height=%d", + pSelf->nNegFps, + pSelf->nNegWidth, + pSelf->nNegHeight); + + TMEDIA_CONSUMER(pSelf)->video.display.chroma = tmedia_chroma_rgb32; + TMEDIA_CONSUMER(pSelf)->decoder.codec_id = tmedia_codec_id_none; // means accept RAW fames + + // The window handle is not created until the call is connect (incoming only) - At least on Internet Explorer 10 + if(hWnd && !pSelf->bPluginWebRTC4All) { + CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp)); + CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain)); + } + else { + if(hWnd && pSelf->bPluginWebRTC4All) { + TSK_DEBUG_INFO("[MF consumer] HWND is defined but we detected webrtc4all...delaying D3D9 device creating until session get connected"); + } + else { + TSK_DEBUG_WARN("Delaying D3D9 device creation because HWND is not defined yet"); + } + } bail: - pSelf->bPrepared = SUCCEEDED(hr); - return pSelf->bPrepared ? 0 : -1; + pSelf->bPrepared = SUCCEEDED(hr); + return pSelf->bPrepared ? 0 : -1; } static int plugin_video_dshow_consumer_start(tmedia_consumer_t* self) { - plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; + plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; - if(!pSelf){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!pSelf) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - if(pSelf->bStarted){ - TSK_DEBUG_INFO("D3D9 video consumer already started"); - return 0; - } - if(!pSelf->bPrepared){ - TSK_DEBUG_ERROR("D3D9 video consumer not prepared"); - return -1; - } + if(pSelf->bStarted) { + TSK_DEBUG_INFO("D3D9 video consumer already started"); + return 0; + } + if(!pSelf->bPrepared) { + TSK_DEBUG_ERROR("D3D9 video consumer not prepared"); + return -1; + } - HRESULT hr = S_OK; + HRESULT hr = S_OK; - pSelf->bPaused = false; - pSelf->bStarted = true; + pSelf->bPaused = false; + pSelf->bStarted = true; - return SUCCEEDED(hr) ? 0 : -1; + return SUCCEEDED(hr) ? 0 : -1; } static int plugin_video_dshow_consumer_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr) { - plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; + plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; - HRESULT hr = S_OK; - HWND hWnd = Window(pSelf); + HRESULT hr = S_OK; + HWND hWnd = Window(pSelf); - IDirect3DSurface9 *pSurf = NULL; + IDirect3DSurface9 *pSurf = NULL; IDirect3DSurface9 *pBB = NULL; - if(!pSelf) - { - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; // because of the mutex lock do it here - } - - tsk_safeobj_lock(pSelf); - - if(!buffer || !size) - { - TSK_DEBUG_ERROR("Invalid parameter"); - CHECK_HR(hr = E_INVALIDARG); - } - - if(!pSelf->bStarted) - { - TSK_DEBUG_INFO("D3D9 video consumer not started"); - CHECK_HR(hr = E_FAIL); - } - - if(!hWnd) - { - TSK_DEBUG_INFO("Do not draw frame because HWND not set"); - goto bail; // not an error as the application can decide to set the HWND at any time - } - - if (!pSelf->bWindowHooked) - { - // Do not hook "hWnd" as it could be the fullscreen handle which is always hooked. - CHECK_HR(hr = HookWindow(pSelf, pSelf->hWindow)); - } - - if(!pSelf->pDevice || !pSelf->pD3D || !pSelf->pSwapChain) - { - if(pSelf->pDevice || pSelf->pD3D || pSelf->pSwapChain) - { - CHECK_HR(hr = E_POINTER); // They must be "all null" or "all valid" - } - - if(hWnd) - { - // means HWND was not set but defined now - pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width; - pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height; - - CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp)); - CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain)); - } - } - - if(pSelf->nNegWidth != TMEDIA_CONSUMER(pSelf)->video.in.width || pSelf->nNegHeight != TMEDIA_CONSUMER(pSelf)->video.in.height){ - TSK_DEBUG_INFO("Negotiated and input video sizes are different:%d#%d or %d#%d", - pSelf->nNegWidth, TMEDIA_CONSUMER(pSelf)->video.in.width, - pSelf->nNegHeight, TMEDIA_CONSUMER(pSelf)->video.in.height); - // Update media type - - SafeRelease(&pSelf->pSwapChain); - CHECK_HR(hr = CreateSwapChain(hWnd, (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width, (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height, pSelf->pDevice, &pSelf->pSwapChain)); - - pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width; - pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height; - - // Update Destination will do noting if the window size haven't changed. - // Force updating the destination rect if negotiated size change - CHECK_HR(hr = UpdateDestinationRect(pSelf, TRUE/* Force */)); - } - - if(((pSelf->nNegWidth * pSelf->nNegHeight) << 2) != size) - { - TSK_DEBUG_ERROR("%u not valid as input size", size); - CHECK_HR(hr = E_FAIL); - } - - CHECK_HR(hr = TestCooperativeLevel(pSelf)); - - CHECK_HR(hr = UpdateDestinationRect(pSelf)); - - CHECK_HR(hr = pSelf->pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurf)); - CHECK_HR(hr = pSurf->LockRect(&pSelf->rcLock, NULL, D3DLOCK_NOSYSLOCK )); - - // Fast copy() using MMX, SSE, or SSE2 - // Only available on Vista or later: Use LoadLibrary() to get a pointer to the function - /*hr = MFCopyImage( - (BYTE*)pSelf->rcLock.pBits, - pSelf->rcLock.Pitch, - (BYTE*)buffer, - (pSelf->nNegWidth << 2), - (pSelf->nNegWidth << 2), - pSelf->nNegHeight - );*/ - - if(pSelf->rcLock.Pitch == (pSelf->nNegWidth << 2)) - { - memcpy(pSelf->rcLock.pBits, buffer, size); - } - else - { - const BYTE* pSrcPtr = (const BYTE*)buffer; - BYTE* pDstPtr = (BYTE*)pSelf->rcLock.pBits; - UINT32 nDstPitch = pSelf->rcLock.Pitch; - UINT32 nSrcPitch = (pSelf->nNegWidth << 2); - for(UINT32 i = 0; i < pSelf->nNegHeight; ++i) - { - memcpy(pDstPtr, pSrcPtr, nSrcPitch); - pDstPtr += nDstPitch; - pSrcPtr += nSrcPitch; - } - } - - if(FAILED(hr)) - { - // unlock() before leaving - pSurf->UnlockRect(); - CHECK_HR(hr); - } - - CHECK_HR(hr = pSurf->UnlockRect()); - - // Color fill the back buffer - CHECK_HR(hr = pSelf->pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBB)); - CHECK_HR(hr = pSelf->pDevice->ColorFill(pBB, NULL, D3DCOLOR_XRGB(0xFF, 0xFF, 0xFF))); - - // Resize keeping aspect ratio and Blit the frame (required) - hr = pSelf->pDevice->StretchRect( - pSurf, - NULL, - pBB, - &pSelf->rcDest/*NULL*/, - D3DTEXF_LINEAR - ); // could fail when display is being resized - if(SUCCEEDED(hr)) - { - // Present the frame - CHECK_HR(hr = pSelf->pDevice->Present(NULL, NULL, NULL, NULL)); - } - else - { - TSK_DEBUG_INFO("StretchRect returned ...%x", hr); - } + if(!pSelf) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; // because of the mutex lock do it here + } + + tsk_safeobj_lock(pSelf); + + if(!buffer || !size) { + TSK_DEBUG_ERROR("Invalid parameter"); + CHECK_HR(hr = E_INVALIDARG); + } + + if(!pSelf->bStarted) { + TSK_DEBUG_INFO("D3D9 video consumer not started"); + CHECK_HR(hr = E_FAIL); + } + + if(!hWnd) { + TSK_DEBUG_INFO("Do not draw frame because HWND not set"); + goto bail; // not an error as the application can decide to set the HWND at any time + } + + if (!pSelf->bWindowHooked) { + // Do not hook "hWnd" as it could be the fullscreen handle which is always hooked. + CHECK_HR(hr = HookWindow(pSelf, pSelf->hWindow)); + } + + if(!pSelf->pDevice || !pSelf->pD3D || !pSelf->pSwapChain) { + if(pSelf->pDevice || pSelf->pD3D || pSelf->pSwapChain) { + CHECK_HR(hr = E_POINTER); // They must be "all null" or "all valid" + } + + if(hWnd) { + // means HWND was not set but defined now + pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width; + pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height; + + CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp)); + CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain)); + } + } + + if(pSelf->nNegWidth != TMEDIA_CONSUMER(pSelf)->video.in.width || pSelf->nNegHeight != TMEDIA_CONSUMER(pSelf)->video.in.height) { + TSK_DEBUG_INFO("Negotiated and input video sizes are different:%d#%d or %d#%d", + pSelf->nNegWidth, TMEDIA_CONSUMER(pSelf)->video.in.width, + pSelf->nNegHeight, TMEDIA_CONSUMER(pSelf)->video.in.height); + // Update media type + + SafeRelease(&pSelf->pSwapChain); + CHECK_HR(hr = CreateSwapChain(hWnd, (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width, (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height, pSelf->pDevice, &pSelf->pSwapChain)); + + pSelf->nNegWidth = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.width; + pSelf->nNegHeight = (UINT32)TMEDIA_CONSUMER(pSelf)->video.in.height; + + // Update Destination will do noting if the window size haven't changed. + // Force updating the destination rect if negotiated size change + CHECK_HR(hr = UpdateDestinationRect(pSelf, TRUE/* Force */)); + } + + if(((pSelf->nNegWidth * pSelf->nNegHeight) << 2) != size) { + TSK_DEBUG_ERROR("%u not valid as input size", size); + CHECK_HR(hr = E_FAIL); + } + + CHECK_HR(hr = TestCooperativeLevel(pSelf)); + + CHECK_HR(hr = UpdateDestinationRect(pSelf)); + + CHECK_HR(hr = pSelf->pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurf)); + CHECK_HR(hr = pSurf->LockRect(&pSelf->rcLock, NULL, D3DLOCK_NOSYSLOCK )); + + // Fast copy() using MMX, SSE, or SSE2 + // Only available on Vista or later: Use LoadLibrary() to get a pointer to the function + /*hr = MFCopyImage( + (BYTE*)pSelf->rcLock.pBits, + pSelf->rcLock.Pitch, + (BYTE*)buffer, + (pSelf->nNegWidth << 2), + (pSelf->nNegWidth << 2), + pSelf->nNegHeight + );*/ + + if(pSelf->rcLock.Pitch == (pSelf->nNegWidth << 2)) { + memcpy(pSelf->rcLock.pBits, buffer, size); + } + else { + const BYTE* pSrcPtr = (const BYTE*)buffer; + BYTE* pDstPtr = (BYTE*)pSelf->rcLock.pBits; + UINT32 nDstPitch = pSelf->rcLock.Pitch; + UINT32 nSrcPitch = (pSelf->nNegWidth << 2); + for(UINT32 i = 0; i < pSelf->nNegHeight; ++i) { + memcpy(pDstPtr, pSrcPtr, nSrcPitch); + pDstPtr += nDstPitch; + pSrcPtr += nSrcPitch; + } + } + + if(FAILED(hr)) { + // unlock() before leaving + pSurf->UnlockRect(); + CHECK_HR(hr); + } + + CHECK_HR(hr = pSurf->UnlockRect()); + + // Color fill the back buffer + CHECK_HR(hr = pSelf->pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBB)); + CHECK_HR(hr = pSelf->pDevice->ColorFill(pBB, NULL, D3DCOLOR_XRGB(0xFF, 0xFF, 0xFF))); + + // Resize keeping aspect ratio and Blit the frame (required) + hr = pSelf->pDevice->StretchRect( + pSurf, + NULL, + pBB, + &pSelf->rcDest/*NULL*/, + D3DTEXF_LINEAR + ); // could fail when display is being resized + if(SUCCEEDED(hr)) { + // Present the frame + CHECK_HR(hr = pSelf->pDevice->Present(NULL, NULL, NULL, NULL)); + } + else { + TSK_DEBUG_INFO("StretchRect returned ...%x", hr); + } bail: - SafeRelease(&pSurf); - SafeRelease(&pBB); + SafeRelease(&pSurf); + SafeRelease(&pBB); - tsk_safeobj_unlock(pSelf); + tsk_safeobj_unlock(pSelf); - return SUCCEEDED(hr) ? 0 : -1; + return SUCCEEDED(hr) ? 0 : -1; } static int plugin_video_dshow_consumer_pause(tmedia_consumer_t* self) { - plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; + plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; - if(!pSelf){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!pSelf->bStarted) - { - TSK_DEBUG_INFO("MF video producer not started"); - return 0; - } + if(!pSelf) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!pSelf->bStarted) { + TSK_DEBUG_INFO("MF video producer not started"); + return 0; + } - HRESULT hr = S_OK; + HRESULT hr = S_OK; - pSelf->bPaused = true; + pSelf->bPaused = true; - return SUCCEEDED(hr) ? 0 : -1; + return SUCCEEDED(hr) ? 0 : -1; } static int plugin_video_dshow_consumer_stop(tmedia_consumer_t* self) { - plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; + plugin_video_dshow_consumer_t* pSelf = (plugin_video_dshow_consumer_t*)self; - if(!pSelf){ + if(!pSelf) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - HRESULT hr = S_OK; - + HRESULT hr = S_OK; + pSelf->bStarted = false; - pSelf->bPaused = false; + pSelf->bPaused = false; - if(pSelf->hWindowFullScreen) - { - ::InvalidateRect(pSelf->hWindowFullScreen, NULL, FALSE); - ::ShowWindow(pSelf->hWindowFullScreen, SW_HIDE); - } + if(pSelf->hWindowFullScreen) { + ::InvalidateRect(pSelf->hWindowFullScreen, NULL, FALSE); + ::ShowWindow(pSelf->hWindowFullScreen, SW_HIDE); + } - // next start() will be called after prepare() - return _plugin_video_dshow_consumer_unprepare(pSelf); + // next start() will be called after prepare() + return _plugin_video_dshow_consumer_unprepare(pSelf); } static int _plugin_video_dshow_consumer_unprepare(plugin_video_dshow_consumer_t* pSelf) { - if(!pSelf){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!pSelf) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - if(pSelf->bStarted) - { - // plugin_win_mf_producer_video_stop(TMEDIA_PRODUCER(pSelf)); - TSK_DEBUG_ERROR("Consumer must be stopped before calling unprepare"); - return -1; - } + if(pSelf->bStarted) { + // plugin_win_mf_producer_video_stop(TMEDIA_PRODUCER(pSelf)); + TSK_DEBUG_ERROR("Consumer must be stopped before calling unprepare"); + return -1; + } - UnhookWindow(pSelf); + UnhookWindow(pSelf); - SafeRelease(&pSelf->pDevice); - SafeRelease(&pSelf->pD3D); - SafeRelease(&pSelf->pSwapChain); + SafeRelease(&pSelf->pDevice); + SafeRelease(&pSelf->pD3D); + SafeRelease(&pSelf->pSwapChain); - pSelf->bPrepared = false; + pSelf->bPrepared = false; - return 0; + return 0; } @@ -510,191 +476,177 @@ static int _plugin_video_dshow_consumer_unprepare(plugin_video_dshow_consumer_t* /* constructor */ static tsk_object_t* plugin_video_dshow_consumer_ctor(tsk_object_t * self, va_list * app) { - plugin_video_dshow_consumer_t *pSelf = (plugin_video_dshow_consumer_t *)self; - if(pSelf) - { - /* init base */ - tmedia_consumer_init(TMEDIA_CONSUMER(pSelf)); - TMEDIA_CONSUMER(pSelf)->video.display.chroma = tmedia_chroma_rgb32; - TMEDIA_CONSUMER(pSelf)->decoder.codec_id = tmedia_codec_id_none; // means accept RAW fames - - /* init self */ - tsk_safeobj_init(pSelf); - TMEDIA_CONSUMER(pSelf)->video.fps = 15; - 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; - - pSelf->pixelAR.Denominator = pSelf->pixelAR.Numerator = 1; - } - return self; + plugin_video_dshow_consumer_t *pSelf = (plugin_video_dshow_consumer_t *)self; + if(pSelf) { + /* init base */ + tmedia_consumer_init(TMEDIA_CONSUMER(pSelf)); + TMEDIA_CONSUMER(pSelf)->video.display.chroma = tmedia_chroma_rgb32; + TMEDIA_CONSUMER(pSelf)->decoder.codec_id = tmedia_codec_id_none; // means accept RAW fames + + /* init self */ + tsk_safeobj_init(pSelf); + TMEDIA_CONSUMER(pSelf)->video.fps = 15; + 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; + + pSelf->pixelAR.Denominator = pSelf->pixelAR.Numerator = 1; + } + return self; } /* destructor */ static tsk_object_t* plugin_video_dshow_consumer_dtor(tsk_object_t * self) -{ - plugin_video_dshow_consumer_t *pSelf = (plugin_video_dshow_consumer_t *)self; - if (pSelf) { - /* stop */ - if (pSelf->bStarted) - { - plugin_video_dshow_consumer_stop(TMEDIA_CONSUMER(pSelf)); - } - - /* deinit base */ - tmedia_consumer_deinit(TMEDIA_CONSUMER(pSelf)); - /* deinit self */ - _plugin_video_dshow_consumer_unprepare(pSelf); - tsk_safeobj_deinit(pSelf); - } - - return self; +{ + plugin_video_dshow_consumer_t *pSelf = (plugin_video_dshow_consumer_t *)self; + if (pSelf) { + /* stop */ + if (pSelf->bStarted) { + plugin_video_dshow_consumer_stop(TMEDIA_CONSUMER(pSelf)); + } + + /* deinit base */ + tmedia_consumer_deinit(TMEDIA_CONSUMER(pSelf)); + /* deinit self */ + _plugin_video_dshow_consumer_unprepare(pSelf); + tsk_safeobj_deinit(pSelf); + } + + return self; } /* object definition */ -static const tsk_object_def_t plugin_video_dshow_consumer_def_s = -{ - sizeof(plugin_video_dshow_consumer_t), - plugin_video_dshow_consumer_ctor, - plugin_video_dshow_consumer_dtor, - tsk_null, +static const tsk_object_def_t plugin_video_dshow_consumer_def_s = { + sizeof(plugin_video_dshow_consumer_t), + plugin_video_dshow_consumer_ctor, + plugin_video_dshow_consumer_dtor, + tsk_null, }; /* plugin definition*/ -static const tmedia_consumer_plugin_def_t plugin_video_dshow_consumer_plugin_def_s = -{ - &plugin_video_dshow_consumer_def_s, - - tmedia_video, - "Microsoft DirectShow consumer (D3D9)", - - plugin_video_dshow_consumer_set, - plugin_video_dshow_consumer_prepare, - plugin_video_dshow_consumer_start, - plugin_video_dshow_consumer_consume, - plugin_video_dshow_consumer_pause, - plugin_video_dshow_consumer_stop +static const tmedia_consumer_plugin_def_t plugin_video_dshow_consumer_plugin_def_s = { + &plugin_video_dshow_consumer_def_s, + + tmedia_video, + "Microsoft DirectShow consumer (D3D9)", + + plugin_video_dshow_consumer_set, + plugin_video_dshow_consumer_prepare, + plugin_video_dshow_consumer_start, + plugin_video_dshow_consumer_consume, + plugin_video_dshow_consumer_pause, + plugin_video_dshow_consumer_stop }; const tmedia_consumer_plugin_def_t *plugin_video_dshow_consumer_plugin_def_t = &plugin_video_dshow_consumer_plugin_def_s; // Helper functions static HRESULT CreateDeviceD3D9( - HWND hWnd, - IDirect3DDevice9** ppDevice, - IDirect3D9 **ppD3D, - D3DPRESENT_PARAMETERS &d3dpp - ) + HWND hWnd, + IDirect3DDevice9** ppDevice, + IDirect3D9 **ppD3D, + D3DPRESENT_PARAMETERS &d3dpp +) { - HRESULT hr = S_OK; + HRESULT hr = S_OK; D3DDISPLAYMODE mode = { 0 }; - D3DPRESENT_PARAMETERS pp = {0}; - - if(!ppDevice || *ppDevice || !ppD3D || *ppD3D) - { - CHECK_HR(hr = E_POINTER); - } - - if(!(*ppD3D = Direct3DCreate9(D3D_SDK_VERSION))) - { + D3DPRESENT_PARAMETERS pp = {0}; + + if(!ppDevice || *ppDevice || !ppD3D || *ppD3D) { + CHECK_HR(hr = E_POINTER); + } + + if(!(*ppD3D = Direct3DCreate9(D3D_SDK_VERSION))) { CHECK_HR(hr = E_OUTOFMEMORY); } CHECK_HR(hr = (*ppD3D)->GetAdapterDisplayMode( - D3DADAPTER_DEFAULT, - &mode - )); + D3DADAPTER_DEFAULT, + &mode + )); CHECK_HR(hr = (*ppD3D)->CheckDeviceType( - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, - mode.Format, - D3DFMT_X8R8G8B8, - TRUE // windowed - )); + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + mode.Format, + D3DFMT_X8R8G8B8, + TRUE // windowed + )); pp.BackBufferFormat = D3DFMT_X8R8G8B8; pp.SwapEffect = D3DSWAPEFFECT_DISCARD; pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - pp.Windowed = TRUE; + pp.Windowed = TRUE; pp.hDeviceWindow = hWnd; CHECK_HR(hr = (*ppD3D)->CreateDevice( - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, - hWnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING, - &pp, - ppDevice - )); + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hWnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING, + &pp, + ppDevice + )); - d3dpp = pp; + d3dpp = pp; bail: - if(FAILED(hr)) - { - SafeRelease(ppD3D); - SafeRelease(ppDevice); - } + if(FAILED(hr)) { + SafeRelease(ppD3D); + SafeRelease(ppDevice); + } return hr; } static HRESULT TestCooperativeLevel( - struct plugin_video_dshow_consumer_s *pSelf - ) + struct plugin_video_dshow_consumer_s *pSelf +) { - HRESULT hr = S_OK; - - if (!pSelf || !pSelf->pDevice) - { - CHECK_HR(hr = E_POINTER); - } - - switch((hr = pSelf->pDevice->TestCooperativeLevel())) - { - case D3D_OK: - { - break; - } - - case D3DERR_DEVICELOST: - { - hr = S_OK; - break; - } - - case D3DERR_DEVICENOTRESET: - { - hr = ResetDevice(pSelf, TRUE); - break; - } - - default: - { - break; - } - } - - CHECK_HR(hr); + HRESULT hr = S_OK; + + if (!pSelf || !pSelf->pDevice) { + CHECK_HR(hr = E_POINTER); + } + + switch((hr = pSelf->pDevice->TestCooperativeLevel())) { + case D3D_OK: { + break; + } + + case D3DERR_DEVICELOST: { + hr = S_OK; + break; + } + + case D3DERR_DEVICENOTRESET: { + hr = ResetDevice(pSelf, TRUE); + break; + } + + default: { + break; + } + } + + CHECK_HR(hr); bail: return hr; } static HRESULT CreateSwapChain( - HWND hWnd, - UINT32 nFrameWidth, - UINT32 nFrameHeight, - IDirect3DDevice9* pDevice, - IDirect3DSwapChain9 **ppSwapChain - ) + HWND hWnd, + UINT32 nFrameWidth, + UINT32 nFrameHeight, + IDirect3DDevice9* pDevice, + IDirect3DSwapChain9 **ppSwapChain +) { HRESULT hr = S_OK; D3DPRESENT_PARAMETERS pp = { 0 }; - if(!pDevice || !ppSwapChain || *ppSwapChain) - { - CHECK_HR(hr = E_POINTER); - } - - pp.BackBufferWidth = nFrameWidth; + if(!pDevice || !ppSwapChain || *ppSwapChain) { + CHECK_HR(hr = E_POINTER); + } + + pp.BackBufferWidth = nFrameWidth; pp.BackBufferHeight = nFrameHeight; pp.Windowed = TRUE; pp.SwapEffect = D3DSWAPEFFECT_FLIP; @@ -706,7 +658,7 @@ static HRESULT CreateSwapChain( pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; pp.BackBufferCount = NUM_BACK_BUFFERS; - CHECK_HR(hr = pDevice->CreateAdditionalSwapChain(&pp, ppSwapChain)); + CHECK_HR(hr = pDevice->CreateAdditionalSwapChain(&pp, ppSwapChain)); bail: return hr; @@ -714,7 +666,7 @@ bail: static inline HWND Window(struct plugin_video_dshow_consumer_s *pSelf) { - return pSelf ? (pSelf->bFullScreen ? pSelf->hWindowFullScreen : pSelf->hWindow) : NULL; + return pSelf ? (pSelf->bFullScreen ? pSelf->hWindowFullScreen : pSelf->hWindow) : NULL; } static inline LONG Width(const RECT& r) @@ -743,17 +695,14 @@ static inline RECT CorrectAspectRatio(const RECT& src, const DSRatio& srcPAR) // Start with a rectangle the same size as src, but offset to the origin (0,0). RECT rc = {0, 0, src.right - src.left, src.bottom - src.top}; - if ((srcPAR.Numerator != 1) || (srcPAR.Denominator != 1)) - { + if ((srcPAR.Numerator != 1) || (srcPAR.Denominator != 1)) { // Correct for the source's PAR. - if (srcPAR.Numerator > srcPAR.Denominator) - { + if (srcPAR.Numerator > srcPAR.Denominator) { // The source has "wide" pixels, so stretch the width. rc.right = MulDiv(rc.right, srcPAR.Numerator, srcPAR.Denominator); } - else if (srcPAR.Numerator < srcPAR.Denominator) - { + else if (srcPAR.Numerator < srcPAR.Denominator) { // The source has "tall" pixels, so stretch the height. rc.bottom = MulDiv(rc.bottom, srcPAR.Denominator, srcPAR.Numerator); } @@ -816,266 +765,242 @@ static inline RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst) static inline HRESULT UpdateDestinationRect(plugin_video_dshow_consumer_t *pSelf, BOOL bForce /*= FALSE*/) { - HRESULT hr = S_OK; - HWND hwnd = Window(pSelf); - - if(!pSelf) - { - CHECK_HR(hr = E_POINTER); - } - - if(!hwnd) - { - CHECK_HR(hr = E_HANDLE); - } + HRESULT hr = S_OK; + HWND hwnd = Window(pSelf); + + if(!pSelf) { + CHECK_HR(hr = E_POINTER); + } + + if(!hwnd) { + CHECK_HR(hr = E_HANDLE); + } RECT rcClient; - GetClientRect(hwnd, &rcClient); + GetClientRect(hwnd, &rcClient); - // only update destination if window size changed - if(bForce || (rcClient.bottom != pSelf->rcWindow.bottom || rcClient.left != pSelf->rcWindow.left || rcClient.right != pSelf->rcWindow.right || rcClient.top != pSelf->rcWindow.top)) - { - CHECK_HR(hr = ResetDevice(pSelf)); + // only update destination if window size changed + if(bForce || (rcClient.bottom != pSelf->rcWindow.bottom || rcClient.left != pSelf->rcWindow.left || rcClient.right != pSelf->rcWindow.right || rcClient.top != pSelf->rcWindow.top)) { + CHECK_HR(hr = ResetDevice(pSelf)); - pSelf->rcWindow = rcClient; + pSelf->rcWindow = rcClient; #if 1 - RECT rcSrc = { 0, 0, pSelf->nNegWidth, pSelf->nNegHeight }; - rcSrc = CorrectAspectRatio(rcSrc, pSelf->pixelAR); - pSelf->rcDest = LetterBoxRect(rcSrc, rcClient); + RECT rcSrc = { 0, 0, pSelf->nNegWidth, pSelf->nNegHeight }; + rcSrc = CorrectAspectRatio(rcSrc, pSelf->pixelAR); + pSelf->rcDest = LetterBoxRect(rcSrc, rcClient); #else - long w = rcClient.right - rcClient.left; - long h = rcClient.bottom - rcClient.top; - float ratio = ((float)pSelf->nNegWidth/(float)pSelf->nNegHeight); - // (w/h)=ratio => - // 1) h=w/ratio - // and - // 2) w=h*ratio - pSelf->rcDest.right = (int)(w/ratio) > h ? (int)(h * ratio) : w; - pSelf->rcDest.bottom = (int)(pSelf->rcDest.right/ratio) > h ? h : (int)(pSelf->rcDest.right/ratio); - pSelf->rcDest.left = ((w - pSelf->rcDest.right) >> 1); - pSelf->rcDest.top = ((h - pSelf->rcDest.bottom) >> 1); + long w = rcClient.right - rcClient.left; + long h = rcClient.bottom - rcClient.top; + float ratio = ((float)pSelf->nNegWidth/(float)pSelf->nNegHeight); + // (w/h)=ratio => + // 1) h=w/ratio + // and + // 2) w=h*ratio + pSelf->rcDest.right = (int)(w/ratio) > h ? (int)(h * ratio) : w; + pSelf->rcDest.bottom = (int)(pSelf->rcDest.right/ratio) > h ? h : (int)(pSelf->rcDest.right/ratio); + pSelf->rcDest.left = ((w - pSelf->rcDest.right) >> 1); + pSelf->rcDest.top = ((h - pSelf->rcDest.bottom) >> 1); #endif - //::InvalidateRect(hwnd, NULL, FALSE); - } + //::InvalidateRect(hwnd, NULL, FALSE); + } bail: - return hr; + return hr; } static HRESULT ResetDevice(plugin_video_dshow_consumer_t *pSelf, BOOL bUpdateDestinationRect /*= FALSE*/) { HRESULT hr = S_OK; - tsk_safeobj_lock(pSelf); + tsk_safeobj_lock(pSelf); - HWND hWnd = Window(pSelf); + HWND hWnd = Window(pSelf); - if (pSelf->pDevice) - { + if (pSelf->pDevice) { D3DPRESENT_PARAMETERS d3dpp = pSelf->d3dpp; hr = pSelf->pDevice->Reset(&d3dpp); - if (FAILED(hr)) - { + if (FAILED(hr)) { SafeRelease(&pSelf->pDevice); - SafeRelease(&pSelf->pD3D); - SafeRelease(&pSelf->pSwapChain); + SafeRelease(&pSelf->pD3D); + SafeRelease(&pSelf->pSwapChain); } } - if (pSelf->pDevice == NULL && hWnd) - { + if (pSelf->pDevice == NULL && hWnd) { CHECK_HR(hr = CreateDeviceD3D9(hWnd, &pSelf->pDevice, &pSelf->pD3D, pSelf->d3dpp)); - CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain)); - } + CHECK_HR(hr = CreateSwapChain(hWnd, pSelf->nNegWidth, pSelf->nNegHeight, pSelf->pDevice, &pSelf->pSwapChain)); + } - if(bUpdateDestinationRect) // endless loop guard - { - CHECK_HR(hr = UpdateDestinationRect(pSelf)); - } + if(bUpdateDestinationRect) { // endless loop guard + CHECK_HR(hr = UpdateDestinationRect(pSelf)); + } bail: - tsk_safeobj_unlock(pSelf); + tsk_safeobj_unlock(pSelf); - return hr; + return hr; } static HRESULT SetFullscreen(struct plugin_video_dshow_consumer_s *pSelf, BOOL bFullScreen) { - HRESULT hr = S_OK; - if(!pSelf) - { - CHECK_HR(hr = E_POINTER); - } - - if(pSelf->bFullScreen != bFullScreen) - { - tsk_safeobj_lock(pSelf); - if(bFullScreen) - { - HWND hWnd = CreateFullScreenWindow(pSelf); - if(hWnd) - { - ::ShowWindow(hWnd, SW_SHOWDEFAULT); - ::UpdateWindow(hWnd); - } - } - else if(pSelf->hWindowFullScreen) - { - ::ShowWindow(pSelf->hWindowFullScreen, SW_HIDE); - } - pSelf->bFullScreen = bFullScreen; - if(pSelf->bPrepared) - { - hr = ResetDevice(pSelf); - } - tsk_safeobj_unlock(pSelf); - - CHECK_HR(hr); - } + HRESULT hr = S_OK; + if(!pSelf) { + CHECK_HR(hr = E_POINTER); + } + + if(pSelf->bFullScreen != bFullScreen) { + tsk_safeobj_lock(pSelf); + if(bFullScreen) { + HWND hWnd = CreateFullScreenWindow(pSelf); + if(hWnd) { + ::ShowWindow(hWnd, SW_SHOWDEFAULT); + ::UpdateWindow(hWnd); + } + } + else if(pSelf->hWindowFullScreen) { + ::ShowWindow(pSelf->hWindowFullScreen, SW_HIDE); + } + pSelf->bFullScreen = bFullScreen; + if(pSelf->bPrepared) { + hr = ResetDevice(pSelf); + } + tsk_safeobj_unlock(pSelf); + + CHECK_HR(hr); + } bail: - return hr; + return hr; } static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) - { - case WM_CREATE: - case WM_SIZE: - case WM_MOVE: - { - struct plugin_video_dshow_consumer_s* pSelf = dynamic_cast<struct plugin_video_dshow_consumer_s*>((struct plugin_video_dshow_consumer_s*)GetPropA(hWnd, "Self")); - if (pSelf) - { - - } - break; - } + switch(uMsg) { + case WM_CREATE: + case WM_SIZE: + case WM_MOVE: { + struct plugin_video_dshow_consumer_s* pSelf = dynamic_cast<struct plugin_video_dshow_consumer_s*>((struct plugin_video_dshow_consumer_s*)GetPropA(hWnd, "Self")); + if (pSelf) { + + } + break; + } #if 0 - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hWnd, &ps); - ps.fErase = FALSE; - - RECT rc; - GetBoundsRect(hdc, &rc, 0); - FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); - - EndPaint(hWnd, &ps); - break; - } + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + ps.fErase = FALSE; + + RECT rc; + GetBoundsRect(hdc, &rc, 0); + FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); + + EndPaint(hWnd, &ps); + break; + } #endif - case WM_ERASEBKGND: - { - return TRUE; // avoid background erasing. - } - - - case WM_CHAR: - case WM_KEYUP: - { - struct plugin_video_dshow_consumer_s* pSelf = dynamic_cast<struct plugin_video_dshow_consumer_s*>((struct plugin_video_dshow_consumer_s*)GetPropA(hWnd, "Self")); - if (pSelf) - { - SetFullscreen(pSelf, FALSE); - } - - break; - } - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); + case WM_ERASEBKGND: { + return TRUE; // avoid background erasing. + } + + + case WM_CHAR: + case WM_KEYUP: { + struct plugin_video_dshow_consumer_s* pSelf = dynamic_cast<struct plugin_video_dshow_consumer_s*>((struct plugin_video_dshow_consumer_s*)GetPropA(hWnd, "Self")); + if (pSelf) { + SetFullscreen(pSelf, FALSE); + } + + break; + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); } static HWND CreateFullScreenWindow(struct plugin_video_dshow_consumer_s *pSelf) { - HRESULT hr = S_OK; - - if(!pSelf) - { - return NULL; - } - - if(!pSelf->hWindowFullScreen) - { - WNDCLASS wc = {0}; - - wc.lpfnWndProc = WndProc; - wc.hInstance = GetModuleHandle(NULL); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.lpszClassName = L"WindowClass"; - RegisterClass(&wc); - pSelf->hWindowFullScreen = ::CreateWindowEx( - NULL, - 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(pSelf->hWindowFullScreen, "Self", pSelf); - } - return pSelf->hWindowFullScreen; + HRESULT hr = S_OK; + + if(!pSelf) { + return NULL; + } + + if(!pSelf->hWindowFullScreen) { + WNDCLASS wc = {0}; + + wc.lpfnWndProc = WndProc; + wc.hInstance = GetModuleHandle(NULL); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszClassName = L"WindowClass"; + RegisterClass(&wc); + pSelf->hWindowFullScreen = ::CreateWindowEx( + NULL, + 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(pSelf->hWindowFullScreen, "Self", pSelf); + } + return pSelf->hWindowFullScreen; } static HRESULT HookWindow(plugin_video_dshow_consumer_t *pSelf, HWND hWnd) { - HRESULT hr = S_OK; + HRESULT hr = S_OK; - tsk_safeobj_lock(pSelf); + tsk_safeobj_lock(pSelf); - CHECK_HR(hr = UnhookWindow(pSelf)); + CHECK_HR(hr = UnhookWindow(pSelf)); - if ((pSelf->hWindow = hWnd)) { - pSelf->wndProc = (WNDPROC)SetWindowLongPtr(pSelf->hWindow, GWLP_WNDPROC, (LONG_PTR)WndProc); - if (!pSelf->wndProc) { - TSK_DEBUG_ERROR("HookWindowLongPtr() failed with errcode=%d", GetLastError()); - CHECK_HR(hr = E_FAIL); - } - pSelf->bWindowHooked = TRUE; - } + if ((pSelf->hWindow = hWnd)) { + pSelf->wndProc = (WNDPROC)SetWindowLongPtr(pSelf->hWindow, GWLP_WNDPROC, (LONG_PTR)WndProc); + if (!pSelf->wndProc) { + TSK_DEBUG_ERROR("HookWindowLongPtr() failed with errcode=%d", GetLastError()); + CHECK_HR(hr = E_FAIL); + } + pSelf->bWindowHooked = TRUE; + } bail: - tsk_safeobj_unlock(pSelf); - return S_OK; + tsk_safeobj_unlock(pSelf); + return S_OK; } static HRESULT UnhookWindow(struct plugin_video_dshow_consumer_s *pSelf) { - tsk_safeobj_lock(pSelf); - if (pSelf->hWindow && pSelf->wndProc) { - SetWindowLongPtr(pSelf->hWindow, GWLP_WNDPROC, (LONG_PTR)pSelf->wndProc); - pSelf->wndProc = NULL; - } - if(pSelf->hWindow) - { - ::InvalidateRect(pSelf->hWindow, NULL, FALSE); - } - pSelf->bWindowHooked = FALSE; - tsk_safeobj_unlock(pSelf); - return S_OK; + tsk_safeobj_lock(pSelf); + if (pSelf->hWindow && pSelf->wndProc) { + SetWindowLongPtr(pSelf->hWindow, GWLP_WNDPROC, (LONG_PTR)pSelf->wndProc); + pSelf->wndProc = NULL; + } + if(pSelf->hWindow) { + ::InvalidateRect(pSelf->hWindow, NULL, FALSE); + } + pSelf->bWindowHooked = FALSE; + tsk_safeobj_unlock(pSelf); + return S_OK; } #else /* !PLUGIN_DS_CV_USE_D3D9 */ -typedef struct plugin_video_dshow_consumer_s -{ - TMEDIA_DECLARE_CONSUMER; - - DSDisplay* display; - INT64 window; - - tsk_bool_t plugin_firefox; - tsk_bool_t started; - tsk_bool_t create_on_ui_thread; +typedef struct plugin_video_dshow_consumer_s { + TMEDIA_DECLARE_CONSUMER; + + DSDisplay* display; + INT64 window; + + tsk_bool_t plugin_firefox; + tsk_bool_t started; + tsk_bool_t create_on_ui_thread; } plugin_video_dshow_consumer_t; @@ -1084,166 +1009,170 @@ plugin_video_dshow_consumer_t; /* ============ Media Consumer Interface ================= */ static int plugin_video_dshow_consumer_set(tmedia_consumer_t *self, const tmedia_param_t* param) { - int ret = 0; - - if(!self || !param){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(param->value_type == tmedia_pvt_int64){ - if(tsk_striequals(param->key, "remote-hwnd")){ - DSCONSUMER(self)->window = (INT64)*((int64_t*)param->value); - if(DSCONSUMER(self)->display){ - if(DSCONSUMER(self)->window){ - DSCONSUMER(self)->display->attach(DSCONSUMER(self)->window); - } - else{ - DSCONSUMER(self)->display->detach(); - } - } - } - } - else if(param->value_type == tmedia_pvt_int32){ - if(tsk_striequals(param->key, "fullscreen")){ - if(DSCONSUMER(self)->display){ - DSCONSUMER(self)->display->setFullscreen(*((int32_t*)param->value) != 0); - } - } - else if(tsk_striequals(param->key, "create-on-current-thead")){ - DSCONSUMER(self)->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true; - } - else if(tsk_striequals(param->key, "plugin-firefox")){ - DSCONSUMER(self)->plugin_firefox = (*((int32_t*)param->value) != 0); - if(DSCONSUMER(self)->display){ - DSCONSUMER(self)->display->setPluginFirefox((DSCONSUMER(self)->plugin_firefox == tsk_true)); - } - } - } - - return ret; + int ret = 0; + + if(!self || !param) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(param->value_type == tmedia_pvt_int64) { + if(tsk_striequals(param->key, "remote-hwnd")) { + DSCONSUMER(self)->window = (INT64)*((int64_t*)param->value); + if(DSCONSUMER(self)->display) { + if(DSCONSUMER(self)->window) { + DSCONSUMER(self)->display->attach(DSCONSUMER(self)->window); + } + else { + DSCONSUMER(self)->display->detach(); + } + } + } + } + else if(param->value_type == tmedia_pvt_int32) { + if(tsk_striequals(param->key, "fullscreen")) { + if(DSCONSUMER(self)->display) { + DSCONSUMER(self)->display->setFullscreen(*((int32_t*)param->value) != 0); + } + } + else if(tsk_striequals(param->key, "create-on-current-thead")) { + DSCONSUMER(self)->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true; + } + else if(tsk_striequals(param->key, "plugin-firefox")) { + DSCONSUMER(self)->plugin_firefox = (*((int32_t*)param->value) != 0); + if(DSCONSUMER(self)->display) { + DSCONSUMER(self)->display->setPluginFirefox((DSCONSUMER(self)->plugin_firefox == tsk_true)); + } + } + } + + return ret; } static int plugin_video_dshow_consumer_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { - plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; - - if(!consumer || !codec && codec->plugin){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - TMEDIA_CONSUMER(consumer)->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps; - TMEDIA_CONSUMER(consumer)->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width; - TMEDIA_CONSUMER(consumer)->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height; - - if(!TMEDIA_CONSUMER(consumer)->video.display.width){ - TMEDIA_CONSUMER(consumer)->video.display.width = TMEDIA_CONSUMER(consumer)->video.in.width; - } - if(!TMEDIA_CONSUMER(consumer)->video.display.height){ - TMEDIA_CONSUMER(consumer)->video.display.height = TMEDIA_CONSUMER(consumer)->video.in.height; - } - - return 0; + plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; + + if(!consumer || !codec && codec->plugin) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + TMEDIA_CONSUMER(consumer)->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps; + TMEDIA_CONSUMER(consumer)->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width; + TMEDIA_CONSUMER(consumer)->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height; + + if(!TMEDIA_CONSUMER(consumer)->video.display.width) { + TMEDIA_CONSUMER(consumer)->video.display.width = TMEDIA_CONSUMER(consumer)->video.in.width; + } + if(!TMEDIA_CONSUMER(consumer)->video.display.height) { + TMEDIA_CONSUMER(consumer)->video.display.height = TMEDIA_CONSUMER(consumer)->video.in.height; + } + + return 0; } static int plugin_video_dshow_consumer_start(tmedia_consumer_t* self) { - plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; - - if(!consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(consumer->started){ - return 0; - } - - // create display on UI thread - if(!consumer->display){ - if (consumer->create_on_ui_thread) createOnUIThead(reinterpret_cast<HWND>((void*)consumer->window), (void**)&consumer->display, true, false); - else createOnCurrentThead(reinterpret_cast<HWND>((void*)consumer->window), (void**)&consumer->display, true, false); - - if(!consumer->display){ - TSK_DEBUG_ERROR("Failed to create display"); - return -2; - } - } - - // Set parameters - consumer->display->setPluginFirefox((consumer->plugin_firefox == tsk_true)); - consumer->display->setFps(TMEDIA_CONSUMER(consumer)->video.fps); - // do not change the display size: see hook() - // consumer->display->setSize(TMEDIA_CONSUMER(consumer)->video.display.width, TMEDIA_CONSUMER(consumer)->video.display.height); - if(consumer->window){ - consumer->display->attach(consumer->window); - } - - // Start display - consumer->display->start(); - consumer->started = tsk_true; - - return 0; + plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; + + if(!consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(consumer->started) { + return 0; + } + + // create display on UI thread + if(!consumer->display) { + if (consumer->create_on_ui_thread) { + createOnUIThead(reinterpret_cast<HWND>((void*)consumer->window), (void**)&consumer->display, true, false); + } + else { + createOnCurrentThead(reinterpret_cast<HWND>((void*)consumer->window), (void**)&consumer->display, true, false); + } + + if(!consumer->display) { + TSK_DEBUG_ERROR("Failed to create display"); + return -2; + } + } + + // Set parameters + consumer->display->setPluginFirefox((consumer->plugin_firefox == tsk_true)); + consumer->display->setFps(TMEDIA_CONSUMER(consumer)->video.fps); + // do not change the display size: see hook() + // consumer->display->setSize(TMEDIA_CONSUMER(consumer)->video.display.width, TMEDIA_CONSUMER(consumer)->video.display.height); + if(consumer->window) { + consumer->display->attach(consumer->window); + } + + // Start display + consumer->display->start(); + consumer->started = tsk_true; + + return 0; } static int plugin_video_dshow_consumer_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr) { - plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; - if(consumer && consumer->display && buffer){ - consumer->display->handleVideoFrame(buffer, TMEDIA_CONSUMER(consumer)->video.display.width, TMEDIA_CONSUMER(consumer)->video.display.height); - return 0; - } - else{ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; + if(consumer && consumer->display && buffer) { + consumer->display->handleVideoFrame(buffer, TMEDIA_CONSUMER(consumer)->video.display.width, TMEDIA_CONSUMER(consumer)->video.display.height); + return 0; + } + else { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } } static int plugin_video_dshow_consumer_pause(tmedia_consumer_t* self) { - plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; + plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; - if(!consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - if(!consumer->display){ - TSK_DEBUG_ERROR("Invalid internal grabber"); - return -2; - } + if(!consumer->display) { + TSK_DEBUG_ERROR("Invalid internal grabber"); + return -2; + } - //consumer->display->pause(); + //consumer->display->pause(); - return 0; + return 0; } static int plugin_video_dshow_consumer_stop(tmedia_consumer_t* self) { - plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; + plugin_video_dshow_consumer_t* consumer = (plugin_video_dshow_consumer_t*)self; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - if(!consumer->started){ - return 0; - } + if(!consumer->started) { + return 0; + } - if(!consumer->display){ - TSK_DEBUG_ERROR("Invalid internal display"); - return -2; - } + if(!consumer->display) { + TSK_DEBUG_ERROR("Invalid internal display"); + return -2; + } - TSK_DEBUG_INFO("Before stopping DirectShow consumer"); - consumer->display->stop(); - consumer->started = tsk_false; - TSK_DEBUG_INFO("After stopping DirectShow consumer"); + TSK_DEBUG_INFO("Before stopping DirectShow consumer"); + consumer->display->stop(); + consumer->started = tsk_false; + TSK_DEBUG_INFO("After stopping DirectShow consumer"); - return 0; + return 0; } @@ -1253,65 +1182,63 @@ static int plugin_video_dshow_consumer_stop(tmedia_consumer_t* self) /* constructor */ static tsk_object_t* plugin_video_dshow_consumer_ctor(tsk_object_t * self, va_list * app) { - CoInitializeEx(NULL, COINIT_MULTITHREADED); - - plugin_video_dshow_consumer_t *consumer = (plugin_video_dshow_consumer_t *)self; - if(consumer){ - /* init base */ - tmedia_consumer_init(TMEDIA_CONSUMER(consumer)); - TMEDIA_CONSUMER(consumer)->video.display.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24 - - /* init self */ - consumer->create_on_ui_thread = tsk_true; - TMEDIA_CONSUMER(consumer)->video.fps = 15; - TMEDIA_CONSUMER(consumer)->video.display.width = 352; - TMEDIA_CONSUMER(consumer)->video.display.height = 288; - TMEDIA_CONSUMER(consumer)->video.display.auto_resize = tsk_true; - } - return self; + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + plugin_video_dshow_consumer_t *consumer = (plugin_video_dshow_consumer_t *)self; + if(consumer) { + /* init base */ + tmedia_consumer_init(TMEDIA_CONSUMER(consumer)); + TMEDIA_CONSUMER(consumer)->video.display.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24 + + /* init self */ + consumer->create_on_ui_thread = tsk_true; + TMEDIA_CONSUMER(consumer)->video.fps = 15; + TMEDIA_CONSUMER(consumer)->video.display.width = 352; + TMEDIA_CONSUMER(consumer)->video.display.height = 288; + TMEDIA_CONSUMER(consumer)->video.display.auto_resize = tsk_true; + } + return self; } /* destructor */ static tsk_object_t* plugin_video_dshow_consumer_dtor(tsk_object_t * self) -{ - plugin_video_dshow_consumer_t *consumer = (plugin_video_dshow_consumer_t *)self; - if(consumer){ - - /* stop */ - if(consumer->started){ - plugin_video_dshow_consumer_stop((tmedia_consumer_t*)self); - } - - /* deinit base */ - tmedia_consumer_deinit(TMEDIA_CONSUMER(consumer)); - /* deinit self */ - SAFE_DELETE_PTR(consumer->display); - - } - - return self; +{ + plugin_video_dshow_consumer_t *consumer = (plugin_video_dshow_consumer_t *)self; + if(consumer) { + + /* stop */ + if(consumer->started) { + plugin_video_dshow_consumer_stop((tmedia_consumer_t*)self); + } + + /* deinit base */ + tmedia_consumer_deinit(TMEDIA_CONSUMER(consumer)); + /* deinit self */ + SAFE_DELETE_PTR(consumer->display); + + } + + return self; } /* object definition */ -static const tsk_object_def_t plugin_video_dshow_consumer_def_s = -{ - sizeof(plugin_video_dshow_consumer_t), - plugin_video_dshow_consumer_ctor, - plugin_video_dshow_consumer_dtor, - tsk_null, +static const tsk_object_def_t plugin_video_dshow_consumer_def_s = { + sizeof(plugin_video_dshow_consumer_t), + plugin_video_dshow_consumer_ctor, + plugin_video_dshow_consumer_dtor, + tsk_null, }; /* plugin definition*/ -static const tmedia_consumer_plugin_def_t plugin_video_dshow_consumer_plugin_def_s = -{ - &plugin_video_dshow_consumer_def_s, - - tmedia_video, - "Microsoft DirectShow consumer (using custom source)", - - plugin_video_dshow_consumer_set, - plugin_video_dshow_consumer_prepare, - plugin_video_dshow_consumer_start, - plugin_video_dshow_consumer_consume, - plugin_video_dshow_consumer_pause, - plugin_video_dshow_consumer_stop +static const tmedia_consumer_plugin_def_t plugin_video_dshow_consumer_plugin_def_s = { + &plugin_video_dshow_consumer_def_s, + + tmedia_video, + "Microsoft DirectShow consumer (using custom source)", + + plugin_video_dshow_consumer_set, + plugin_video_dshow_consumer_prepare, + plugin_video_dshow_consumer_start, + plugin_video_dshow_consumer_consume, + plugin_video_dshow_consumer_pause, + plugin_video_dshow_consumer_stop }; const tmedia_consumer_plugin_def_t *plugin_video_dshow_consumer_plugin_def_t = &plugin_video_dshow_consumer_plugin_def_s; |