//==========================================================================; // // playbackimpl.h : additional infrastructure to support implementing IMSVidPlayback // nicely from c++ // Copyright (c) Microsoft Corporation 1999. // ///////////////////////////////////////////////////////////////////////////// #pragma once #ifndef PLAYBACKIMPL_H #define PLAYBACKIMPL_H #include #include "inputimpl.h" #include namespace MSVideoControl { #define BACKWARDS_STEPPING 0 const long nano_to_hundredths = 100000; template class DECLSPEC_NOVTABLE IMSVidPlaybackImpl : public IMSVidInputDeviceImpl { protected: bool m_fEnableResetOnStop; public: IMSVidPlaybackImpl(): m_fEnableResetOnStop(false) {} virtual ~IMSVidPlaybackImpl() {} //----------------------------------------------------------------------------------------- // Name: //----------------------------------------------------------------------------------------- STDMETHOD(get_Length)(/*[out, retval]*/long *lLength){ HRESULT hr = S_OK; LONGLONG tempval; PositionModeList curMode; try{ // Checking args and init'ing interfaces if (!lLength){ return E_POINTER; } if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } // See if object supports IMediaSeeking PQMediaSeeking PQIMSeeking(m_pGraph); if(PQIMSeeking){ // Find out what postion mode is being used hr = get_PositionMode(&curMode); if(FAILED(hr)){ return hr; } hr = PQIMSeeking->GetDuration(&tempval); if(FAILED(hr)){ return hr; } // If it is FrameMode no conversion needed if(curMode == FrameMode){ *lLength = static_cast(tempval); hr = S_OK; return hr; } // If it is TenthsSecondsMode need to be converted from 100 nanosecond units else if(curMode == TenthsSecondsMode){ *lLength = static_cast(tempval / nano_to_hundredths); hr = S_OK; return hr; } // If it is some other mode not supported by the vidctl else{ return E_UNEXPECTED; } } // See if object supports IMediaPostion PQMediaPosition PQIMPos(m_pGraph); if(PQIMPos){ // Get position double tempDub; hr = PQIMPos->get_CurrentPosition(&tempDub); // IMediaPostion only supports 100 Nanosecond units *lLength = static_cast(tempDub / nano_to_hundredths); hr = S_OK; return hr; } // Could Not QI IMedia Seeking or Position return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } //----------------------------------------------------------------------------------------- // Name: get_CurrentPosition(LONGLONG*) //----------------------------------------------------------------------------------------- STDMETHOD(get_CurrentPosition)(/*[out,retval]*/long *lPosition) { HRESULT hr = S_OK; LONGLONG tempval; PositionModeList curMode; try{ // Checking args and init'ing interfaces if (!lPosition){ return E_POINTER; } if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } // See if object supports IMediaSeeking PQMediaSeeking PQIMSeeking(m_pGraph); if(PQIMSeeking){ // Find out what postion mode is being used hr = get_PositionMode(&curMode); if(FAILED(hr)){ return hr; } hr = PQIMSeeking->GetCurrentPosition(&tempval); if(FAILED(hr)){ return hr; } // If it is FrameMode no conversion needed if(curMode == FrameMode){ *lPosition = static_cast(tempval); hr = S_OK; return hr; } // If it is TenthsSecondsMode need to be converted from 100 nanosecond units else if(curMode == TenthsSecondsMode){ *lPosition = static_cast(tempval / nano_to_hundredths); hr = S_OK; return hr; } // If it is some other mode not supported by the vidctl else{ return E_UNEXPECTED; } } // See if object supports IMediaPostion PQMediaPosition PQIMPos(m_pGraph); if(PQIMPos){ // Get position double tempDub; hr = PQIMPos->get_CurrentPosition(&tempDub); // IMediaPostion only supports 100 Nanosecond units *lPosition = static_cast(tempDub / nano_to_hundredths); hr = S_OK; return hr; } // Could Not QI IMedia Seeking or Position return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } //----------------------------------------------------------------------------------------- // Name: put_CurrentPosition(LONGLONG) //----------------------------------------------------------------------------------------- STDMETHOD(put_CurrentPosition)(/*[in]*/long lPosition) { HRESULT hr = S_OK; LONGLONG tempval = 0; PositionModeList curMode; LONG curPos; try{ // Checking args and interfaces if (!m_pGraph) { return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } hr = get_CurrentPosition(&curPos); if(curPos == lPosition){ return NOERROR; } // Check for a IMediaSeeking Interface PQMediaSeeking PQIMSeeking(m_pGraph); if(PQIMSeeking){ // Get the position Mode hr = get_PositionMode(&curMode); if(FAILED(hr)){ return hr; } tempval = lPosition; // If it is in TenthsSecondsMode convert input into 100 nanosecond units if(curMode == TenthsSecondsMode){ tempval = static_cast(lPosition); tempval = tempval * nano_to_hundredths; } // If it is in some other mode else if(curMode != FrameMode){ return E_UNEXPECTED; } // Set the new Position #if 0 if(curPos > lPosition && !m_pGraph.IsStopped()){ DWORD seekingFlags = AM_SEEKING_CanSeekBackwards; hr = PQIMSeeking->CheckCapabilities(&seekingFlags); if(FAILED(hr)){ return hr; } } #endif hr = PQIMSeeking->SetPositions(&tempval, AM_SEEKING_AbsolutePositioning, NULL, 0); return hr; } // Check for a IMediaPostion PQMediaPosition PQIMPos(m_pGraph); if(PQIMPos){ if(curPos > lPosition && !m_pGraph.IsStopped()){ long canSeekBackwardRetVal; PQIMPos->CanSeekBackward(&canSeekBackwardRetVal); if(canSeekBackwardRetVal != -1){// OATRUE = -1 return E_INVALIDARG; } } // IMediaPosition only does 100 nanosecond units double tempDub = lPosition; tempDub = tempDub * nano_to_hundredths; hr = PQIMPos->put_CurrentPosition(tempDub); return hr; } // Could Not QI Media Position or Seeking return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } //----------------------------------------------------------------------------------------- // Name: put_PositionMode(LONGLONG) //----------------------------------------------------------------------------------------- STDMETHOD(put_PositionMode)(/*[in]*/PositionModeList lPositionMode) { HRESULT hr = S_OK; double testval; get_Rate(&testval); try{ // Checking args and interfaces if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } // only valid values if(lPositionMode != FrameMode && lPositionMode != TenthsSecondsMode){ return E_INVALIDARG; } // Try for a IMediaSeeking PQMediaSeeking PQIMSeeking(m_pGraph); if(PQIMSeeking){ // Set the new mode if(lPositionMode == FrameMode){ return PQIMSeeking->SetTimeFormat( &( static_cast(TIME_FORMAT_FRAME) ) ); } if(lPositionMode == TenthsSecondsMode){ return PQIMSeeking->SetTimeFormat(&(static_cast(TIME_FORMAT_MEDIA_TIME))); } } // Try for a IMediaPosition PQMediaPosition PQIMPos(m_pGraph); if(PQIMPos){ // Only supports TenthsSecondsMode if(lPositionMode == TenthsSecondsMode){ return S_OK; } else{ return E_FAIL; } } // Could Not QI return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } //----------------------------------------------------------------------------------------- // Name: get_PositionMode(LONGLONG*) //----------------------------------------------------------------------------------------- STDMETHOD(get_PositionMode)(/*[out,retval]*/PositionModeList* lPositionMode) { HRESULT hr = S_OK; double testval; get_Rate(&testval); try{ // Checking args and interfaces if(!lPositionMode){ return E_POINTER; } if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } // Get an IMediaSeeking Interface PQMediaSeeking PQIMSeeking(m_pGraph); if(PQIMSeeking){ // Get the mode GUID cur_mode; hr = PQIMSeeking->GetTimeFormat(&cur_mode); if(FAILED(hr)){ return hr; } // Check to see which mode it is in if(cur_mode == static_cast(TIME_FORMAT_FRAME)){ *lPositionMode = FrameMode; return S_OK; } if(cur_mode == static_cast(TIME_FORMAT_MEDIA_TIME)){ *lPositionMode = TenthsSecondsMode; return S_OK; } // Not in a vidctl supported mode else{ return E_FAIL; } } // Get IMediaPosition PQMediaPosition PQIMPos(m_pGraph); if(PQIMPos){ // Only supports TenthsSecondsMode *lPositionMode = TenthsSecondsMode; return S_OK; } // Could Not QI return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } STDMETHOD(get_Duration)(double *dPos) { return E_NOTIMPL; } STDMETHOD(get_PrerollTime)(double *dPos) { return E_NOTIMPL; } STDMETHOD(put_PrerollTime)(double dPos) { return E_NOTIMPL; } STDMETHOD(get_StartTime)(double *StartTime) { return E_NOTIMPL; } STDMETHOD(put_StartTime)(double StartTime) { return E_NOTIMPL; } STDMETHOD(get_StopTime)(double *StopTime) { return E_NOTIMPL; } STDMETHOD(put_StopTime)(double StopTime) { return E_NOTIMPL; } //----------------------------------------------------------------------------------------- // Name: get_EnableResetOnStop(VARIANT_BOOL*) //----------------------------------------------------------------------------------------- STDMETHOD(get_EnableResetOnStop)(/*[out, retval]*/ VARIANT_BOOL *pVal){ HRESULT hr = S_OK; try { if(NULL == pVal){ throw(E_POINTER); } if(m_fEnableResetOnStop == true){ *pVal = VARIANT_TRUE; } else{ *pVal = VARIANT_FALSE; } } catch(HRESULT hrTmp){ hr = hrTmp; } catch(...){ hr = E_UNEXPECTED; } return hr; }// end of function get_EnableResetOnStop //----------------------------------------------------------------------------------------- // Name: put_EnableResetOnStop(VARIANT_BOOL) //----------------------------------------------------------------------------------------- STDMETHOD(put_EnableResetOnStop)(/*[in]*/ VARIANT_BOOL newVal){ HRESULT hr = S_OK; try { if(newVal == VARIANT_TRUE){ m_fEnableResetOnStop = true; } else{ m_fEnableResetOnStop = false; } } catch(...){ hr = E_UNEXPECTED; } return hr; }// end of function put_EnableResetOnStop //----------------------------------------------------------------------------------------- // Name: get_CanStep(VARIANT_BOOL, VARIANT_BOOL*) //----------------------------------------------------------------------------------------- STDMETHOD(get_CanStep)(VARIANT_BOOL fBackwards, VARIANT_BOOL *pfCan){ // NOTE: NO ONE supports backwords stepping (why not? who knows) // so just like everyone else we dont either try{ // Checking args and interfaces if(NULL == pfCan){ // Passed a NULL Pointer return E_POINTER; } if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } //Get a VideoFrameStep Interface PQVideoFrameStep pVFS(m_pGraph); if(!pVFS){ // Could Not QI return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } #if BACKWARDS_STEPPING // Checking for Backward Stepping should always be 0 if(fBackwards == VARIANT_TRUE){ // Backwords Stepping Not Supported Most Likely if(pVFS->CanStep(TRUE, NULL)==S_OK){ // It is all Good, Can Step Backwords *pfCan = VARIANT_TRUE; return S_OK; } *pfCan = VARIANT_FALSE; return S_OK; } #else // Still checking for Backward Stepping if(fBackwards == VARIANT_TRUE){ *pfCan = VARIANT_FALSE; return S_OK; } #endif // End checking for Backward Stepping // Checking for Forward Stepping else{ if(pVFS->CanStep(FALSE, NULL)==S_OK){ // It is all Good, Can Step Forward *pfCan = VARIANT_TRUE; return S_OK; } else{ // Can't Step *pfCan = VARIANT_FALSE; return S_OK; } } } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } //----------------------------------------------------------------------------------------- // Name: Step(long) //----------------------------------------------------------------------------------------- STDMETHOD(Step)(long lStep){ try{ // Checking args and interfaces if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } PQVideoFrameStep pVFS(m_pGraph); if(!pVFS){ // Could Not QI return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } #if BACKWARDS_STEPPING // Checking for Backward Stepping should always be 0 // If backwords stepping set rate or what ever needs to be done if(lStep < 0){ // Backwords Stepping Not Supported Most Likely if(pVFS->CanStep(TRUE, NULL)==S_OK){ // It is all Good, Can Step Backwords CComQIPtr IMPos(m_pGraph); CComQIPtr IMCon(m_pGraph); if(IMPos&&IMCon){ OAFilterState enterState; IMCon->GetState(INFINITE , &enterState); HRESULT hr = IMPos->put_Rate(1); if(SUCCEEDED(hr)){ hr = pVFS->Step((-lStep), NULL); if(SUCCEEDED(hr)){ return S_OK; } else{ return E_UNEXPECTED; } } } } // Backwords stepping not supported return E_NOTIMPL; } #else // Still checking for Backward Stepping if(lStep < 0){ return E_NOTIMPL; } #endif // End checking for Backward Stepping // Make it step return pVFS->Step(lStep, NULL); } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } // note: the following methods control the playback device *NOT* the graph. // if the underlying source filter only supports these functions via // imediacontrol on the graph then this device segment object should return E_NOTIMPL. STDMETHOD(Run)() { return E_NOTIMPL; } STDMETHOD(Pause)() { return E_NOTIMPL; } STDMETHOD(Stop)() { return E_NOTIMPL; } //----------------------------------------------------------------------------------------- // Name: put_Rate(double) //----------------------------------------------------------------------------------------- STDMETHOD(put_Rate)(double lRate){ HRESULT hr = S_OK; try{ /*** Checking args and init'ing interfaces ***/ if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } // Attempt to set the rate using IMediaSeeking PQMediaSeeking PQIMSeeking(m_pGraph); if(PQIMSeeking){ return PQIMSeeking->SetRate(lRate); } // If IMediaSeeking FAILS try IMediaPostion PQMediaPosition PQIMPos(m_pGraph); if(PQIMPos){ // Change rate return PQIMPos->put_Rate((double)lRate); } // Could Not QI Either one set the error return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } //----------------------------------------------------------------------------------------- // Name: get_Rate(double*) //----------------------------------------------------------------------------------------- STDMETHOD(get_Rate)(double *plRate){ HRESULT hr = S_OK; double curRate = 1; try{ /*** Checking args and init'ing interfaces ***/ if (!plRate){ return E_POINTER; } if (!m_pGraph) { // graph not valid return ImplReportError(__uuidof(T), IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE)); } PQMediaSeeking PQIMSeeking(m_pGraph); if(PQIMSeeking){ hr = PQIMSeeking->GetRate(&curRate); } else{ PQMediaPosition PQIMPos(m_pGraph); if(PQIMPos){ // Get rate hr = PQIMPos->get_Rate(&curRate); } // Could Not QI else{ return ImplReportError(__uuidof(T), IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE); } } if(SUCCEEDED(hr)){ *plRate = curRate; TRACELSM(TRACE_DETAIL, (dbgDump << "Playbackimpl::get_Rate() rate = " << curRate), ""); } else{ TRACELSM(TRACE_ERROR, (dbgDump << "Playbackimpl::get_Rate() get_rate failed"), ""); } return hr; } catch(HRESULT hrTmp){ // Something went bad, threw a HRESULT return ImplReportError(__uuidof(T), IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp); } catch(...){ // Something went bad, dont know what it threw return E_UNEXPECTED; } } }; }; // namespace #endif // end of file - playbackimpl.h