topical media & game development

talk show tell print

hush-src-multi-MultiPlayer-MultiPlayerDlg.cpp / cpp



  //------------------------------------------------------------------------------
  // File: MultiPlayerDlg.cpp
  //
  // Desc: DirectShow sample code - MultiVMR9 MultiPlayer sample
  //
  // Copyright (c) Microsoft Corporation.  All rights reserved.
  //------------------------------------------------------------------------------
  
  include <stdafx.h>
  include <MultiPlayer.h>
  include <MultiPlayerDlg.h>
  include <VMR9Subgraph.h>
  
  include <list>
  using namespace std;
  
  ifdef _DEBUG
  define new DEBUG_NEW
  endif
  
  const DWORD g_TimerID = 0x12345;
  extern HINSTANCE g_hInstance;
  
  // auxiliary array to simplify management of the dialog's controls
  UINT g_nControlIDs[] = 
  {
      IDC_COMBO_SOURCES,
      IDC_SLIDER_TIME,
      IDC_SLIDER_ALPHA,
      IDC_SLIDER_YPOS,
      IDC_SLIDER_XSIZE,
      IDC_SLIDER_ZORDER,
      IDC_SLIDER_XPOS,
      IDC_SLIDER_YSIZE,
      IDC_BUTTON_START,
      IDC_STATIC_TOTAL,
      IDC_STATIC_PATH,
      IDC_STATIC_STATE,
      IDC_STATIC_ALPHA,
      IDC_STATIC_XPOS,
      IDC_STATIC_XSIZE,
      IDC_STATIC_ZORDER,
      IDC_STATIC_YPOS,
      IDC_STATIC_YSIZE,
      IDC_SLIDER_SETFPS,
      IDC_STATIC_SETFPS,
  };
  
  int g_nControls = sizeof(g_nControlIDs) / sizeof(UINT);
  
  // CAboutDlg dialog used for App About
  
  class CAboutDlg : public CDialog
  {
  public:
      CAboutDlg();
  
  // Dialog Data
      enum { IDD = IDD_ABOUTBOX };
  
      protected:
      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  
  // Implementation
  protected:
      DECLARE_MESSAGE_MAP()
  };
  
  CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  {
  }
  
  void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  {
      CDialog::DoDataExchange(pDX);
  }
  
  BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  END_MESSAGE_MAP()
  
  
****************************Public*Routine******************************\ CMultiPlayerSession::Initialize default initialization of the wizard \*************************************************************************

  
  HRESULT CMultiPlayerSession::Initialize()
  {
      HRESULT hr = S_OK;
  
      try
      {
          if( m_pWizard )
              throw VFW_E_WRONG_STATE;
  
          // create wizard
          hr = CoCreateInstance( CLSID_MultiVMR9Wizard,
                                  NULL,
                                  CLSCTX_INPROC_SERVER,
                                  IID_IMultiVMR9Wizard,
                                  (void**)&m_pWizard);
          CHECK_HR( hr, DbgMsg("CMultiPlayerSession::Initialize: Failed to create instance of MultiVMR9Wizard, hr = 0x%08x", hr));
  
          // create video window
          CHECK_HR(
              hr = CreateVideoWindow_(400, 300, WS_CAPTION|WS_OVERLAPPED|WS_THICKFRAME|WS_POPUP),
              DbgMsg("CMultiPlayerSession::Initialize: failed to create video window"));
  
          // initialize wizard with default
          CHECK_HR(
              hr = m_pWizard->Initialize(NULL, m_hwndVideo, NULL),
              DbgMsg("CMultiPlayerSession::Initialize: failed to initialize the wizard, hr = 0x%08x", hr));
  
          // get interfaces
          CHECK_HR(
              m_pWizard->GetRenderEngine( &m_pRenderEngine),
              DbgMsg("CMultiPlayerSession::Initialize: failed to get Render Engine, hr = 0x%08x", hr));
  
          CHECK_HR(
              m_pRenderEngine->GetMixerControl( &m_pMixerControl),
              DbgMsg("CMultiPlayerSession::Initialize: failed to get Mixer Control, hr = 0x%08x", hr));
  
          CHECK_HR(
              m_pRenderEngine->GetUILayer( &m_pUILayer),
              DbgMsg("CMultiPlayerSession::Initialize: failed to get UILayer, hr = 0x%08x", hr));
      }
      catch( HRESULT hr1 )
      {
          hr = hr1;
      }
  
      return hr;
  }
  
  
****************************Public*Routine******************************\ CMultiPlayerSession::Terminate default termination of the wizard \*************************************************************************

  
  HRESULT CMultiPlayerSession::Terminate()
  {
      // since CMultiPlayerSession adds no data to the base CMultigraphSession,
      // default cleaning in the ~CMultigraphSession() is all we need
      return S_OK;
  }
  
  // CMultiPlayerDlg dialog
  
  
****************************Public*Routine******************************\ CMultiPlayerDlg constructor \*************************************************************************

  
  CMultiPlayerDlg::CMultiPlayerDlg(CWnd* pParent /*=NULL*/)
      : CDialog(CMultiPlayerDlg::IDD, pParent)
      , m_pSession( NULL )
      , m_strTotal(_T(""))
      , m_strPath(_T(""))
      , m_strSourceState(_T(""))
      , m_strAlpha(_T(""))
      , m_strXPos(_T(""))
      , m_strXSize(_T(""))
      , m_strYPos(_T(""))
      , m_strYSize(_T(""))
      , m_strZOrder(_T(""))
      , m_strFPS(_T(""))
      , m_dwTotalSources(0L)
      , m_dwSourceCounter(0)
      , m_fSetFPS( 30.f)
      , m_fGetFPS( 30.f)
      , m_nTimer( 0)
      , m_bmpAttach( NULL )
      , m_bmpAttachGray( NULL )
      , m_bmpDetach( NULL )
      , m_bmpDetachGray( NULL )
      , m_bmpPlay( NULL )
      , m_bmpPlayGray( NULL )
      , m_bmpPause( NULL )
      , m_bmpPauseGray( NULL )
      , m_bmpScale( NULL )
      , m_bmpScaleGray( NULL )
      , m_bmpColor( NULL )
      , m_bmpColorGray( NULL )
  {
      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  }
  
  
****************************Public*Routine******************************\ DoDataExchange MFC-generated \*************************************************************************

  
  void CMultiPlayerDlg::DoDataExchange(CDataExchange* pDX)
  {
      CDialog::DoDataExchange(pDX);
      DDX_Text(pDX, IDC_STATIC_TOTAL, m_strTotal);
      DDX_Text(pDX, IDC_STATIC_PATH, m_strPath);
      DDX_Text(pDX, IDC_STATIC_ALPHA, m_strAlpha);
      DDX_Text(pDX, IDC_STATIC_XPOS, m_strXPos);
      DDX_Text(pDX, IDC_STATIC_XSIZE, m_strXSize);
      DDX_Text(pDX, IDC_STATIC_YPOS, m_strYPos);
      DDX_Text(pDX, IDC_STATIC_YSIZE, m_strYSize);
      DDX_Text(pDX, IDC_STATIC_ZORDER, m_strZOrder);
      DDX_Text(pDX, IDC_STATIC_SETFPS, m_strFPS);
      DDX_Text(pDX, IDC_STATIC_START, m_strStartTime);
      DDX_Text(pDX, IDC_STATIC_CURTIME, m_strCurTime);
      DDX_Text(pDX, IDC_STATIC_STOP, m_strStopTime);
      DDX_Control(pDX, IDC_COMBO_SOURCES, m_comboSources);
      DDX_Control(pDX, IDC_SLIDER_TIME, m_sliderTime);
      DDX_Control(pDX, IDC_SLIDER_ALPHA, m_sliderAlpha);
      DDX_Control(pDX, IDC_SLIDER_XPOS, m_sliderXPos);
      DDX_Control(pDX, IDC_SLIDER_XSIZE, m_sliderXSize);
      DDX_Control(pDX, IDC_SLIDER_YPOS, m_sliderYPos);
      DDX_Control(pDX, IDC_SLIDER_YSIZE, m_sliderYSize);
      DDX_Control(pDX, IDC_SLIDER_ZORDER, m_sliderZOrder);
      DDX_Control(pDX, IDC_SLIDER_SETFPS, m_sliderFPS);
  }
  
  
****************************Public*Routine******************************\ MESSAGE_MAP MFC-generated \*************************************************************************

  
  BEGIN_MESSAGE_MAP(CMultiPlayerDlg, CDialog)
      ON_WM_SYSCOMMAND()
      ON_WM_PAINT()
      ON_WM_DESTROY()
      ON_WM_TIMER()
      ON_WM_QUERYDRAGICON()
      ON_CBN_SELCHANGE(IDC_COMBO_SOURCES, OnCbnSelchangeComboSources)
      ON_BN_CLICKED(IDC_BUTTON_ATTACH, OnBnClickedButtonAttach)
      ON_BN_CLICKED(IDC_BUTTON_DETACH, OnBnClickedButtonDetach)
      ON_BN_CLICKED(IDC_BUTTON_PLAY, OnBnClickedButtonPlay)
      ON_BN_CLICKED(IDC_BUTTON_PAUSE, OnBnClickedButtonPause)
      ON_BN_CLICKED(IDOK, OnOK)
      ON_BN_CLICKED(IDC_BUTTON_FIT, OnBnClickedButtonFit)
      ON_BN_CLICKED(IDC_BUTTON_COLOR, OnBnClickedButtonColor)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_ALPHA, OnNMReleasedcaptureSliderAlpha)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_SETFPS, OnNMReleasedcaptureSliderSetfps)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_TIME, OnNMReleasedcaptureSliderTime)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_ZORDER, OnNMReleasedcaptureSliderZorder)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_XPOS, OnNMReleasedcaptureSliderXpos)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_YPOS, OnNMReleasedcaptureSliderYpos)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_XSIZE, OnNMReleasedcaptureSliderXsize)
      ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_YSIZE, OnNMReleasedcaptureSliderYsize)
  END_MESSAGE_MAP()
  
  // CMultiPlayerDlg message handlers
  
****************************Public*Routine******************************\ OnInitDialog In addition to dialog initialization, set initial ranges and positions of sliders and default string values; load buttons' bitmaps, initialize timer. Once this is done, cocreate instance of the wizard \*************************************************************************

  
  BOOL CMultiPlayerDlg::OnInitDialog()
  {
      CDialog::OnInitDialog();
  
      // Add "About..." menu item to system menu.
  
      // IDM_ABOUTBOX must be in the system command range.
      ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
      ASSERT(IDM_ABOUTBOX < 0xF000);
  
      CMenu* pSysMenu = GetSystemMenu(FALSE);
      if (pSysMenu != NULL)
      {
          CString strAboutMenu;
          strAboutMenu.LoadString(IDS_ABOUTBOX);
          if (!strAboutMenu.IsEmpty())
          {
              pSysMenu->AppendMenu(MF_SEPARATOR);
              pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
          }
      }
  
      // Set the icon for this dialog.  The framework does this automatically
      //  when the application's main window is not a dialog
      SetIcon(m_hIcon, TRUE);         // Set big icon
      SetIcon(m_hIcon, FALSE);        // Set small icon
  
      // set sliders
      m_sliderAlpha.SetRange(0,100,TRUE);
      m_sliderTime.SetRange(0,100,TRUE);
      m_sliderXPos.SetRange(-100,100,TRUE);
      m_sliderXSize.SetRange(-100,100,TRUE);
      m_sliderYPos.SetRange(-100,100,TRUE);
      m_sliderYSize.SetRange(-100,100,TRUE);
      m_sliderZOrder.SetRange(0,1,TRUE);
      m_sliderFPS.SetRange(0,100,TRUE);
  
      m_sliderAlpha.SetTicFreq(5);
      m_sliderTime.SetTicFreq(5);
      m_sliderXPos.SetTicFreq(10);
      m_sliderYPos.SetTicFreq(10);
      m_sliderXSize.SetTicFreq(10);
      m_sliderYSize.SetTicFreq(10);
      m_sliderFPS.SetTicFreq(5);
  
      HINSTANCE hInst = AfxGetInstanceHandle();
      m_bmpAttach = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_ATTACH));
      m_bmpAttachGray = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_ATTACH_DISABLE));
      m_bmpDetach = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_DETACH));
      m_bmpDetachGray = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_DETACH_DISABLE));
      m_bmpPlay = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_PLAY));
      m_bmpPlayGray = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_PLAY_DISABLE));
      m_bmpPause = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_PAUSE));
      m_bmpPauseGray = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_PAUSE_DISABLE));
      m_bmpScale = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_SCALE));
      m_bmpScaleGray = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_SCALE_DISABLE));
      m_bmpColor = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_COLOR));
      m_bmpColorGray = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP_COLOR_DISABLE));
  
      m_nTimer = SetTimer( g_TimerID, 500, 0);
      SetWindowPos(NULL,1,1,0,0,SWP_NOOWNERZORDER|SWP_NOSIZE);
      UpdateWindow();
  
      m_pSession = new CMultiPlayerSession;
      if( !m_pSession )
      {
          AfxMessageBox(_T("Memory allocation error"),MB_OK,0);
          return FALSE;
      }
  
      HRESULT hr = m_pSession->Initialize();
      if( FAILED(hr))
      {
          AfxMessageBox(_T("Failed to create MultiVMR9Wizard object.\r\nMake sure you have registered MultiVMR9.dll"),MB_OK,0);
          return FALSE;
      }
  
      UpdateMediaButtons_();
      UpdateState_();
      UpdateSubgraphInfo_();
  
      UINT uintIDs[] = 
      {
          IDC_BUTTON_ATTACH,
          IDC_BUTTON_DETACH,
          IDC_BUTTON_PLAY,
          IDC_BUTTON_PAUSE,
          IDC_BUTTON_FIT,
          IDC_BUTTON_COLOR
      };
  
      UINT uintTips[] = 
      {
          IDS_TT_ADD,
          IDS_TT_DETACH,
          IDS_TT_PLAY,
          IDS_TT_PAUSE,
          IDS_TT_FIT,
          IDS_TT_BKCOLOR
      };
  
      // initialize tool tips
      for( int i=0; i< g_nButtons; i++ )
      {
          m_hwndToolTips[i] = ::CreateWindow(TOOLTIPS_CLASS, NULL,
                                           WS_POPUP | TTS_NOPREFIX,
                                           0, 0, 0, 0, NULL, NULL, g_hInstance, NULL );
          if( m_hwndToolTips[i] )
          {
              ::SetWindowPos( m_hwndToolTips[i], HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
              HWND hwndBtn = ::GetDlgItem( GetSafeHwnd(), uintIDs[i]);
              if( !IsWindow( hwndBtn ) )
              {
                  continue;
              }
  
              m_ti[i].cbSize = sizeof( TOOLINFO );
              m_ti[i].uFlags = TTF_TRANSPARENT | TTF_CENTERTIP | TTF_SUBCLASS | TTF_IDISHWND;
              m_ti[i].hwnd = hwndBtn;
              m_ti[i].uId =  (UINT_PTR)hwndBtn;
              m_ti[i].hinst = g_hInstance;
              m_ti[i].lpszText =MAKEINTRESOURCE(uintTips[i]);
              ::GetClientRect( m_hwndToolTips[i], &(m_ti[i].rect));
              LRESULT lRes = ::SendMessage( m_hwndToolTips[i], TTM_ADDTOOL, 0, (LPARAM)&(m_ti[i]) );
          } // if
      }// for
  
      //m_ToolTips.Activate( TRUE );
      
      //SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOSIZE);
  
      return TRUE;  // return TRUE  unless you set the focus to a control
  }
  
  
****************************Public*Routine******************************\ OnOK Response to "close" button First off, clean MultiVMR9-specific stuff, terminate and destroy Wizard \*************************************************************************

  
  void CMultiPlayerDlg::OnOK()
  {
      Clean_();
      HRESULT hr = S_OK;
      CString strMsg;
  
      if( m_pSession )
      {
          hr = m_pSession->Terminate();
          delete m_pSession;
          m_pSession = NULL;
      }
  
      CDialog::OnOK();
  }
  
  
****************************Public*Routine******************************\ OnSysCommand MFC-generated \*************************************************************************

  
  void CMultiPlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
  {
      if ((nID & 0xFFF0) == IDM_ABOUTBOX)
      {
          CAboutDlg dlgAbout;
          dlgAbout.DoModal();
      }
      else
      {
          CDialog::OnSysCommand(nID, lParam);
      }
  }
  
  // If you add a minimize button to your dialog, you will need the code below
  //  to draw the icon.  For MFC applications using the document/view model,
  //  this is automatically done for you by the framework.
  
  
****************************Public*Routine******************************\ OnPaint MFC-generated \*************************************************************************

  
  void CMultiPlayerDlg::OnPaint() 
  {
      if (IsIconic())
      {
          CPaintDC dc(this); // device context for painting
  
          SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
  
          // Center icon in client rectangle
          int cxIcon = GetSystemMetrics(SM_CXICON);
          int cyIcon = GetSystemMetrics(SM_CYICON);
          CRect rect;
          GetClientRect(&rect);
          int x = (rect.Width() - cxIcon + 1) / 2;
          int y = (rect.Height() - cyIcon + 1) / 2;
  
          // Draw the icon
          dc.DrawIcon(x, y, m_hIcon);
      }
      else
      {
          CDialog::OnPaint();
      }
  }
  
  
****************************Public*Routine******************************\ OnQueryDragIcon MFC-generated \*************************************************************************

  
  // The system calls this function to obtain the cursor to display while the user drags
  //  the minimized window.
  HCURSOR CMultiPlayerDlg::OnQueryDragIcon()
  {
      return static_cast<HCURSOR>(m_hIcon);
  }
  
  
****************************Public*Routine******************************\ OnDestroy clean MultiVMR9-specific stuff, delete bitmaps, kill the timer \*************************************************************************

  
  void CMultiPlayerDlg::OnDestroy()
  {
      CDialog::OnDestroy();
  
      KillTimer( m_nTimer );
      Clean_();
  
      DeleteObject( m_bmpAttach);
      DeleteObject( m_bmpAttachGray);
      DeleteObject( m_bmpDetach);
      DeleteObject( m_bmpDetachGray);
      DeleteObject( m_bmpPlay);
      DeleteObject( m_bmpPlayGray);
      DeleteObject( m_bmpPause);
      DeleteObject( m_bmpPauseGray);
      DeleteObject( m_bmpScale);
      DeleteObject( m_bmpScaleGray);
      DeleteObject( m_bmpColor);
      DeleteObject( m_bmpColorGray);
  
      for( int i=0; i<g_nButtons; i++)
      {
          ::SendMessage( m_hwndToolTips[i], TTM_DELTOOL, 0, (LPARAM)&(m_ti[i]) );
          ::DestroyWindow( m_hwndToolTips[i] );
      }
  
  }
  
  
****************************Public*Routine******************************\ OnTimer call-back function to update dialog controls reflecting states and properties of video sources \*************************************************************************

  
  void CMultiPlayerDlg::OnTimer(UINT nIDEvent)
  {
      DWORD_PTR dwID = NULL;
      CVMR9Subgraph *pSrc = NULL;
      int FramesPerSecBy100;
      int nItem = -1;
      DWORD dwZ = 0L;
  
      HRESULT hr = S_OK;
  
      if( !m_pSession )
      {
          return;
      }
  
      FramesPerSecBy100 = m_pSession->GetFrameRate();
      m_fGetFPS = (float)FramesPerSecBy100/100.f;
  
      nItem = m_comboSources.GetCurSel();
      if( nItem == -1 )
      {
          return;
      }
  
      dwID = m_comboSources.GetItemData( nItem );
      pSrc = m_pSession->GetSubgraph( dwID );
      // for actively selected source
      if( !pSrc )
      {
          return;
      }
  
      UpdateSubgraphInfo_();
  
      // also, for all sources, check if a movie is close to the end and 
      // restart to provide looping play mode
      m_pSession->LoopSources();
  
      CDialog::OnTimer(nIDEvent);
  }
  
  
****************************Public*Routine******************************\ GetHHMMSS converts LONGLONG value of the reftime (timestamp from IMediaSeeking) to the CString of format "HH:MM:SS" (hours, minutes, seconds) \*************************************************************************

  
  CString CMultiPlayerDlg::GetHHMMSS( LONGLONG llT )
  {
      int hh;
      int mm;
      int ss;
      LONG SecTotal;
      CString strRet;
  
      SecTotal = (LONG)(llT / 10000000L);
      hh = (int)(SecTotal / 3600);
      mm = (int)((SecTotal - hh * 3600) / 60);
      ss = (int)(SecTotal - hh * 3600 - mm * 60);
  
      strRet.Format(_T("%02d:%02d:%02d"), hh, mm, ss);
      return strRet;
  }
  
  
****************************Public*Routine******************************\ OnBnClickedButtonAttach response to "Attach" button \*************************************************************************

  
  void CMultiPlayerDlg::OnBnClickedButtonAttach()
  {
      TCHAR achPath[MAX_PATH];
      WCHAR wcPath[MAX_PATH];
      DWORD_PTR dwID = NULL;
      HRESULT hr = S_OK;
      int nItem;
      HWND hwnd = NULL;
  
      if( !m_pSession )
      {
          return;
      }
  
      if( m_pSession->GetSize() > 16 ) 
      {
          AfxMessageBox(_T("This sample allows to render no more than 16 different streams at once"), MB_OK, NULL);
          return;
      }
  
      CFileDialog file(TRUE, NULL, NULL,OFN_FILEMUSTEXIST,
          _T("Media Files (*.asf;*.avi;*.mpg;*.mpeg;*.wmv)|*.asf;*.avi;*.mpg;*.mpeg;*.wmv|All Files (*.*)|*.*\0\0"),
          NULL);
  
      if( IDOK == file.DoModal())
      {
          lstrcpy( achPath, LPCTSTR(file.GetPathName()));
  ifdef UNICODE
          wcscpy( wcPath, achPath );
  else
          MultiByteToWideChar(CP_ACP, 0, achPath,-1, wcPath, MAX_PATH);
  endif
          hr = m_pSession->AddSource( wcPath, dwID);
          if( FAILED(hr))
          {
              CString strMessage;
              strMessage.Format(_T("Failed to attach media source to MultiVMR9. Error code 0x%08x"),hr);
              AfxMessageBox( strMessage, MB_OK, 0);
              return;
          }
          nItem = m_comboSources.AddString( achPath );
          m_comboSources.SetItemData( nItem, dwID);
          m_comboSources.SetCurSel( nItem );
  
          hwnd = m_pSession->GetWindow();
          ::ShowWindow( hwnd, SW_SHOW);
  
          UpdateState_();
          UpdateSubgraphInfo_();
          
          UpdateMediaButtons_();
          OnBnClickedButtonPlay();
      }
  }
  
  
****************************Public*Routine******************************\ OnBnClickedButtonDetach response to "Detach" button \*************************************************************************

  
  void CMultiPlayerDlg::OnBnClickedButtonDetach()
  {
      HRESULT hr = S_OK;
      int nItem = -1;
      DWORD_PTR dwID = NULL;
      HWND hwnd = NULL;
  
      if( !m_pSession )
          return;
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
          return;
  
      dwID = m_comboSources.GetItemData( nItem );
  
      hr = m_pSession->DeleteSource( dwID );
      if( FAILED( hr))
      {
          CString strMsg;
          strMsg.Format(TEXT("Failed to detach the graph from the wizard: hr = 0x%08x"), hr);
          MessageBox( LPCTSTR(strMsg));
          return;
      }
  
      m_comboSources.DeleteString(nItem);
      if( m_comboSources.GetCount() == 0)
      {
          m_comboSources.SetWindowText(TEXT(""));
          hwnd = m_pSession->GetWindow();
          ::ShowWindow( hwnd, SW_HIDE);
      }
      else
      {
          m_comboSources.SetCurSel(0);
      }
  
      UpdateData(FALSE);
      UpdateSubgraphInfo_();
      UpdateMediaButtons_();
  }
  
  
****************************Public*Routine******************************\ OnBnClickedButtonPlay response to "Play" button \*************************************************************************

  
  void CMultiPlayerDlg::OnBnClickedButtonPlay()
  {
      HRESULT hr = S_OK;
      DWORD_PTR dwID = NULL;
      CVMR9Subgraph *pSrc = NULL;
      int nItem = -1;
      void* pData = NULL;
  
      if( !m_pSession )
      {
          return;
      }
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
      {
          return;
      }
  
      dwID = m_comboSources.GetItemData( nItem );
      pSrc = m_pSession->GetSubgraph( dwID);
  
      if( !pSrc ) 
          return;
  
      pSrc->Run();
      UpdateMediaButtons_();
  }
  
  
****************************Public*Routine******************************\ OnBnClickedButtonPause response to "Pause" button \*************************************************************************

  
  void CMultiPlayerDlg::OnBnClickedButtonPause()
  {
      HRESULT hr = S_OK;
      DWORD_PTR dwID = NULL;
      CVMR9Subgraph *pSrc = NULL;
      int nItem = -1;
      void* pData = NULL;
  
      if( !m_pSession )
      {
          return;
      }
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
      {
          return;
      }
  
      dwID = m_comboSources.GetItemData( nItem );
      pSrc = m_pSession->GetSubgraph( dwID);
  
      if( !pSrc ) 
          return;
  
      pSrc->Pause();
      UpdateMediaButtons_();
  }
  
  
****************************Public*Routine******************************\ OnBnClickedButtonColor response to "Set background color" button \*************************************************************************

  
  void CMultiPlayerDlg::OnBnClickedButtonColor()
  {
      HRESULT hr = S_OK;
      COLORREF color;
      CColorDialog ClrDlg(0,CC_ANYCOLOR,this);
  
      if( !m_pSession )
          return;
  
      if( IDOK == ClrDlg.DoModal())
      {
          color = ClrDlg.GetColor();
          m_pSession->SetColor( color );
      }
  }
  
  
****************************Public*Routine******************************\ OnBnClickedButtonFit response to "Fit source to the window" button \*************************************************************************

  
  void CMultiPlayerDlg::OnBnClickedButtonFit()
  {
      HRESULT hr = S_OK;
      NORMALIZEDRECT nr;
      DWORD_PTR dwID = NULL;
      int nItem = -1;
      RECT rc;
      HWND hwnd = NULL;
      CComPtr<IMultiVMR9MixerControl> pMixer;
  
      if( !m_pSession )
          return;
  
      ::GetClientRect( hwnd, &rc);
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
      {
          return;
      }
      dwID = m_comboSources.GetItemData( nItem );
  
      pMixer = m_pSession->GetMixerControl();
  
      hwnd = m_pSession->GetWindow();
      if( !IsWindow( hwnd ))
          return;
  
      ::GetClientRect( hwnd, &rc);
  
      hr = pMixer->GetIdealOutputRect( dwID, rc.right, rc.bottom, &nr);
      hr = pMixer->SetOutputRect( dwID, &nr);
  }
  
  
****************************Public*Routine******************************\ OnCbnSelchangeComboSources response to selection change in the combobox \*************************************************************************

  
  void CMultiPlayerDlg::OnCbnSelchangeComboSources()
  {
      UpdateMediaButtons_();
      UpdateSubgraphInfo_();
  }
  
  
*************************** sliders ***********************************

  
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderAlpha slider for alpha \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderAlpha(NMHDR *pNMHDR, LRESULT *pResult)
  {
      int nItem = -1;
      DWORD_PTR dwID = NULL;
      HRESULT hr = S_OK;
      CComPtr<IMultiVMR9MixerControl> pMixer;
      float alpha;
  
      if( !m_pSession )
      {
          return;
      }
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
      {
          return;
      }
      dwID = m_comboSources.GetItemData(nItem);
  
      int nPos = m_sliderAlpha.GetPos();
      alpha = (float)nPos/100.f;
  
      pMixer = m_pSession->GetMixerControl();
  
      if( !pMixer )
      {
          return;
      }
  
      hr = pMixer->SetAlpha( dwID, alpha );
      *pResult = 0;
  }
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderSetfps slider for desired FPS \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderSetfps(NMHDR *pNMHDR, LRESULT *pResult)
  {
      HRESULT hr = S_OK;
      int nPos = m_sliderFPS.GetPos();
  
      CComPtr<IMultiVMR9RenderEngine> pRenderEngine;
  
      if( !m_pSession )
          return;
  
      pRenderEngine = m_pSession->GetRenderEngine();
  
      if( !pRenderEngine )
          return;
  
      m_fSetFPS = (float)nPos;
      hr = pRenderEngine->SetFrameRate( nPos * 100);
      *pResult = 0;
  }
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderTime slider for timeline \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderTime(NMHDR *pNMHDR, LRESULT *pResult)
  {
      HRESULT hr = S_OK;
      DWORD_PTR dwID;
      CVMR9Subgraph *pSrc = NULL;
      LONGLONG  llCur, llDur;
      int nItem = -1;
      int nPos;
  
      if( !m_pSession )
          return;
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
          return;
  
      dwID = m_comboSources.GetItemData( nItem );
      pSrc = m_pSession->GetSubgraph( dwID);
      if( !pSrc )
          return;
  
      hr = pSrc->GetTimes( llCur, llDur );
      if( FAILED(hr))
          return;
  
      nPos = m_sliderTime.GetPos();
      llCur = nPos * llDur / 100L;
      pSrc->SetTime( llCur );
  
      *pResult = 0;
  }
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderZorder slider for Z-order \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderZorder(NMHDR *pNMHDR, LRESULT *pResult)
  {
      HRESULT hr = S_OK;
      DWORD_PTR dwID = NULL;
      CComPtr<IMultiVMR9MixerControl> pMixer;
      int nItem = -1;
      int nPos;
  
      if( !m_pSession )
          return;
  
      pMixer = m_pSession->GetMixerControl();
  
      if( !pMixer )
          return;
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
          return;
  
      dwID = m_comboSources.GetItemData( nItem);
      nPos = m_sliderZOrder.GetPos();
  
      hr = pMixer->SetZOrder( dwID, nPos);
      *pResult = 0;
  }
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderXpos slider for X-position \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderXpos(NMHDR *pNMHDR, LRESULT *pResult)
  {
      UpdateOutputRect_();
      *pResult = 0;
  }
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderYpos slider for Y-position \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderYpos(NMHDR *pNMHDR, LRESULT *pResult)
  {
      UpdateOutputRect_();
      *pResult = 0;
  }
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderXsize slider for X-size \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderXsize(NMHDR *pNMHDR, LRESULT *pResult)
  {
      UpdateOutputRect_();
      *pResult = 0;
  }
  
  
****************************Public*Routine******************************\ OnNMReleasedcaptureSliderYsize slider for Y-size \*************************************************************************

  
  void CMultiPlayerDlg::OnNMReleasedcaptureSliderYsize(NMHDR *pNMHDR, LRESULT *pResult)
  {
      UpdateOutputRect_();
      *pResult = 0;
  }
  
  
//////////////////////// PRIVATE ROUTINE
///////////////////////


****************************Private*Routine*****************************\ Clean_ Cleans MultiVMR9-specific data; stops all the subgraphs and detaches them from the wizard; destroys m_listSources container; cleans combo box \*************************************************************************

  
  void CMultiPlayerDlg::Clean_()
  {
      HRESULT hr = S_OK;
      CString strMsg;
  
      // detach all players
      if( m_pSession )
      {
          m_pSession->Terminate();
          delete m_pSession;
          m_pSession = NULL;
      }
      m_comboSources.Clear();
  
      KillTimer( g_TimerID );
      Sleep(100);
  
  }
  
  
****************************Private*Routine*****************************\ UpdateState_ Updates controls depending on whether we have any source selected or not (when list is empty) \*************************************************************************

  
  void CMultiPlayerDlg::UpdateState_()
  {
      int i = 0;
  
      if( !m_pSession )
          return;
  
      int nItems = m_pSession->GetSize();
  
      if( 0 == nItems ) // we are empty
      {
          // disable anything but 'Add new video', 'total sources', and 'close',
          for( i=0; i<g_nControls; i++)
          {
              if( GetDlgItem( g_nControlIDs[i] ))
              {
                  if( IDC_STATIC_TOTAL == g_nControlIDs[i] )
                  {
                      GetDlgItem( g_nControlIDs[i])->EnableWindow( TRUE );
                  }
                  else
                  {
                      GetDlgItem( g_nControlIDs[i])->EnableWindow( FALSE );
                  }
              }
          }
      }
      else // we are not empty
      {
          // enable everything
          for( i=0; i<g_nControls; i++)
          {
              if( GetDlgItem( g_nControlIDs[i] ))
              {
                  GetDlgItem( g_nControlIDs[i])->EnableWindow( TRUE );
              }
          }
      }
  
      UpdateData( FALSE );
  }
  
  
****************************Private*Routine*****************************\ UpdateSubgraphInfo_ Updates controls to reflect currently selected source \*************************************************************************

  
  void CMultiPlayerDlg::UpdateSubgraphInfo_()
  {
      int nItem = -1;
      CVMR9Subgraph *pSrc = NULL;
      void *pData = NULL;
      DWORD_PTR dwID;
  
      if( m_pSession )
      {
          m_strTotal.Format(_T("Total sources: \%ld"), m_pSession->GetSize());
          m_strFPS.Format( _T("Desired FPS = %5.2f, Actual FPS = %5.2f"), m_fSetFPS, m_fGetFPS);
      }
  
      SetSliderPosition_( m_sliderFPS, (int)(m_fGetFPS + 10.f));
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem || !m_pSession)
      {
          // clean and return to defaults
          // update strings
          m_strPath = _T("");
          m_strAlpha.Format(_T("Alpha-level: 1.0"));
          m_strXPos.Format(_T("X-position = 0.0"));
          m_strYPos.Format(_T("Y-position = 0.0"));
          m_strXSize.Format(_T("X-size = 1.0"));
          m_strYSize.Format(_T("Y-size = 1.0"));
          m_strZOrder.Format(_T("Z-order = 0"));
  
          // update sliders
          SetSliderPosition_( m_sliderAlpha, 100);
          SetSliderPosition_( m_sliderXPos, 0);
          SetSliderPosition_( m_sliderYPos, 0);
          SetSliderPosition_( m_sliderXSize, 100);
          SetSliderPosition_( m_sliderYSize, 100);
          SetSliderPosition_( m_sliderZOrder, 0);
      }
      else
      {
          TCHAR achPath[MAX_PATH];
          float alpha = 1.f;
          DWORD dwZ = 0;
          LONGLONG llCur;
          LONGLONG llDur;
          NORMALIZEDRECT nr;
          NORMALIZEDRECT nrI;
          HWND hwnd;
          RECT rc;
  
          CComPtr<IMultiVMR9MixerControl> pMixer;
  
          pMixer = m_pSession->GetMixerControl();
          dwID = m_comboSources.GetItemData( nItem );
          pSrc = m_pSession->GetSubgraph( dwID);
  
          if( pSrc && pMixer )
          {
              pSrc->GetPathT( achPath );
              m_strPath.Format( _T("\%s"), achPath);
  
              // Update strings
              pMixer->GetAlpha( dwID, &alpha );
              m_strAlpha.Format( _T("Alpha = %5.2f"), alpha );
  
              pSrc->GetTimes( llCur, llDur );
              m_strStartTime = GetHHMMSS( 0L);
              m_strCurTime = GetHHMMSS( llCur );
              m_strStopTime = GetHHMMSS( llDur );
  
              pMixer->GetZOrder( dwID, &dwZ);
              m_strZOrder.Format( _T("Z-order = \%ld"), dwZ);
  
              // Update sliders
              SetSliderPosition_( m_sliderAlpha, (int)(alpha * 100.f));
              if( llDur )
              {
                  SetSliderPosition_( m_sliderTime, 
                      (int)(llCur * 100 / llDur));
              }
              m_sliderZOrder.SetRange( 0, m_pSession->GetSize()-1, TRUE);
              SetSliderPosition_( m_sliderZOrder, dwZ );
  
              hwnd = m_pSession->GetWindow();
              ::GetClientRect( hwnd, &rc);
  
              pMixer->GetOutputRect( dwID, &nr);
              pMixer->GetIdealOutputRect( dwID, rc.right, rc.bottom, &nrI);
              // Update positions
              float cx  = (nr.left +  nr.right) / 2.f;
              float cy  = (nr.top +  nr.bottom) / 2.f;
              float cxi = (nrI.left + nrI.right) / 2.f;
              float cyi = (nrI.top + nrI.bottom) / 2.f;
  
              float w  = nr.right - nr.left;
              float h  = nr.bottom - nr.top;
              float wi = nrI.right - nrI.left;
              float hi = nrI.bottom - nrI.top;
  
              float XPos = (cx - cxi) / wi;
              float YPos = (cy - cyi) / hi;
  
              float XSize = w / wi;
              float YSize = h / hi;
  
              // set strings
              m_strXPos.Format(_T("X-position = %5.2f"), XPos);
              m_strYPos.Format(_T("Y-position = %5.2f"), YPos);
              m_strXSize.Format(_T("X-size = %5.2f"), XSize);
              m_strYSize.Format(_T("Y-size = %5.2f"), YSize);
  
              // set sliders
              SetSliderPosition_( m_sliderXPos, (int)(XPos * 100.f));
              SetSliderPosition_( m_sliderYPos, (int)(YPos * 100.f));
              SetSliderPosition_( m_sliderXSize, (int)(XSize * 100.f));
              SetSliderPosition_( m_sliderYSize, (int)(YSize * 100.f));
          }
      }
  
      UpdateData(FALSE);
      return;
  }
  
  
****************************Private*Routine*****************************\ UpdateMediaButtons_ Updates media buttons depending on the number of attached sources and the state of currently selected source \*************************************************************************

  
  void CMultiPlayerDlg::UpdateMediaButtons_()
  {
      OAFilterState state;
      CVMR9Subgraph *pSrc = NULL;
      int nItems;
      DWORD_PTR dwID;
  
      if( !m_pSession )
          return;
  
      nItems = m_pSession->GetSize();
  
      if( GetDlgItem(IDC_BUTTON_ATTACH) )
      {
          ::SendMessage(  GetDlgItem(IDC_BUTTON_ATTACH)->GetSafeHwnd(), 
                          BM_SETIMAGE, 
                          (WPARAM)IMAGE_BITMAP, 
                          (LPARAM)( nItems<16 ? m_bmpAttach : m_bmpAttachGray) );
      }
      if( GetDlgItem(IDC_BUTTON_DETACH) )
      {
          ::SendMessage(  GetDlgItem(IDC_BUTTON_DETACH)->GetSafeHwnd(), 
                          BM_SETIMAGE, 
                          (WPARAM)IMAGE_BITMAP, 
                          (LPARAM)(nItems>0 ? m_bmpDetach : m_bmpDetachGray));
      }
  
      if( GetDlgItem(IDC_BUTTON_COLOR) )
      {
          ::SendMessage(  GetDlgItem(IDC_BUTTON_COLOR)->GetSafeHwnd(), 
                          BM_SETIMAGE, 
                          (WPARAM)IMAGE_BITMAP, 
                          (LPARAM)m_bmpColor);
      }
  
      if( 0 < m_comboSources.GetCount() && m_pSession)
      {
          int nItem = 0;
          
          nItem = m_comboSources.GetCurSel();
          if( -1 != nItem )
          {
              dwID = m_comboSources.GetItemData( nItem );
              pSrc = m_pSession->GetSubgraph( dwID);
          }
      }
  
      if( NULL == pSrc )
      {
          ::SendMessage(  GetDlgItem(IDC_BUTTON_PLAY)->GetSafeHwnd(), 
                          BM_SETIMAGE, 
                          (WPARAM)IMAGE_BITMAP, 
                          (LPARAM)(m_bmpPlayGray));
          ::SendMessage(  GetDlgItem(IDC_BUTTON_PAUSE)->GetSafeHwnd(), 
                          BM_SETIMAGE, 
                          (WPARAM)IMAGE_BITMAP, 
                          (LPARAM)(m_bmpPauseGray));
  
          ::SendMessage(  GetDlgItem(IDC_BUTTON_FIT)->GetSafeHwnd(), 
                          BM_SETIMAGE, 
                          (WPARAM)IMAGE_BITMAP, 
                          (LPARAM)(m_bmpScaleGray));
      }
      else
      {
          ::SendMessage(  GetDlgItem(IDC_BUTTON_FIT)->GetSafeHwnd(), 
                          BM_SETIMAGE, 
                          (WPARAM)IMAGE_BITMAP, 
                          (LPARAM)(m_bmpScale));
  
          state = pSrc->GetState();
          if( State_Running == state )
          {
              ::SendMessage(  GetDlgItem(IDC_BUTTON_PLAY)->GetSafeHwnd(), 
                              BM_SETIMAGE, 
                              (WPARAM)IMAGE_BITMAP, 
                              (LPARAM)(m_bmpPlayGray));
              ::SendMessage(  GetDlgItem(IDC_BUTTON_PAUSE)->GetSafeHwnd(), 
                              BM_SETIMAGE, 
                              (WPARAM)IMAGE_BITMAP, 
                              (LPARAM)(m_bmpPause));
  
          }
          else
          {
              ::SendMessage(  GetDlgItem(IDC_BUTTON_PLAY)->GetSafeHwnd(), 
                              BM_SETIMAGE, 
                              (WPARAM)IMAGE_BITMAP, 
                              (LPARAM)(m_bmpPlay));
              ::SendMessage(  GetDlgItem(IDC_BUTTON_PAUSE)->GetSafeHwnd(), 
                              BM_SETIMAGE, 
                              (WPARAM)IMAGE_BITMAP, 
                              (LPARAM)(m_bmpPauseGray));
          }
      }
  }
  
  
****************************Private*Routine*****************************\ UpdateOutputRect_ Transforms positions of "pos" and "size" sliders to NORMALIZEDRECT \*************************************************************************

  
  void CMultiPlayerDlg::UpdateOutputRect_()
  {
      int nItem = -1;
      DWORD_PTR dwID = NULL;
      CVMR9Subgraph *pSrc = NULL;
      int nPos = 0;
      CComPtr<IMultiVMR9MixerControl> pMixer;
      NORMALIZEDRECT nr;
      NORMALIZEDRECT nrI;
      HWND hwnd;
      RECT rc;
      HRESULT hr = S_OK;
      
      if( !m_pSession )
          return;
  
      nItem = m_comboSources.GetCurSel();
      if( -1 == nItem )
          return;
  
      dwID = m_comboSources.GetItemData( nItem );
      pSrc = m_pSession->GetSubgraph( dwID );
      if( !pSrc )
          return;
  
      pMixer = m_pSession->GetMixerControl();
      if( !pMixer )
          return;
  
      hwnd = m_pSession->GetWindow();
      if( !IsWindow( hwnd ))
          return;
  
      ::GetClientRect( hwnd, &rc);
  
      pMixer->GetOutputRect( dwID, &nr);
      pMixer->GetIdealOutputRect( dwID, rc.right, rc.bottom, &nrI);
  
      float wi = nrI.right - nrI.left;
      float hi = nrI.bottom - nrI.top;
  
      if( 0.f == wi || 0.f == hi )
          return;
  
      float cxi = (nrI.left + nrI.right) / 2.f;
      float cyi = (nrI.top + nrI.bottom) / 2.f;
  
      float cx = cxi + wi * (float)(m_sliderXPos.GetPos()) / 100.f;
      float cy = cyi + hi * (float)(m_sliderYPos.GetPos()) / 100.f;
  
      float w = (float)(m_sliderXSize.GetPos()) / 100.f / wi / 2.f;
      float h = (float)(m_sliderYSize.GetPos()) / 100.f / hi / 2.f;
  
      nr.left   = cx - w;
      nr.right  = cx + w;
      nr.top    = cy - h;
      nr.bottom = cy + h;
  
      pMixer->SetOutputRect( dwID, &nr);
  }
  
  
****************************Private*Routine*****************************\ SetSliderPosition_ Sets slider position only if slider is not captured by mouse \*************************************************************************

  
  void CMultiPlayerDlg::SetSliderPosition_( CSliderCtrl& slider, int Pos)
  {
      CWnd *pwnd = GetCapture();
  
      if( pwnd ==(CWnd*)(&slider) )
      {
          return;
      }
      slider.SetPos( Pos );
  }
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.