windows-nt/Source/XPSP1/NT/multimedia/dshow/vidctl/playbackimpl.h

697 lines
25 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//==========================================================================;
//
// 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 <math.h>
#include "inputimpl.h"
#include <uuids.h>
namespace MSVideoControl {
#define BACKWARDS_STEPPING 0
const long nano_to_hundredths = 100000;
template<class T, LPCGUID LibID, LPCGUID KSCategory, class MostDerivedInterface = IMSVidPlayback>
class DECLSPEC_NOVTABLE IMSVidPlaybackImpl :
public IMSVidInputDeviceImpl<T, LibID, KSCategory, MostDerivedInterface> {
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<long>(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<long>(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<long>(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<long>(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<long>(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<long>(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<LONGLONG>(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<GUID>(TIME_FORMAT_FRAME) ) );
}
if(lPositionMode == TenthsSecondsMode){
return PQIMSeeking->SetTimeFormat(&(static_cast<GUID>(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<GUID>(TIME_FORMAT_FRAME)){
*lPositionMode = FrameMode;
return S_OK;
}
if(cur_mode == static_cast<GUID>(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<IMediaPosition> IMPos(m_pGraph);
CComQIPtr<IMediaControl> 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