2098 lines
53 KiB
C++
2098 lines
53 KiB
C++
// 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 "stdafx.h"
|
|
|
|
#include "resource.h"
|
|
#include "tedapp.h"
|
|
#include "tedmaintoolbar.h"
|
|
#include "dock.h"
|
|
#include "mfapi.h"
|
|
#include "mferror.h"
|
|
#include "commdlg.h"
|
|
#include "splitterbar.h"
|
|
#include "tedtransformdialog.h"
|
|
#include "dmo.h"
|
|
#include "propertyview.h"
|
|
#include "tedinputguiddialog.h"
|
|
#include "Tedcontentprotectionmanager.h"
|
|
#include "tedplayer.h"
|
|
#include <initguid.h>
|
|
#include <mferror.h>
|
|
#include <uuids.h>
|
|
#include <Windowsx.h>
|
|
#include "tedtranscode.h"
|
|
|
|
#include <assert.h>
|
|
|
|
unsigned int CTedApp::MAIN_TOOLBAR_ID = 5000;
|
|
const int CTedApp::m_nSeekerRange = 100;
|
|
const UINT_PTR CTedApp::ms_nTimerID = 0;
|
|
const DWORD CTedApp::ms_dwTimerLen = 200;
|
|
const double CTedApp::m_dblInitialSplitterPos = 0.65;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
HINSTANCE g_hInst = NULL;
|
|
HINSTANCE g_hTedUtilInst = NULL;
|
|
CTedApp * g_pApp;
|
|
|
|
//////////////////////////////////
|
|
// CTedAppVideoWindowHandler
|
|
// Provides video windows to TEDUTIL.
|
|
|
|
CTedAppVideoWindowHandler::CTedAppVideoWindowHandler(HWND hWndParent)
|
|
: m_hWndParent(hWndParent)
|
|
, m_cRef(0)
|
|
{
|
|
}
|
|
|
|
CTedAppVideoWindowHandler::~CTedAppVideoWindowHandler()
|
|
{
|
|
for(size_t i = 0; i < m_arrWindows.GetCount(); i++)
|
|
{
|
|
if(m_arrWindows.GetAt(i)->m_hWnd) m_arrWindows.GetAt(i)->DestroyWindow();
|
|
delete m_arrWindows.GetAt(i);
|
|
}
|
|
}
|
|
|
|
HRESULT CTedAppVideoWindowHandler::GetVideoWindow(LONG_PTR* phWnd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
RECT rectLastWindow = {0, 0, 0, 0};
|
|
if(m_arrWindows.GetCount() >= 1)
|
|
{
|
|
m_arrWindows.GetAt(m_arrWindows.GetCount() - 1)->GetWindowRect(&rectLastWindow);
|
|
}
|
|
|
|
RECT rect;
|
|
rect.left = m_dwCascadeMargin + rectLastWindow.left;
|
|
rect.top = m_dwCascadeMargin + rectLastWindow.top;
|
|
rect.right = rect.left + m_dwDefaultWindowWidth;
|
|
rect.bottom = rect.top + m_dwDefaultWindowHeight;
|
|
|
|
if(NULL == phWnd)
|
|
{
|
|
IFC( E_POINTER );
|
|
}
|
|
|
|
CTedVideoWindow* pVideoWindow = new CTedVideoWindow();
|
|
if(pVideoWindow->Create(m_hWndParent, &rect, LoadAtlString(IDS_VIDEO_PLAYBACK), WS_CAPTION | WS_POPUPWINDOW, 0, 0U, NULL) == NULL)
|
|
{
|
|
IFC( HRESULT_FROM_WIN32(GetLastError()) );
|
|
}
|
|
|
|
*phWnd = (LONG_PTR) pVideoWindow->m_hWnd;
|
|
m_arrWindows.Add(pVideoWindow);
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTedAppVideoWindowHandler::ReleaseVideoWindow(LONG_PTR hWnd)
|
|
{
|
|
for(size_t i = 0; i < m_arrWindows.GetCount(); ++i)
|
|
{
|
|
CTedVideoWindow* pWindow = m_arrWindows.GetAt(i);
|
|
|
|
if(pWindow->m_hWnd == (HWND) hWnd)
|
|
{
|
|
m_arrWindows.RemoveAt(i);
|
|
--i;
|
|
|
|
pWindow->DestroyWindow();
|
|
delete pWindow;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CTedAppVideoWindowHandler::ShowWindows(int nCmdShow)
|
|
{
|
|
for(size_t i = 0; i < m_arrWindows.GetCount(); i++)
|
|
{
|
|
m_arrWindows.GetAt(i)->ShowWindow(nCmdShow);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CTedAppVideoWindowHandler::QueryInterface(REFIID riid, void** ppInterface)
|
|
{
|
|
if(NULL == ppInterface)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
if(riid == IID_IUnknown)
|
|
{
|
|
IUnknown* punk = this;
|
|
*ppInterface = punk;
|
|
AddRef();
|
|
}
|
|
else if(riid == IID_ITedVideoWindowHandler)
|
|
{
|
|
ITedVideoWindowHandler* ptvwh = this;
|
|
*ppInterface = ptvwh;
|
|
AddRef();
|
|
}
|
|
else
|
|
{
|
|
*ppInterface = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
ULONG CTedAppVideoWindowHandler::AddRef()
|
|
{
|
|
LONG cRef = InterlockedIncrement(&m_cRef);
|
|
|
|
return cRef;
|
|
}
|
|
|
|
ULONG CTedAppVideoWindowHandler::Release()
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
|
|
if(0 == cRef)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CTedAppMediaEventHandler
|
|
// Decouples player from app class. Initiates application response to media events
|
|
|
|
CTedAppMediaEventHandler::CTedAppMediaEventHandler(CTedApp* pApp)
|
|
: m_pApp(pApp)
|
|
{
|
|
}
|
|
|
|
CTedAppTopoEventHandler::~CTedAppTopoEventHandler()
|
|
{
|
|
}
|
|
|
|
void CTedAppMediaEventHandler::NotifyEventError(HRESULT hr)
|
|
{
|
|
m_pApp->HandleMMError(LoadAtlString(IDS_E_MEDIA_EVENT), hr);
|
|
}
|
|
|
|
void CTedAppMediaEventHandler::HandleMediaEvent(IMFMediaEvent* pEvent)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
MediaEventType met;
|
|
HRESULT hrEvent;
|
|
|
|
IFC( pEvent->GetType(&met) );
|
|
IFC( pEvent->GetStatus(&hrEvent) );
|
|
|
|
|
|
if(SUCCEEDED(hrEvent))
|
|
{
|
|
switch(met)
|
|
{
|
|
case MESessionStarted:
|
|
m_pApp->PostMessage(WM_MF_SESSIONPLAY, hrEvent, 0);
|
|
break;
|
|
case MESessionEnded:
|
|
m_pApp->PostMessage(WM_MF_SESSIONENDED, hrEvent, 0);
|
|
break;
|
|
case MESessionTopologySet:
|
|
m_pApp->PostMessage(WM_MF_TOPOLOGYSET, hrEvent, 0);
|
|
break;
|
|
case MESessionTopologyStatus:
|
|
{
|
|
UINT32 unTopoStatus = MFGetAttributeUINT32(pEvent, MF_EVENT_TOPOLOGY_STATUS, 0);
|
|
if(MF_TOPOSTATUS_READY == unTopoStatus)
|
|
{
|
|
m_pApp->PostMessage(WM_MF_TOPOLOGYREADY, hrEvent, 0);
|
|
}
|
|
}
|
|
break;
|
|
case MESessionCapabilitiesChanged:
|
|
m_pApp->PostMessageW(WM_MF_CAPABILITIES_CHANGED, hrEvent, 0);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(met)
|
|
{
|
|
case MESessionStarted:
|
|
m_pApp->HandleMMError(LoadAtlString(IDS_E_PLAYBACK_START), hrEvent);
|
|
break;
|
|
case MESessionTopologySet:
|
|
m_pApp->PostMessage(WM_MF_TOPOLOGYSET, hrEvent, 0);
|
|
break;
|
|
case MESessionTopologiesCleared:
|
|
// This can fail if the session has been closed, but
|
|
// this is OK -- the session will still accept new topologies.
|
|
break;
|
|
default:
|
|
NotifyEventError(hrEvent);
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if(FAILED(hr))
|
|
{
|
|
NotifyEventError(hr);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// CTedAppTopoEventHandler
|
|
// Receives event notifications from the topology editor
|
|
|
|
CTedAppTopoEventHandler::CTedAppTopoEventHandler(CTedApp* pApp)
|
|
: m_pApp(pApp)
|
|
{
|
|
}
|
|
|
|
HRESULT CTedAppTopoEventHandler::NotifyAddedNode(int nNodeID)
|
|
{
|
|
m_pApp->NotifyTopoChange();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CTedAppTopoEventHandler::NotifyRemovedNode(int nNodeID)
|
|
{
|
|
m_pApp->NotifyTopoChange();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CTedAppTopoEventHandler::NotifyConnection(int nUpNodeID, int nDownNodeID)
|
|
{
|
|
m_pApp->NotifyTopoChange();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CTedAppTopoEventHandler::NotifyDisconnection(int nUpNodeID, int nDownNodeID)
|
|
{
|
|
m_pApp->NotifyTopoChange();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CTedAppTopoEventHandler::QueryInterface(REFIID riid, void** ppInterface)
|
|
{
|
|
if(NULL == ppInterface)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
if(riid == IID_IUnknown)
|
|
{
|
|
IUnknown* punk = this;
|
|
*ppInterface = punk;
|
|
AddRef();
|
|
}
|
|
else if(riid == IID_ITedTopoEventHandler)
|
|
{
|
|
ITedTopoEventHandler* ptteh = this;
|
|
*ppInterface = ptteh;
|
|
AddRef();
|
|
}
|
|
else
|
|
{
|
|
*ppInterface = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
ULONG CTedAppTopoEventHandler::AddRef()
|
|
{
|
|
LONG cRef = InterlockedIncrement(&m_cRef);
|
|
|
|
return cRef;
|
|
}
|
|
|
|
ULONG CTedAppTopoEventHandler::Release()
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
|
|
if(0 == cRef)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//CTedChooserDialog
|
|
// Generic drop-down selection dialog
|
|
|
|
CTedChooserDialog::CTedChooserDialog(const CAtlString& strTitle)
|
|
: m_strTitle(strTitle)
|
|
{
|
|
}
|
|
|
|
void CTedChooserDialog::AddPossibleChoice(CAtlStringW strChoice)
|
|
{
|
|
m_arrChoices.Add(strChoice);
|
|
}
|
|
|
|
|
|
LRESULT CTedChooserDialog::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
SetWindowText(m_strTitle);
|
|
|
|
m_hChooserCombo = GetDlgItem(IDC_CHOOSER);
|
|
|
|
for(DWORD i = 0; i < m_arrChoices.GetCount(); i++)
|
|
{
|
|
::SendMessage(m_hChooserCombo, CB_ADDSTRING, 0, (LPARAM) m_arrChoices.GetAt(i).GetString());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedChooserDialog::OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr;
|
|
int comboLength = ::GetWindowTextLength(m_hChooserCombo);
|
|
|
|
LPWSTR strCombo = new WCHAR[comboLength + 1];
|
|
CHECK_ALLOC( strCombo );
|
|
|
|
::GetWindowText(m_hChooserCombo, strCombo, comboLength + 1);
|
|
m_strChoice = CAtlStringW(strCombo);
|
|
|
|
delete[] strCombo;
|
|
|
|
Cleanup:
|
|
EndDialog(IDOK);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedChooserDialog::OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
EndDialog(IDCANCEL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
LRESULT CTedAboutDialog::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
WCHAR szFileName[1024];
|
|
if ( !GetModuleFileName(g_hInst, szFileName, 1024) )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
if(NULL == hFile)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
FILETIME LastModifiedTime;
|
|
if( !GetFileTime(hFile, NULL, NULL, &LastModifiedTime) )
|
|
{
|
|
CloseHandle(hFile);
|
|
return GetLastError();
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
|
|
SYSTEMTIME SystemTime;
|
|
if( !FileTimeToSystemTime(&LastModifiedTime, &SystemTime) )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
SYSTEMTIME LocalTime;
|
|
if( !SystemTimeToTzSpecificLocalTime(NULL, &SystemTime, &LocalTime) )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
WCHAR szVersion[10];
|
|
if( 0 == LoadString(g_hInst, IDS_VERSION, szVersion, 10) )
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
CAtlString strVersion;
|
|
strVersion.FormatMessage(IDS_APP_VERSION, szVersion, LocalTime.wMonth, LocalTime.wDay, LocalTime.wYear);
|
|
SetDlgItemText(IDS_VERSION, strVersion.GetString());
|
|
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CAtlString CTedInputURLDialog::GetURL()
|
|
{
|
|
return m_strURL;
|
|
}
|
|
|
|
LRESULT CTedInputURLDialog::OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr;
|
|
HWND hInputURLWnd = GetDlgItem(IDC_INPUTURL);
|
|
|
|
int iTextLength = ::GetWindowTextLength(hInputURLWnd);
|
|
|
|
LPWSTR szURL = new WCHAR[iTextLength + 1];
|
|
CHECK_ALLOC( szURL );
|
|
|
|
::GetWindowText(hInputURLWnd, szURL, iTextLength + 1);
|
|
m_strURL.SetString(szURL);
|
|
|
|
delete[] szURL;
|
|
|
|
Cleanup:
|
|
EndDialog(IDOK);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CTedCaptureSourceDialog::CTedCaptureSourceDialog( bool bVideo )
|
|
: m_ppSourceActivates( NULL )
|
|
, m_dwActivates( 0 )
|
|
, m_dwSelectedIndex( 0 )
|
|
{
|
|
EnumCaptureSources( bVideo );
|
|
}
|
|
|
|
CTedCaptureSourceDialog::~CTedCaptureSourceDialog()
|
|
{
|
|
//
|
|
// Cleanup
|
|
//
|
|
if ( m_ppSourceActivates )
|
|
{
|
|
for ( DWORD i = 0; i < m_dwActivates; i++ )
|
|
{
|
|
m_ppSourceActivates[ i ]->Release();
|
|
}
|
|
|
|
CoTaskMemFree( m_ppSourceActivates );
|
|
}
|
|
}
|
|
|
|
IMFActivate* CTedCaptureSourceDialog::GetSourceActivate()
|
|
{
|
|
IMFActivate* pActivate = NULL;
|
|
|
|
if ( ( NULL != m_ppSourceActivates ) &&
|
|
( m_dwSelectedIndex < m_dwActivates ) )
|
|
{
|
|
pActivate = m_ppSourceActivates[ m_dwSelectedIndex ];
|
|
pActivate ->AddRef();
|
|
}
|
|
|
|
return pActivate;
|
|
}
|
|
|
|
LRESULT CTedCaptureSourceDialog::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
//
|
|
// Fill in the dropdown values based on enumerated activates
|
|
//
|
|
for ( DWORD i = 0; i < m_dwActivates; i++ )
|
|
{
|
|
UINT32 nLen = 0;
|
|
WCHAR* pwsz = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Get the friendly name
|
|
//
|
|
hr = m_ppSourceActivates[ i ]->GetStringLength( MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
|
|
&nLen );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
pwsz = new WCHAR[ nLen + 1 ];
|
|
if ( pwsz == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = m_ppSourceActivates[ i ]->GetString( MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
|
|
pwsz,
|
|
nLen + 1,
|
|
&nLen );
|
|
}
|
|
|
|
//
|
|
// Add to the dropdown
|
|
//
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
ComboBox_AddString( GetDlgItem( IDC_COMBOSOURCES ), pwsz );
|
|
}
|
|
else
|
|
{
|
|
ComboBox_AddString( GetDlgItem( IDC_COMBOSOURCES ), TEXT("Capture Source") );
|
|
}
|
|
|
|
if ( pwsz )
|
|
{
|
|
delete[] pwsz;
|
|
}
|
|
}
|
|
|
|
if ( m_dwActivates != 0 )
|
|
{
|
|
//
|
|
// Preselect the first one
|
|
//
|
|
ComboBox_SetCurSel( GetDlgItem( IDC_COMBOSOURCES ), 0 );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedCaptureSourceDialog::OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
m_dwSelectedIndex = ComboBox_GetCurSel( GetDlgItem( IDC_COMBOSOURCES ) );
|
|
|
|
EndDialog(IDOK);
|
|
return 0;
|
|
}
|
|
|
|
HRESULT CTedCaptureSourceDialog::EnumCaptureSources( bool bVideo )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMFAttributes* pAttributes = NULL;
|
|
|
|
//
|
|
// Set source type GUID to indicate video capture devices
|
|
//
|
|
hr = MFCreateAttributes( &pAttributes, 10 );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
if ( bVideo )
|
|
{
|
|
hr = pAttributes->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID );
|
|
}
|
|
else
|
|
{
|
|
hr = pAttributes->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enumerate the capture sources
|
|
//
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = MFEnumDeviceSources( pAttributes,
|
|
&m_ppSourceActivates,
|
|
(UINT32*)&m_dwActivates );
|
|
}
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
if ( pAttributes )
|
|
{
|
|
pAttributes->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//CTedApp
|
|
// Main application window controller
|
|
|
|
CTedApp::CTedApp()
|
|
: m_pPlayer(NULL)
|
|
, m_pVideoWindowHandler(NULL)
|
|
, m_pTopoEventHandler(NULL)
|
|
, m_pMediaEventHandler(NULL)
|
|
, m_pCPM(NULL)
|
|
, m_pPropertyController(NULL)
|
|
, m_pDock(NULL)
|
|
, m_pSplitter(NULL)
|
|
, m_pMainToolbar(NULL)
|
|
, m_fMergeRequired(false)
|
|
, m_fResolved(false)
|
|
, m_fPendingPlay(false)
|
|
, m_fStopTrackingUntilSessionStarted(false)
|
|
, m_pPendingTopo(NULL)
|
|
, m_pTopoView(NULL)
|
|
, m_fCanSeek(false)
|
|
{
|
|
CoInitializeEx( NULL, COINIT_MULTITHREADED );
|
|
|
|
if(FAILED(MFStartup( MF_VERSION )))
|
|
{
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
CTedApp::~CTedApp()
|
|
{
|
|
if(m_pTopoView)
|
|
{
|
|
m_pTopoView->CloseTopoWindow();
|
|
m_pTopoView->Release();
|
|
}
|
|
|
|
if(m_pVideoWindowHandler) m_pVideoWindowHandler->Release();
|
|
if(m_pTopoEventHandler) m_pTopoEventHandler->Release();
|
|
if(m_pPropertyController) m_pPropertyController->Release();
|
|
if(m_pCPM) m_pCPM->Release();
|
|
|
|
|
|
delete m_pMainToolbar;
|
|
delete m_pDock;
|
|
delete m_pSplitter;
|
|
delete m_pPlayer;
|
|
delete m_pPropSplitter;
|
|
delete m_pMediaEventHandler;
|
|
|
|
if(m_pPendingTopo) m_pPendingTopo->Release();
|
|
|
|
MFShutdown();
|
|
CoUninitialize();
|
|
}
|
|
|
|
HRESULT CTedApp::Init(LPCWSTR lpCmdLine)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// create window
|
|
m_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDC_TRV));
|
|
if(m_hMenu == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(Create(NULL, NULL, LoadAtlString(IDS_WDW_NAME), WS_OVERLAPPEDWINDOW, 0, m_hMenu, NULL) == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(lpCmdLine && lpCmdLine[0] != 0)
|
|
{
|
|
LoadFile(lpCmdLine);
|
|
}
|
|
|
|
Cleanup:
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_APP_INIT), hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CTedApp::HandleMMError(const CAtlStringW& message, HRESULT errResult)
|
|
{
|
|
m_MFErrorHandler.HandleMFError(message, errResult);
|
|
}
|
|
|
|
void CTedApp::NotifySplitterMoved()
|
|
{
|
|
// No processing currently needed after splitter movement
|
|
}
|
|
|
|
void CTedApp::NotifyTopoChange()
|
|
{
|
|
m_pMainToolbar->MarkResolved(false);
|
|
m_fResolved = false;
|
|
}
|
|
|
|
void CTedApp::HandleSeekerScroll(WORD wPos)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(m_pPlayer && m_pPlayer->IsPlaying() && m_fCanSeek)
|
|
{
|
|
MFTIME duration;
|
|
IFC( m_pPlayer->GetDuration(duration) );
|
|
|
|
MFTIME seekTime = (wPos * duration) / m_nSeekerRange;
|
|
IFC( m_pPlayer->PlayFrom(seekTime) );
|
|
|
|
m_fStopTrackingUntilSessionStarted = true;
|
|
}
|
|
|
|
Cleanup:
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_PLAY_MEDIA), hr);
|
|
}
|
|
}
|
|
|
|
void CTedApp::HandleRateScroll(WORD wPos)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(m_pPlayer && m_pPlayer->IsTopologySet())
|
|
{
|
|
float flRate = wPos / 10.0f;
|
|
|
|
if(flRate != 0)
|
|
{
|
|
hr = m_pPlayer->SetRate(flRate);
|
|
}
|
|
|
|
m_pMainToolbar->UpdateRateDisplay(flRate);
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_PLAY_RATE), hr);
|
|
}
|
|
}
|
|
|
|
LRESULT CTedApp::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
RECT rect;
|
|
RECT toolRect;
|
|
|
|
m_pMediaEventHandler = new CTedAppMediaEventHandler(this);
|
|
CHECK_ALLOC( m_pMediaEventHandler );
|
|
|
|
// create toolbar
|
|
m_pMainToolbar = new CTedMainToolbar();
|
|
CHECK_ALLOC( m_pMainToolbar );
|
|
IFC( m_pMainToolbar->Init(m_hWnd, MAIN_TOOLBAR_ID) );
|
|
m_pMainToolbar->SetTrackbarScrollCallback(&HandleSeekerScrollFunc);
|
|
m_pMainToolbar->GetRateBar()->SetScrollCallback(&HandleRateScrollFunc);
|
|
m_pMainToolbar->ShowRateBar(SW_HIDE);
|
|
|
|
m_pMainToolbar->GetClientRect(&toolRect);
|
|
GetClientRect(&rect);
|
|
rect.top = toolRect.bottom;
|
|
rect.bottom = rect.bottom - 100;
|
|
|
|
m_pDock = new CDock;
|
|
CHECK_ALLOC( m_pDock );
|
|
if(m_pDock->Create(m_hWnd, rect, LoadAtlString(IDS_DOCK), WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE) == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
ZeroMemory(&rect, sizeof(rect));
|
|
|
|
m_pSplitter = new CSplitterBar(m_pDock, false, m_hWnd);
|
|
CHECK_ALLOC( m_pSplitter );
|
|
if(m_pSplitter->Create(m_pDock->m_hWnd, &rect, LoadAtlString(IDS_SPLITTER)) == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
m_pPropSplitter = new CSplitterBar(m_pDock, true, m_hWnd);
|
|
CHECK_ALLOC( m_pPropSplitter );
|
|
if(m_pPropSplitter->Create(m_pDock->m_hWnd, &rect, LoadAtlString(IDS_SPLITTER), WS_CHILD | WS_CLIPSIBLINGS) == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
rect.top += 5;
|
|
CPropertyEditWindow* pPropView = new CPropertyEditWindow();
|
|
CHECK_ALLOC( pPropView );
|
|
if(pPropView->Create(m_pDock->m_hWnd, rect, LoadAtlString(IDS_PROP_VIEW), WS_CHILD | WS_BORDER | WS_VISIBLE) == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
m_pCPM = new CTedContentProtectionManager(this);
|
|
CHECK_ALLOC( m_pCPM );
|
|
m_pCPM->AddRef();
|
|
|
|
m_pPlayer = new CTedPlayer(m_pMediaEventHandler, m_pCPM);
|
|
CHECK_ALLOC( m_pPlayer );
|
|
|
|
m_pVideoWindowHandler = new CTedAppVideoWindowHandler(m_hWnd);
|
|
CHECK_ALLOC( m_pVideoWindowHandler );
|
|
m_pVideoWindowHandler->AddRef();
|
|
|
|
m_pTopoEventHandler = new CTedAppTopoEventHandler(this);
|
|
CHECK_ALLOC( m_pTopoEventHandler );
|
|
m_pTopoEventHandler->AddRef();
|
|
|
|
m_pPropertyController = new CPropertyController(pPropView);
|
|
CHECK_ALLOC( m_pPropertyController );
|
|
m_pPropertyController->AddRef();
|
|
|
|
IFC( TEDCreateTopoViewer(m_pVideoWindowHandler, m_pPropertyController, m_pTopoEventHandler, &m_pTopoView) );
|
|
IFC( m_pTopoView->CreateTopoWindow(LoadAtlString(IDS_WDW_TOPOVIEW), WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, (LONG_PTR) m_pDock->m_hWnd, (LONG_PTR*) &m_hEditWnd) );
|
|
|
|
m_EditWindow.Attach(m_hEditWnd);
|
|
|
|
RebuildDockWithOneView();
|
|
|
|
m_MFErrorHandler.SetParentWnd(m_hWnd);
|
|
|
|
HICON hIcon = ::LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_TRV));
|
|
SetIcon(hIcon, TRUE);
|
|
SetIcon(hIcon, FALSE);
|
|
|
|
EnableInput(ID_PLAY_PLAY, TRUE);
|
|
|
|
Cleanup:
|
|
|
|
return (LRESULT) hr;
|
|
}
|
|
|
|
LRESULT CTedApp::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnMediaCapabilitiesChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
DWORD dwCaps;
|
|
m_pPlayer->GetCapabilities(&dwCaps);
|
|
|
|
if(dwCaps & MFSESSIONCAP_SEEK)
|
|
{
|
|
m_fCanSeek = true;
|
|
}
|
|
else
|
|
{
|
|
m_fCanSeek = false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
m_pMainToolbar->SetWindowPos(NULL, 0, 0, LOWORD(lParam), 30,
|
|
SWP_NOZORDER | SWP_NOREDRAW);
|
|
|
|
m_pDock->SetWindowPos(NULL, 0, 30, LOWORD(lParam), HIWORD(lParam) - 30,
|
|
SWP_NOZORDER | SWP_NOREDRAW);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnSessionPlay(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = (HRESULT) wParam;
|
|
|
|
KillTimer(ms_nTimerID);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
SetTimer(ms_nTimerID, ms_dwTimerLen, NULL);
|
|
}
|
|
|
|
m_fStopTrackingUntilSessionStarted = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnTopologySet(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
HRESULT hrTopologySet = (HRESULT) wParam;
|
|
HandleTopologySet(hrTopologySet);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnTopologyReady(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
HRESULT hr;
|
|
float flSlowest, flFastest;
|
|
hr = m_pPlayer->GetRateBounds(MFRATE_FORWARD, &flSlowest, &flFastest);
|
|
|
|
if(FAILED(hr) || flSlowest == 0.0f && flFastest == 0.0f)
|
|
{
|
|
m_pMainToolbar->ShowRateBar(SW_HIDE);
|
|
}
|
|
else
|
|
{
|
|
m_pMainToolbar->ShowRateBar(SW_SHOW);
|
|
m_pMainToolbar->GetRateBar()->SetRange(DWORD(flSlowest * 10), DWORD(flFastest * 10));
|
|
m_pMainToolbar->GetRateBar()->SetPos(10);
|
|
|
|
m_pMainToolbar->GetRateBar()->SendMessage(TBM_CLEARTICS, 0, 0);
|
|
|
|
for(DWORD dwTicPos = 10; dwTicPos < flFastest * 10; dwTicPos += 10)
|
|
{
|
|
m_pMainToolbar->GetRateBar()->SendMessage(TBM_SETTIC, 0, dwTicPos);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnSessionEnded(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
m_pVideoWindowHandler->ShowWindows(SW_HIDE);
|
|
|
|
EnableInput(ID_PLAY_PLAY, TRUE);
|
|
EnableInput(ID_PLAY_STOP, FALSE);
|
|
EnableInput(ID_PLAY_PAUSE, FALSE);
|
|
|
|
MFTIME duration;
|
|
m_pPlayer->GetDuration(duration);
|
|
|
|
m_pMainToolbar->UpdateTimeDisplay(0, duration);
|
|
|
|
KillTimer(ms_nTimerID);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnSplitterMoved(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
NotifySplitterMoved();
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
if(wParam == ms_nTimerID)
|
|
{
|
|
if(m_pPlayer->IsPlaying())
|
|
{
|
|
MFTIME time, duration;
|
|
HRESULT hr = m_pPlayer->GetTime(&time);
|
|
HRESULT hr2 = m_pPlayer->GetDuration(duration);
|
|
|
|
if(SUCCEEDED(hr) && SUCCEEDED(hr2) && !m_fStopTrackingUntilSessionStarted)
|
|
{
|
|
m_pMainToolbar->UpdateTimeDisplay(time, duration);
|
|
}
|
|
}
|
|
}
|
|
|
|
SetTimer(ms_nTimerID, ms_dwTimerLen, NULL);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnUntrustedComponent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
MessageBox(LoadAtlString(IDS_E_UNTRUSTED_COMPONENTS), NULL, MB_OK);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnProtectedContent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = m_pCPM->ManualEnableContent();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
m_MFErrorHandler.HandleMFError(LoadAtlString(IDS_E_MANUAL_LICENSE), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnIndividualization(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = m_pCPM->Individualize();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
m_MFErrorHandler.HandleMFError(LoadAtlString(IDS_E_PROT_CONTENT_PLAYBACK), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CTedApp::HandleTopologySet(HRESULT hrTopologySet)
|
|
{
|
|
assert(m_pPlayer != NULL);
|
|
|
|
CComPtr<IMFTopology> spFullTopo;
|
|
CAtlStringW strTime;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if(FAILED(hrTopologySet))
|
|
{
|
|
// We failed to set the topology; merge the old topology
|
|
m_pTopoView->MergeTopology(m_pPendingTopo);
|
|
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_RESOLUTION), hrTopologySet);
|
|
m_fPendingPlay = false;
|
|
return;
|
|
}
|
|
|
|
if(m_fMergeRequired)
|
|
{
|
|
hr = m_pPlayer->GetFullTopology(&spFullTopo);
|
|
|
|
if(spFullTopo != NULL)
|
|
{
|
|
TOPOID TopoID = 0;
|
|
spFullTopo->GetTopologyID(&TopoID);
|
|
|
|
// Ensure this is the topology that was most recently set on the player
|
|
if(TopoID == m_PendingTopoID)
|
|
{
|
|
m_fMergeRequired = false;
|
|
hr = m_pTopoView->MergeTopology(spFullTopo);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_MERGE), hr);
|
|
}
|
|
else
|
|
{
|
|
m_pMainToolbar->MarkResolved(true);
|
|
m_fResolved = true;
|
|
|
|
if(m_fPendingPlay)
|
|
{
|
|
hr = Play();
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_PLAY), hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_RETRIEVE), hr);
|
|
}
|
|
}
|
|
|
|
MFTIME duration = 0;
|
|
m_pPlayer->GetDuration(duration);
|
|
|
|
m_pMainToolbar->UpdateTimeDisplay(0, duration);
|
|
m_fPendingPlay = false;
|
|
}
|
|
|
|
LRESULT CTedApp::OnLoad(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
CAtlString strFilter = LoadAtlString(IDS_FILE_XML);
|
|
CAtlString strTitle = LoadAtlString(IDS_FILE_LOAD);
|
|
strFilter.SetAt(strFilter.GetLength()-1,0); // force double-null termination
|
|
strFilter.SetAt(strFilter.GetLength()-2,0);
|
|
|
|
TCHAR fileBuffer[m_dwMaxAcceptedFileNameLength];
|
|
fileBuffer[0] = 0;
|
|
|
|
OPENFILENAME openFileInfo;
|
|
openFileInfo.lStructSize = sizeof(OPENFILENAME);
|
|
openFileInfo.hwndOwner = m_hWnd;
|
|
openFileInfo.hInstance = 0;
|
|
openFileInfo.lpstrFilter = strFilter;
|
|
openFileInfo.lpstrCustomFilter = NULL;
|
|
openFileInfo.nFilterIndex = 1;
|
|
openFileInfo.lpstrFile = fileBuffer;
|
|
openFileInfo.nMaxFile = m_dwMaxAcceptedFileNameLength;
|
|
openFileInfo.lpstrFileTitle = NULL;
|
|
openFileInfo.nMaxFileTitle = 0;
|
|
openFileInfo.lpstrInitialDir = NULL;
|
|
openFileInfo.lpstrTitle = strTitle;
|
|
openFileInfo.Flags = 0;
|
|
openFileInfo.nFileOffset = 0;
|
|
openFileInfo.nFileExtension = 0;
|
|
openFileInfo.lpstrDefExt = NULL;
|
|
openFileInfo.lCustData = NULL;
|
|
openFileInfo.pvReserved = NULL;
|
|
openFileInfo.dwReserved = 0;
|
|
openFileInfo.FlagsEx = 0;
|
|
|
|
if(GetOpenFileName(&openFileInfo))
|
|
{
|
|
LoadFile(openFileInfo.lpstrFile);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnSave(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
CAtlString strFilter = LoadAtlString(IDS_FILE_XML);
|
|
CAtlString strTitle = LoadAtlString(IDS_FILE_SAVE);
|
|
strFilter.SetAt(strFilter.GetLength()-1,0); // force double-null termination
|
|
strFilter.SetAt(strFilter.GetLength()-2,0);
|
|
|
|
TCHAR fileBuffer[m_dwMaxAcceptedFileNameLength];
|
|
fileBuffer[0] = 0;
|
|
|
|
OPENFILENAME openFileInfo;
|
|
openFileInfo.lStructSize = sizeof(OPENFILENAME);
|
|
openFileInfo.hwndOwner = m_hWnd;
|
|
openFileInfo.hInstance = 0;
|
|
openFileInfo.lpstrFilter = strFilter;
|
|
openFileInfo.lpstrCustomFilter = NULL;
|
|
openFileInfo.nFilterIndex = 1;
|
|
openFileInfo.lpstrFile = fileBuffer;
|
|
openFileInfo.nMaxFile = m_dwMaxAcceptedFileNameLength;
|
|
openFileInfo.lpstrFileTitle = NULL;
|
|
openFileInfo.nMaxFileTitle = 0;
|
|
openFileInfo.lpstrInitialDir = NULL;
|
|
openFileInfo.lpstrTitle = strTitle;
|
|
openFileInfo.Flags = 0;
|
|
openFileInfo.nFileOffset = 0;
|
|
openFileInfo.nFileExtension = 0;
|
|
openFileInfo.lpstrDefExt = L"XML";
|
|
openFileInfo.lCustData = NULL;
|
|
openFileInfo.pvReserved = NULL;
|
|
openFileInfo.dwReserved = 0;
|
|
openFileInfo.FlagsEx = 0;
|
|
|
|
if(GetSaveFileName(&openFileInfo))
|
|
{
|
|
HRESULT hr = m_pTopoView->SaveTopology(openFileInfo.lpstrFile);
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_FILE_SAVE), hr);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnDelete(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
m_pTopoView->DeleteSelectedNode();
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnNewTopology(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
BOOL fIsSaved = FALSE;
|
|
m_pTopoView->IsSaved(&fIsSaved);
|
|
|
|
if(!fIsSaved)
|
|
{
|
|
int iMBResult = MessageBox(LoadAtlString(IDS_TOPO_NOT_SAVED), LoadAtlString(IDS_TOPO_NEW), MB_YESNO);
|
|
|
|
if(iMBResult == IDNO) return 0;
|
|
}
|
|
|
|
m_pTopoView->NewTopology();
|
|
|
|
ResetInterface();
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddSource(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
CAtlString strFilter = LoadAtlString(IDS_FILE_MEDIA);
|
|
CAtlString strTitle = LoadAtlString(IDS_FILE_SELECT);
|
|
strFilter.SetAt(strFilter.GetLength()-1,0); // force double-null termination
|
|
strFilter.SetAt(strFilter.GetLength()-2,0);
|
|
|
|
TCHAR fileBuffer[m_dwMaxAcceptedFileNameLength];
|
|
fileBuffer[0] = 0;
|
|
|
|
OPENFILENAME openFileInfo;
|
|
openFileInfo.lStructSize = sizeof(OPENFILENAME);
|
|
openFileInfo.hwndOwner = m_hWnd;
|
|
openFileInfo.hInstance = 0;
|
|
openFileInfo.lpstrFilter = strFilter;
|
|
openFileInfo.lpstrCustomFilter = NULL;
|
|
openFileInfo.nFilterIndex = 1;
|
|
openFileInfo.lpstrFile = fileBuffer;
|
|
openFileInfo.nMaxFile = m_dwMaxAcceptedFileNameLength;
|
|
openFileInfo.lpstrFileTitle = NULL;
|
|
openFileInfo.nMaxFileTitle = 0;
|
|
openFileInfo.lpstrInitialDir = NULL;
|
|
openFileInfo.lpstrTitle = strTitle;
|
|
openFileInfo.Flags = OFN_FILEMUSTEXIST;
|
|
openFileInfo.nFileOffset = 0;
|
|
openFileInfo.nFileExtension = 0;
|
|
openFileInfo.lpstrDefExt = NULL;
|
|
openFileInfo.lCustData = NULL;
|
|
openFileInfo.pvReserved = NULL;
|
|
openFileInfo.dwReserved = 0;
|
|
openFileInfo.FlagsEx = 0;
|
|
|
|
if(GetOpenFileName(&openFileInfo))
|
|
{
|
|
HRESULT hr = m_pTopoView->AddSource(openFileInfo.lpstrFile);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_SOURCE_CREATE), hr);
|
|
}
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddSink(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {
|
|
// For future use
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddSAR(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = m_pTopoView->AddSAR();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_AUDIO_RENDERER_CREATE), hr);
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddEVR(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = m_pTopoView->AddEVR();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_VIDEO_RENDERER_CREATE), hr);
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddTransform(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CTedTransformDialog transformDialog;
|
|
|
|
if(transformDialog.DoModal() == IDOK)
|
|
{
|
|
hr = m_pTopoView->AddTransformActivate(transformDialog.GetChosenActivate());
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TRANSFORM_CREATE), hr);
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddTee(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = m_pTopoView->AddTee();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TEE_CREATE), hr);
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddCustomMFT(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
CTedInputGuidDialog dialog;
|
|
HRESULT hr = S_OK;
|
|
|
|
if(dialog.DoModal() == IDOK)
|
|
{
|
|
GUID gidTransID = dialog.GetInputGuid();
|
|
hr = m_pTopoView->AddTransform(gidTransID, LoadAtlString(IDS_MFT_CUSTOM));
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TRANSFORM_CREATE), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddCustomSink(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
CTedInputGuidDialog dialog;
|
|
HRESULT hr = S_OK;
|
|
|
|
if(dialog.DoModal() == IDOK)
|
|
{
|
|
GUID gidSinkID = dialog.GetInputGuid();
|
|
hr = m_pTopoView->AddCustomSink(gidSinkID);
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_SINK_CREATE), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddVideoCaptureSource(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMFMediaSource* pSource = NULL;
|
|
CTedCaptureSourceDialog dialog( true );
|
|
|
|
if ( dialog.DoModal() == IDOK )
|
|
{
|
|
IMFActivate* pActivate = dialog.GetSourceActivate();
|
|
if ( pActivate )
|
|
{
|
|
hr = pActivate->ActivateObject( IID_IMFMediaSource, (void**)&pSource );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = m_pTopoView->AddCaptureSource( pSource );
|
|
}
|
|
}
|
|
|
|
if ( pActivate )
|
|
{
|
|
pActivate->Release();
|
|
}
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_VIDEO_CAP_SOURCE_CREATE), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnAddAudioCaptureSource(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IMFMediaSource* pSource = NULL;
|
|
CTedCaptureSourceDialog dialog( false );
|
|
|
|
if ( dialog.DoModal() == IDOK )
|
|
{
|
|
IMFActivate* pActivate = dialog.GetSourceActivate();
|
|
if ( pActivate )
|
|
{
|
|
hr = pActivate->ActivateObject( IID_IMFMediaSource, (void**)&pSource );
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = m_pTopoView->AddCaptureSource( pSource );
|
|
}
|
|
}
|
|
|
|
if ( pActivate )
|
|
{
|
|
pActivate->Release();
|
|
}
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_AUDIO_CAP_SOURCE_CREATE), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnLoadTopology(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = ResolveTopologyFromEditor();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_RESOLUTION), hr);
|
|
}
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnActionPlay(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!m_fResolved)
|
|
{
|
|
m_fPendingPlay = true;
|
|
hr = ResolveTopologyFromEditor();
|
|
if(FAILED(hr))
|
|
{
|
|
m_fPendingPlay = false;
|
|
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_RESOLUTION), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
hr = Play();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_PLAY), hr);
|
|
}
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnActionStop(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr;
|
|
|
|
IFC(m_pPlayer->Stop());
|
|
|
|
m_pVideoWindowHandler->ShowWindows(SW_HIDE);
|
|
|
|
EnableInput(ID_PLAY_PLAY, TRUE);
|
|
EnableInput(ID_PLAY_STOP, FALSE);
|
|
EnableInput(ID_PLAY_PAUSE, FALSE);
|
|
|
|
MFTIME duration;
|
|
m_pPlayer->GetDuration(duration);
|
|
|
|
m_pMainToolbar->UpdateTimeDisplay(0, duration);
|
|
|
|
KillTimer(ms_nTimerID);
|
|
|
|
Cleanup:
|
|
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnActionPause(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {
|
|
HRESULT hr;
|
|
|
|
IFC( m_pPlayer->Pause() );
|
|
|
|
EnableInput(ID_PLAY_PLAY, TRUE);
|
|
EnableInput(ID_PLAY_STOP, TRUE);
|
|
EnableInput(ID_PLAY_PAUSE, FALSE);
|
|
|
|
Cleanup:
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnSpy(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = m_pTopoView->SpySelectedNode();
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
m_MFErrorHandler.HandleMFError(LoadAtlString(IDS_E_NODE_SPY), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnCustomTopoloader(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
CTedInputGuidDialog dialog;
|
|
HRESULT hr = S_OK;
|
|
|
|
if(dialog.DoModal() == IDOK && dialog.IsValidGuid())
|
|
{
|
|
CComPtr<IMFTopoLoader> spTopoLoader;
|
|
GUID gidTopoloader = dialog.GetInputGuid();
|
|
|
|
// Test creation of a topoloader with this CLSID to ensure it is valid, rather than
|
|
// fail when creating the session in a seemingly unrelated error.
|
|
hr = CoCreateInstance(gidTopoloader, NULL, CLSCTX_INPROC_SERVER, IID_IMFTopoLoader, (void **)&spTopoLoader);
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TOPOLOADER_CREATE), hr);
|
|
}
|
|
else
|
|
{
|
|
m_pPlayer->SetCustomTopoloader(gidTopoloader);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnExit(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
SendMessage(WM_CLOSE, 0, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnHelpHelp(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HINSTANCE hReturned = ShellExecute(NULL, L"open", L"http://go.microsoft.com/fwlink/?LinkId=92748", NULL, NULL, SW_SHOW);
|
|
|
|
if(hReturned <= HINSTANCE(32))
|
|
{
|
|
MessageBox(LoadAtlString(IDS_E_URL_OPEN), LoadAtlString(IDS_ERROR), MB_OK);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnHelpAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
CTedAboutDialog dialog;
|
|
dialog.DoModal();
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnRenderFile(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CAtlString strFilter = LoadAtlString(IDS_FILE_MEDIA);
|
|
CAtlString strTitle = LoadAtlString(IDS_FILE_SELECT);
|
|
strFilter.SetAt(strFilter.GetLength()-1,0); // force double-null termination
|
|
strFilter.SetAt(strFilter.GetLength()-2,0);
|
|
|
|
TCHAR fileBuffer[m_dwMaxAcceptedFileNameLength];
|
|
fileBuffer[0] = 0;
|
|
|
|
OPENFILENAME openFileInfo;
|
|
openFileInfo.lStructSize = sizeof(OPENFILENAME);
|
|
openFileInfo.hwndOwner = m_hWnd;
|
|
openFileInfo.hInstance = 0;
|
|
openFileInfo.lpstrFilter = strFilter;
|
|
openFileInfo.lpstrCustomFilter = NULL;
|
|
openFileInfo.nFilterIndex = 1;
|
|
openFileInfo.lpstrFile = fileBuffer;
|
|
openFileInfo.nMaxFile = m_dwMaxAcceptedFileNameLength;
|
|
openFileInfo.lpstrFileTitle = NULL;
|
|
openFileInfo.nMaxFileTitle = 0;
|
|
openFileInfo.lpstrInitialDir = NULL;
|
|
openFileInfo.lpstrTitle = strTitle;
|
|
openFileInfo.Flags = OFN_FILEMUSTEXIST;
|
|
openFileInfo.nFileOffset = 0;
|
|
openFileInfo.nFileExtension = 0;
|
|
openFileInfo.lpstrDefExt = NULL;
|
|
openFileInfo.lCustData = NULL;
|
|
openFileInfo.pvReserved = NULL;
|
|
openFileInfo.dwReserved = 0;
|
|
openFileInfo.FlagsEx = 0;
|
|
|
|
if(GetOpenFileName(&openFileInfo))
|
|
{
|
|
CComPtr<IMFTopology> spTopology;
|
|
CComPtr<IMFTopology> spTedTopo;
|
|
|
|
HRESULT hrConstructor;
|
|
CTedMediaFileRenderer TedMediaFileRenderer(openFileInfo.lpstrFile, m_pVideoWindowHandler, hrConstructor);
|
|
IFC( hrConstructor );
|
|
|
|
IFC( TedMediaFileRenderer.Load(&spTopology) );
|
|
IFC( m_pTopoView->ShowTopology(spTopology, openFileInfo.lpstrFile) );
|
|
|
|
ResetInterface();
|
|
|
|
BOOL fIsProtected;
|
|
IFC( m_pTopoView->GetTopology(&spTedTopo, &fIsProtected) );
|
|
IFC( SetTopologyOnPlayer(spTedTopo, fIsProtected, FALSE) );
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32( CommDlgExtendedError() );
|
|
}
|
|
|
|
Cleanup:
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_MEDIA_RENDER), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnRenderURL(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CTedInputURLDialog dialog;
|
|
|
|
if(dialog.DoModal() == IDOK)
|
|
{
|
|
CComPtr<IMFTopology> spTopology;
|
|
CComPtr<IMFTopology> spTedTopo;
|
|
|
|
HRESULT hrConstructor;
|
|
CTedMediaFileRenderer TedMediaFileRenderer(dialog.GetURL(), m_pVideoWindowHandler, hrConstructor);
|
|
IFC( hrConstructor );
|
|
|
|
IFC( TedMediaFileRenderer.Load(&spTopology) );
|
|
IFC( m_pTopoView->ShowTopology(spTopology, dialog.GetURL()) );
|
|
|
|
ResetInterface();
|
|
|
|
BOOL fIsProtected;
|
|
IFC( m_pTopoView->GetTopology(&spTedTopo, &fIsProtected) );
|
|
IFC( SetTopologyOnPlayer(spTedTopo, fIsProtected, FALSE) );
|
|
}
|
|
|
|
Cleanup:
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_MEDIA_RENDER), hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTedApp::OnRenderTranscode(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IMFTopology> spTopology;
|
|
CComPtr<IMFTopology> spTedTopo;
|
|
TCHAR fileBuffer[m_dwMaxAcceptedFileNameLength];
|
|
fileBuffer[0] = 0;
|
|
|
|
OPENFILENAME openFileInfo;
|
|
ZeroMemory(&openFileInfo, sizeof(OPENFILENAME));
|
|
openFileInfo.lStructSize = sizeof(OPENFILENAME);
|
|
openFileInfo.hwndOwner = m_hWnd;
|
|
openFileInfo.hInstance = 0;
|
|
openFileInfo.lpstrFilter = L"Media Files\0*.*\0";
|
|
openFileInfo.lpstrCustomFilter = NULL;
|
|
openFileInfo.nFilterIndex = 1;
|
|
openFileInfo.lpstrFile = fileBuffer;
|
|
openFileInfo.nMaxFile = m_dwMaxAcceptedFileNameLength;
|
|
openFileInfo.lpstrFileTitle = NULL;
|
|
openFileInfo.nMaxFileTitle = 0;
|
|
openFileInfo.lpstrInitialDir = NULL;
|
|
openFileInfo.lpstrTitle = L"Select Media Source";
|
|
openFileInfo.Flags = OFN_FILEMUSTEXIST;
|
|
openFileInfo.nFileOffset = 0;
|
|
openFileInfo.nFileExtension = 0;
|
|
openFileInfo.lpstrDefExt = NULL;
|
|
openFileInfo.lCustData = NULL;
|
|
openFileInfo.pvReserved = NULL;
|
|
openFileInfo.dwReserved = 0;
|
|
openFileInfo.FlagsEx = 0;
|
|
|
|
if(GetOpenFileName(&openFileInfo))
|
|
{
|
|
CTedChooserDialog ChooserDialog(L"Choose Transcode Profile");
|
|
|
|
CTedTranscodeTopologyBuilder Builder(openFileInfo.lpstrFile, &hr);
|
|
IFC( hr );
|
|
|
|
size_t cProfiles = Builder.GetProfileCount();
|
|
for(size_t i = 0; i < cProfiles; i++)
|
|
{
|
|
ChooserDialog.AddPossibleChoice(Builder.GetProfileName(i));
|
|
}
|
|
|
|
if(ChooserDialog.DoModal() == IDOK)
|
|
{
|
|
TCHAR fileBuffer2[m_dwMaxAcceptedFileNameLength];
|
|
fileBuffer2[0] = 0;
|
|
|
|
OPENFILENAME targetFileInfo;
|
|
targetFileInfo.lStructSize = sizeof(OPENFILENAME);
|
|
targetFileInfo.hwndOwner = m_hWnd;
|
|
targetFileInfo.hInstance = 0;
|
|
targetFileInfo.lpstrFilter = L"Media Files\0*.*\0";
|
|
targetFileInfo.lpstrCustomFilter = NULL;
|
|
targetFileInfo.nFilterIndex = 1;
|
|
targetFileInfo.lpstrFile = fileBuffer2;
|
|
targetFileInfo.nMaxFile = m_dwMaxAcceptedFileNameLength;
|
|
targetFileInfo.lpstrFileTitle = NULL;
|
|
targetFileInfo.nMaxFileTitle = 0;
|
|
targetFileInfo.lpstrInitialDir = NULL;
|
|
targetFileInfo.lpstrTitle = L"Choose target file";
|
|
targetFileInfo.Flags = OFN_OVERWRITEPROMPT;
|
|
targetFileInfo.nFileOffset = 0;
|
|
targetFileInfo.nFileExtension = 0;
|
|
targetFileInfo.lpstrDefExt = NULL;
|
|
targetFileInfo.lCustData = NULL;
|
|
targetFileInfo.pvReserved = NULL;
|
|
targetFileInfo.dwReserved = 0;
|
|
targetFileInfo.FlagsEx = 0;
|
|
|
|
if(GetSaveFileName(&targetFileInfo))
|
|
{
|
|
IFC( Builder.BuildTranscodeTopology(ChooserDialog.GetChoice(), targetFileInfo.lpstrFile, &spTopology) );
|
|
|
|
IFC( m_pTopoView->ShowTopology(spTopology, openFileInfo.lpstrFile) );
|
|
|
|
ResetInterface();
|
|
|
|
BOOL fIsProtected;
|
|
IFC( m_pTopoView->GetTopology(&spTedTopo, &fIsProtected) );
|
|
IFC( SetTopologyOnPlayer(spTedTopo, fIsProtected, TRUE) );
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32( CommDlgExtendedError() );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
Cleanup:
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(L"Error rendering transcode topology", hr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CTedApp::EnableInput(UINT item, BOOL enabled)
|
|
{
|
|
m_pMainToolbar->EnableButtonByCommand(item, enabled);
|
|
if(enabled)
|
|
{
|
|
EnableMenuItem(m_hMenu, item, MF_ENABLED);
|
|
}
|
|
else
|
|
{
|
|
EnableMenuItem(m_hMenu, item, MF_GRAYED);
|
|
}
|
|
}
|
|
|
|
void CTedApp::RebuildDockWithOneView()
|
|
{
|
|
m_pDock->RemoveAllAreas();
|
|
|
|
CDock::CArea* pEditArea = m_pDock->AddArea(CDock::MOVE_NO);
|
|
CDock::CArea* pPropertiesArea = m_pDock->AddArea(CDock::MOVE_NO);
|
|
CDock::CArea* pVerticalSplit = m_pDock->AddArea(CDock::MOVE_VERTICAL);
|
|
|
|
// Create the splitter between the properties view and the edit view
|
|
pVerticalSplit->m_Attach.pTop = m_pDock->GetStockArea(CDock::STOCK_AREA_TOP);
|
|
pVerticalSplit->m_Attach.pBottom = m_pDock->GetStockArea(CDock::STOCK_AREA_BOTTOM);
|
|
pVerticalSplit->m_pWindow = m_pPropSplitter;
|
|
|
|
pVerticalSplit->m_posFixed.left = m_dblInitialSplitterPos;
|
|
pVerticalSplit->m_posFixed.width = m_dwSplitterWidth;
|
|
|
|
// Create the edit view
|
|
pEditArea->m_Attach.pLeft = m_pDock->GetStockArea(CDock::STOCK_AREA_LEFT);
|
|
pEditArea->m_Attach.pRight = pVerticalSplit;
|
|
pEditArea->m_Attach.pTop = m_pDock->GetStockArea(CDock::STOCK_AREA_TOP);
|
|
pEditArea->m_Attach.pBottom = m_pDock->GetStockArea(CDock::STOCK_AREA_BOTTOM);
|
|
pEditArea->m_pWindow = &m_EditWindow; //m_pEditorView;
|
|
|
|
// Create the properties view
|
|
pPropertiesArea->m_Attach.pLeft = pVerticalSplit;
|
|
pPropertiesArea->m_Attach.pRight = m_pDock->GetStockArea(CDock::STOCK_AREA_RIGHT);
|
|
pPropertiesArea->m_Attach.pTop = m_pDock->GetStockArea(CDock::STOCK_AREA_TOP);
|
|
pPropertiesArea->m_Attach.pBottom = m_pDock->GetStockArea(CDock::STOCK_AREA_BOTTOM);
|
|
pPropertiesArea->m_pWindow = m_pPropertyController->GetWindow();
|
|
|
|
m_pPropSplitter->ShowWindow(SW_SHOW);
|
|
m_pPropertyController->GetWindow()->ShowWindow(SW_SHOW);
|
|
m_pSplitter->ShowWindow(SW_HIDE);
|
|
|
|
m_pDock->UpdateDock();
|
|
}
|
|
|
|
void CTedApp::DisablePlayback()
|
|
{
|
|
EnableInput(ID_PLAY_PLAY, FALSE);
|
|
EnableInput(ID_PLAY_STOP, FALSE);
|
|
EnableInput(ID_PLAY_PAUSE, FALSE);
|
|
}
|
|
|
|
HRESULT CTedApp::HasBuggedPins(IMFTopology* pTopology, bool* fBuggedPins)
|
|
{
|
|
HRESULT hr;
|
|
*fBuggedPins = false;
|
|
WORD cNodes;
|
|
IFC( pTopology->GetNodeCount(&cNodes) );
|
|
for(WORD i = 0; i < cNodes && !(*fBuggedPins); i++)
|
|
{
|
|
CComPtr<IMFTopologyNode> spNode;
|
|
IFC( pTopology->GetNode(i, &spNode) );
|
|
|
|
DWORD cInputs;
|
|
IFC( spNode->GetInputCount(&cInputs) )
|
|
for(DWORD j = 0; j < cInputs; j++)
|
|
{
|
|
CComPtr<IMFTopologyNode> spUpNode;
|
|
DWORD dwUpIndex;
|
|
HRESULT hrPin = spNode->GetInput(j, &spUpNode, &dwUpIndex);
|
|
if(FAILED(hrPin))
|
|
{
|
|
*fBuggedPins = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!(*fBuggedPins))
|
|
{
|
|
DWORD cOutputs;
|
|
IFC( spNode->GetOutputCount(&cOutputs) );
|
|
for(DWORD j = 0; j < cOutputs; j++)
|
|
{
|
|
CComPtr<IMFTopologyNode> spDownNode;
|
|
DWORD dwDownIndex;
|
|
HRESULT hrPin = spNode->GetOutput(j, &spDownNode, &dwDownIndex);
|
|
if(FAILED(hrPin))
|
|
{
|
|
*fBuggedPins = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
void CTedApp::ResetInterface()
|
|
{
|
|
if(m_pPlayer && m_pPlayer->IsPlaying())
|
|
{
|
|
m_pPlayer->Stop();
|
|
}
|
|
|
|
m_pMainToolbar->UpdateTimeDisplay(0, 0);
|
|
m_pMainToolbar->ShowRateBar(SW_HIDE);
|
|
m_pMainToolbar->MarkResolved(false);
|
|
m_fResolved = false;
|
|
}
|
|
|
|
HRESULT CTedApp::ResolveTopologyFromEditor()
|
|
{
|
|
HRESULT hr;
|
|
BOOL fIsProtected;
|
|
|
|
CComPtr<IMFTopology> spTopo;
|
|
IFC( m_pTopoView->GetTopology(&spTopo, &fIsProtected) );
|
|
|
|
// WORKAROUND: Currently, disconnected pins are bugged in media foundation.
|
|
// The pin is disconnected, but the node will still have an input/output count of
|
|
// one. When trying to resolve a topology with a bugged pin like this, the
|
|
// topoloader will create a work item with a 'NULL' destination node.
|
|
// Executing this work item causes E_POINTER to be returned to the client.
|
|
// Since E_POINTER make little sense from the context of the UI, handle
|
|
// this issue here.
|
|
bool fHasBuggedPins;
|
|
IFC( HasBuggedPins(spTopo, &fHasBuggedPins) );
|
|
if(fHasBuggedPins)
|
|
{
|
|
MessageBox(LoadAtlString(IDS_E_TOPO_RESOLUTION_PINS), LoadAtlString(IDS_ERROR), MB_OK);
|
|
goto Cleanup;
|
|
}
|
|
|
|
IFC( SetTopologyOnPlayer(spTopo, fIsProtected, FALSE) );
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTedApp::SetTopologyOnPlayer(IMFTopology* pTopo, BOOL fIsProtected, BOOL fIsTranscode)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if(m_pPendingTopo) m_pPendingTopo->Release();
|
|
m_pPendingTopo = pTopo;
|
|
m_pPendingTopo->AddRef();
|
|
|
|
m_pPendingTopo->GetTopologyID(&m_PendingTopoID);
|
|
|
|
if(fIsProtected)
|
|
{
|
|
hr = m_pPlayer->InitProtected();
|
|
}
|
|
else
|
|
{
|
|
hr = m_pPlayer->InitClear();
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = m_pPlayer->SetTopology(pTopo, fIsTranscode);
|
|
if(FAILED(hr))
|
|
{
|
|
if(hr == MF_E_NOT_FOUND)
|
|
{
|
|
MessageBox(LoadAtlString(IDS_E_TOPO_RESOLUTION_NO_SOURCE), LoadAtlString(IDS_ERROR), MB_OK);
|
|
hr = S_OK;
|
|
m_fPendingPlay = false;
|
|
}
|
|
|
|
goto Cleanup;
|
|
}
|
|
m_fMergeRequired = true;
|
|
}
|
|
else
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_TOPO_RESOLUTION_INIT), hr);
|
|
hr = S_OK;
|
|
}
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTedApp::Play()
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_pVideoWindowHandler->ShowWindows(SW_SHOW);
|
|
|
|
if(m_fCanSeek)
|
|
{
|
|
MFTIME duration;
|
|
WORD wPos = m_pMainToolbar->GetSeekBar()->GetPos();
|
|
|
|
IFC( m_pPlayer->GetDuration(duration) );
|
|
MFTIME seekTime = (wPos * duration) / m_nSeekerRange;
|
|
IFC( m_pPlayer->PlayFrom(seekTime) );
|
|
}
|
|
else
|
|
{
|
|
IFC( m_pPlayer->Start() );
|
|
}
|
|
|
|
EnableInput(ID_PLAY_PLAY, FALSE);
|
|
EnableInput(ID_PLAY_STOP, TRUE);
|
|
EnableInput(ID_PLAY_PAUSE, TRUE);
|
|
|
|
SetTimer(ms_nTimerID, ms_dwTimerLen, NULL);
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
void CTedApp::LoadFile(LPCWSTR szFile)
|
|
{
|
|
HRESULT hr = m_pTopoView->LoadTopology(szFile);
|
|
if(FAILED(hr))
|
|
{
|
|
HandleMMError(LoadAtlString(IDS_E_FILE_LOAD_XML), hr);
|
|
}
|
|
}
|
|
|
|
void HandleSeekerScrollFunc(WORD wPos)
|
|
{
|
|
g_pApp->HandleSeekerScroll(wPos);
|
|
}
|
|
|
|
void HandleRateScrollFunc(WORD wPos)
|
|
{
|
|
g_pApp->HandleRateScroll(wPos);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
HRESULT InitTedApp(LPCWSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
g_pApp = new CTedApp;
|
|
if(g_pApp == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
IFC(g_pApp->Init(lpCmdLine));
|
|
|
|
/* Make the window visible; update its client area; and return "success" */
|
|
g_pApp->ShowWindow(nCmdShow);
|
|
g_pApp->UpdateWindow();
|
|
|
|
Cleanup:
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL WINAPI wWinMain(
|
|
__in HINSTANCE hInstance,
|
|
__in_opt HINSTANCE hPrevInstance,
|
|
__in_opt LPWSTR lpCmdLine,
|
|
__in int nCmdShow
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MSG msg;
|
|
HACCEL hAccelTable;
|
|
INITCOMMONCONTROLSEX iccex;
|
|
|
|
g_hInst = hInstance;
|
|
|
|
(void)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
|
|
|
|
g_hTedUtilInst = LoadLibraryEx(L"TEDUTIL.dll", NULL, 0);
|
|
|
|
// Initialize common controls
|
|
iccex.dwSize = sizeof (INITCOMMONCONTROLSEX);
|
|
iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES;
|
|
InitCommonControlsEx(&iccex);
|
|
|
|
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TRV));
|
|
|
|
/* Perform initializations that apply to a specific instance */
|
|
IFC(InitTedApp(lpCmdLine, nCmdShow));
|
|
|
|
/* Acquire and dispatch messages until a WM_QUIT uMessage is received. */
|
|
while(GetMessage( &msg, NULL, 0, 0))
|
|
{
|
|
if (!TranslateAccelerator(g_pApp->m_hWnd, hAccelTable, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
delete g_pApp;
|
|
|
|
DestroyAcceleratorTable(hAccelTable);
|
|
|
|
::FreeLibrary(g_hTedUtilInst);
|
|
|
|
return (int)msg.wParam;
|
|
|
|
Cleanup:
|
|
assert(SUCCEEDED(hr));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|