From 6bcf419d2e8f739b432d4790d1ba9d48ab65365b Mon Sep 17 00:00:00 2001 From: fcolin Date: Fri, 18 Nov 2011 12:14:12 +0000 Subject: --- ARMFCaptureD3D/preview.cpp | 701 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 701 insertions(+) create mode 100644 ARMFCaptureD3D/preview.cpp (limited to 'ARMFCaptureD3D/preview.cpp') diff --git a/ARMFCaptureD3D/preview.cpp b/ARMFCaptureD3D/preview.cpp new file mode 100644 index 0000000..e8d3624 --- /dev/null +++ b/ARMFCaptureD3D/preview.cpp @@ -0,0 +1,701 @@ +////////////////////////////////////////////////////////////////////////// +// +// preview.cpp: Manages video preview. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +////////////////////////////////////////////////////////////////////////// + +#include "ARMFCaptureD3D.h" +#include "debug.h" +#include +#include "ARAnalyse.h" + +extern ARAnalyse *g_pAnalyse; + +extern HWND g_hStatus; + +//------------------------------------------------------------------- +// CreateInstance +// +// Static class method to create the CPreview object. +//------------------------------------------------------------------- + +HRESULT CPreview::CreateInstance( + HWND hVideo, // Handle to the video window. + HWND hEvent, // Handle to the window to receive notifications. + CPreview **ppPlayer // Receives a pointer to the CPreview object. + ) +{ + assert(hVideo != NULL); + assert(hEvent != NULL); + + if (ppPlayer == NULL) + { + return E_POINTER; + } + + CPreview *pPlayer = new (std::nothrow) CPreview(hVideo, hEvent); + + // The CPlayer constructor sets the ref count to 1. + + if (pPlayer == NULL) + { + return E_OUTOFMEMORY; + } + + HRESULT hr = pPlayer->Initialize(); + + if (SUCCEEDED(hr)) + { + *ppPlayer = pPlayer; + (*ppPlayer)->AddRef(); + } + + SafeRelease(&pPlayer); + return hr; +} + + +//------------------------------------------------------------------- +// constructor +//------------------------------------------------------------------- + +CPreview::CPreview(HWND hVideo, HWND hEvent) : + m_pReader(NULL), + m_pSource(NULL), + m_hwndVideo(hVideo), + m_hwndEvent(hEvent), + m_nRefCount(1), + m_pwszSymbolicLink(NULL), + m_cchSymbolicLink(0) +{ + InitializeCriticalSection(&m_critsec); + m_video = true; + m_transform = false; + m_moyen = false; +} + +//------------------------------------------------------------------- +// destructor +//------------------------------------------------------------------- + +CPreview::~CPreview() +{ + CloseDevice(); + m_draw.DestroyDevice(); + DeleteCriticalSection(&m_critsec); +} + + +//------------------------------------------------------------------- +// Initialize +// +// Initializes the object. +//------------------------------------------------------------------- + +HRESULT CPreview::Initialize() +{ + HRESULT hr = S_OK; + + hr = m_draw.CreateDevice(m_hwndVideo); + + return hr; +} + +bool CPreview::ToggleVideo() +{ + m_video = !m_video; + return m_video; +} + +bool CPreview::ToggleTransform() +{ + m_transform = !m_transform; + return m_transform; +} +bool CPreview::ToggleMoyen() +{ + m_moyen = !m_moyen; + return m_moyen; +} + +//------------------------------------------------------------------- +// CloseDevice +// +// Releases all resources held by this object. +//------------------------------------------------------------------- + +HRESULT CPreview::CloseDevice() +{ + EnterCriticalSection(&m_critsec); + + if ( m_pSource ) + { + m_pSource->Stop(); + m_pSource->Shutdown(); + } + + SafeRelease(&m_pReader); + SafeRelease(&m_pSource); + + + CoTaskMemFree(m_pwszSymbolicLink); + m_pwszSymbolicLink = NULL; + m_cchSymbolicLink = 0; + + LeaveCriticalSection(&m_critsec); + return S_OK; +} + + +/////////////// IUnknown methods /////////////// + +//------------------------------------------------------------------- +// AddRef +//------------------------------------------------------------------- + +ULONG CPreview::AddRef() +{ + return InterlockedIncrement(&m_nRefCount); +} + + +//------------------------------------------------------------------- +// Release +//------------------------------------------------------------------- + +ULONG CPreview::Release() +{ + ULONG uCount = InterlockedDecrement(&m_nRefCount); + if (uCount == 0) + { + delete this; + } + // For thread safety, return a temporary variable. + return uCount; +} + + + +//------------------------------------------------------------------- +// QueryInterface +//------------------------------------------------------------------- + +HRESULT CPreview::QueryInterface(REFIID riid, void** ppv) +{ + static const QITAB qit[] = + { + QITABENT(CPreview, IMFSourceReaderCallback), + { 0 }, + }; + return QISearch(this, qit, riid, ppv); +} + + +/////////////// IMFSourceReaderCallback methods /////////////// + +//------------------------------------------------------------------- +// OnReadSample +// +// Called when the IMFMediaSource::ReadSample method completes. +//------------------------------------------------------------------- + +HRESULT CPreview::OnReadSample( + HRESULT hrStatus, + DWORD dwStreamIndex, + DWORD /*dwStreamFlags*/, + LONGLONG llTimestamp, + IMFSample *pSample // Can be NULL + ) +{ + HRESULT hr = hrStatus; + IMFMediaBuffer *pBuffer = NULL; + DWORD cbCurrentLength = 0; + + EnterCriticalSection(&m_critsec); + + if (SUCCEEDED(hr)) + { + if (pSample) + { + // Get the video frame buffer from the sample. + hr = pSample->ConvertToContiguousBuffer(&pBuffer); + + // AR analyse + if ( g_pAnalyse && SUCCEEDED(hr) ) + { + BYTE *image_buffer=0; + pBuffer->Lock( &image_buffer, 0, &cbCurrentLength ); + double time = (double)(llTimestamp)/ 10000000.0; + // Gray scale & blur & threshold + if ( m_transform) + g_pAnalyse->Transform( image_buffer, cbCurrentLength, m_moyen ); + g_pAnalyse->Analyse(time, image_buffer, cbCurrentLength ); + pBuffer->Unlock(); + } + // Draw the frame. + + if ( m_video && SUCCEEDED(hr)) + { + hr = m_draw.DrawFrame(pBuffer); + } + + } + } + // Request the next frame. + if (m_pReader && SUCCEEDED(hr)) + { + hr = m_pReader->ReadSample( + dwStreamIndex, + 0, + NULL, // actual + NULL, // flags + NULL, // timestamp + NULL // sample + ); + } + + if (FAILED(hr)) + { + NotifyError(hr); + } + if ( pBuffer ) SafeRelease(&pBuffer); + + LeaveCriticalSection(&m_critsec); + + if (g_pAnalyse && SUCCEEDED(hr)) + { + // display status message + WCHAR szBuf[1024]; + + StringCbPrintf(szBuf, sizeof(szBuf),TEXT("Markers count=%3d confidence=( %0.1f / %0.1f / %0.1f ) FPS=( %0.1f / %0.1f / %0.1f ) delay=( %0.3f / %0.3f / %0.3f )"), + g_pAnalyse->markers.size(), + g_pAnalyse->confidence.Min(), g_pAnalyse->confidence.Max(), g_pAnalyse->confidence.Avg() , + g_pAnalyse->frame_per_seconds.Min(), g_pAnalyse->frame_per_seconds.Max(), g_pAnalyse->frame_per_seconds.Avg(), + g_pAnalyse->frame_delay.Min(), g_pAnalyse->frame_delay.Max(), g_pAnalyse->frame_delay.Avg() ); + SendMessage(g_hStatus, SB_SETTEXT, 0, (LPARAM)(LPSTR)szBuf ); + } + + return hr; +} + + +//------------------------------------------------------------------- +// TryMediaType +// +// Test a proposed video format. +//------------------------------------------------------------------- + +HRESULT CPreview::TryMediaType(IMFMediaType *pType) +{ + HRESULT hr = S_OK; + + BOOL bFound = FALSE; + GUID subtype = { 0 }; + + hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); + + if (FAILED(hr)) + { + return hr; + } + + // Do we support this type directly? + if (m_draw.IsFormatSupported(subtype)) + { + bFound = TRUE; + } + else + { + // Can we decode this media type to one of our supported + // output formats? + + for (DWORD i = 0; ; i++) + { + // Get the i'th format. + hr = m_draw.GetFormat(i, &subtype); + if (FAILED(hr)) { break; } + + hr = pType->SetGUID(MF_MT_SUBTYPE, subtype); + + if (FAILED(hr)) { break; } + + // Try to set this type on the source reader. + hr = m_pReader->SetCurrentMediaType( + (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, + NULL, + pType + ); + + if (SUCCEEDED(hr)) + { + bFound = TRUE; + break; + } + } + } + + if (bFound) + { + EnterCriticalSection(&m_critsec); + hr = m_draw.SetVideoType(pType); + LeaveCriticalSection(&m_critsec); + } + + return hr; +} + +//------------------------------------------------------------------- +// SetDevice +// +// Set up preview for a specified video capture device. +//------------------------------------------------------------------- + +HRESULT CPreview::SetDevice(IMFActivate *pActivate, int formatType) +{ + HRESULT hr = S_OK; + + IMFAttributes *pAttributes = NULL; + IMFMediaType *pType = NULL; + + EnterCriticalSection(&m_critsec); + + // Release the current device, if any. + + hr = CloseDevice(); + + // Create the media source for the device. + if (SUCCEEDED(hr)) + { + hr = pActivate->ActivateObject( + __uuidof(IMFMediaSource), + (void**)&m_pSource + ); + } + + // Get the symbolic link. + if (SUCCEEDED(hr)) + { + hr = pActivate->GetAllocatedString( + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, + &m_pwszSymbolicLink, + &m_cchSymbolicLink + ); + } + + // + // Create the source reader. + // + + // Create an attribute store to hold initialization settings. + + if (SUCCEEDED(hr)) + { + hr = MFCreateAttributes(&pAttributes, 2); + } + if (SUCCEEDED(hr)) + { + hr = pAttributes->SetUINT32(MF_READWRITE_DISABLE_CONVERTERS, TRUE); + } + + // Set the callback pointer. + if (SUCCEEDED(hr)) + { + hr = pAttributes->SetUnknown( + MF_SOURCE_READER_ASYNC_CALLBACK, + this + ); + } + + if (SUCCEEDED(hr)) + { + hr = MFCreateSourceReaderFromMediaSource( + m_pSource, + pAttributes, + &m_pReader + ); + } + + + // Try to find a suitable output type. + if (SUCCEEDED(hr)) + { + + for (DWORD i = formatType; ; i++) + { + hr = m_pReader->GetNativeMediaType( + (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, + i, + &pType + ); + + if (FAILED(hr)) { break; } + + //hr = TryMediaType(pType); already done in SetFormat !! + hr = SetFormat(pType); + + SafeRelease(&pType); + + if (SUCCEEDED(hr)) + { + // Found an output type. + + break; + } + } + } + if (SUCCEEDED(hr)) + { + // Ask for the first sample. + hr = m_pReader->ReadSample( + (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, + 0, + NULL, + NULL, + NULL, + NULL + ); + } + + if (FAILED(hr)) + { + if (m_pSource) + { + m_pSource->Shutdown(); + + // NOTE: The source reader shuts down the media source + // by default, but we might not have gotten that far. + } + CloseDevice(); + } + + + SafeRelease(&pAttributes); + SafeRelease(&pType); + + LeaveCriticalSection(&m_critsec); + return hr; +} + + + +//------------------------------------------------------------------- +// ResizeVideo +// Resizes the video rectangle. +// +// The application should call this method if the size of the video +// window changes; e.g., when the application receives WM_SIZE. +//------------------------------------------------------------------- + +HRESULT CPreview::ResizeVideo(WORD /*width*/, WORD /*height*/) +{ + HRESULT hr = S_OK; + + EnterCriticalSection(&m_critsec); + + hr = m_draw.ResetDevice(); + + if (FAILED(hr)) + { + MessageBox(NULL, L"ResetDevice failed!", NULL, MB_OK); + } + + LeaveCriticalSection(&m_critsec); + + return hr; +} + + +//------------------------------------------------------------------- +// CheckDeviceLost +// Checks whether the current device has been lost. +// +// The application should call this method in response to a +// WM_DEVICECHANGE message. (The application must register for +// device notification to receive this message.) +//------------------------------------------------------------------- + +HRESULT CPreview::CheckDeviceLost(DEV_BROADCAST_HDR *pHdr, BOOL *pbDeviceLost) +{ + DEV_BROADCAST_DEVICEINTERFACE *pDi = NULL; + + if (pbDeviceLost == NULL) + { + return E_POINTER; + } + + *pbDeviceLost = FALSE; + + if (pHdr == NULL) + { + return S_OK; + } + + if (pHdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) + { + return S_OK; + } + + pDi = (DEV_BROADCAST_DEVICEINTERFACE*)pHdr; + + + EnterCriticalSection(&m_critsec); + + if (m_pwszSymbolicLink) + { + if (_wcsicmp(m_pwszSymbolicLink, pDi->dbcc_name) == 0) + { + *pbDeviceLost = TRUE; + } + } + + LeaveCriticalSection(&m_critsec); + + return S_OK; +} + +HRESULT CPreview::EnumerateCaptureFormats(IMFMediaType ***pppTypes, UINT32 *pcCount) +{ + IMFPresentationDescriptor *pPD = NULL; + IMFStreamDescriptor *pSD = NULL; + IMFMediaTypeHandler *pHandler = NULL; + IMFMediaType *pType = NULL; + + HRESULT hr = m_pSource->CreatePresentationDescriptor(&pPD); + if (FAILED(hr)) + { + goto done; + } + + BOOL fSelected; + hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); + if (FAILED(hr)) + { + goto done; + } + + hr = pSD->GetMediaTypeHandler(&pHandler); + if (FAILED(hr)) + { + goto done; + } + + DWORD cTypes = 0; + hr = pHandler->GetMediaTypeCount(&cTypes); + if (FAILED(hr)) + { + goto done; + } + *pcCount = cTypes; + *pppTypes = (IMFMediaType**)CoTaskMemAlloc( cTypes * sizeof(IMFMediaType*)); + + for (DWORD i = 0; i < cTypes; i++) + { + hr = pHandler->GetMediaTypeByIndex(i, &pType); + if (FAILED(hr)) + { + goto done; + } + (*pppTypes)[i] = pType; + pType->AddRef(); + // LogMediaType(pType); + //OutputDebugString(L"\n"); + + SafeRelease(&pType); + } + +done: + SafeRelease(&pPD); + SafeRelease(&pSD); + SafeRelease(&pHandler); + SafeRelease(&pType); + return hr; +} + +HRESULT CPreview::SetFormat(IMFMediaType *pType) +{ + IMFPresentationDescriptor *pPD = NULL; + IMFStreamDescriptor *pSD = NULL; + IMFMediaTypeHandler *pHandler = NULL; + UINT32 width; + UINT32 height; + UINT32 sample_size; + //IMFMediaType *pType = NULL; + EnterCriticalSection(&m_critsec); + + HRESULT hr = m_pSource->CreatePresentationDescriptor(&pPD); + if (FAILED(hr)) + { + goto done; + } + + BOOL fSelected; + hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); + if (FAILED(hr)) + { + goto done; + } + + hr = pSD->GetMediaTypeHandler(&pHandler); + if (FAILED(hr)) + { + goto done; + } + + /*hr = pHandler->GetMediaTypeByIndex(dwFormatIndex, &pType); + if (FAILED(hr)) + { + goto done; + }*/ + + hr = pHandler->SetCurrentMediaType(pType); + if (FAILED(hr)) + { + goto done; + } + LeaveCriticalSection(&m_critsec); + + hr = TryMediaType(pType); + + EnterCriticalSection(&m_critsec); + + if (FAILED(hr)) + { + goto done; + } + hr = MFGetAttributeSize( pType, MF_MT_FRAME_SIZE, &width, &height); + if (FAILED(hr)) + { + goto done; + } + hr = pType->GetUINT32( MF_MT_SAMPLE_SIZE, &sample_size); + if (FAILED(hr)) + { + goto done; + } + LogMediaType(pType); + + // Initialize AR Anayse + if ( g_pAnalyse ) + g_pAnalyse->InitialiseTracker( width, height, sample_size ); + +done: + SafeRelease(&pPD); + SafeRelease(&pSD); + SafeRelease(&pHandler); + //SafeRelease(&pType); + + LeaveCriticalSection(&m_critsec); + + return hr; +} + + + + -- cgit v1.1