windows-nt/Source/XPSP1/NT/multimedia/dshow/vidctl/msvidctl/msvidsbesource.cpp
2020-09-26 16:20:57 +08:00

1221 lines
42 KiB
C++

//==========================================================================;
//
// Copyright (c) Microsoft Corporation 1999-2000.
//
//--------------------------------------------------------------------------;
//
// MSVidStreamBufferSource.cpp : Implementation of CMSVidStreamBufferSource
//
#include "stdafx.h"
#ifndef TUNING_MODEL_ONLY
#include "atltmp.h"
#include <encdec.h>
#include "MSVidCtl.h"
#include "MSVidsbeSource.h"
#include "encdec.h"
#if 0 // code for testing wm content
#include <wmsdkidl.h>
#endif
#include "msvidsbesink.h" // to get pabCert2
#define FILE_BEGINNING 0
#define LOCAL_OATRUE -1
DEFINE_EXTERN_OBJECT_ENTRY(CLSID_MSVidStreamBufferSource, CMSVidStreamBufferSource)
enum{
CLOSE_TO_LIVE = 50,
};
/////////////////////////////////////////////////////////////////////////////
// CMSVidStreamBufferSource
STDMETHODIMP CMSVidStreamBufferSource::get_SBESource(/*[out, retval]*/ IUnknown **sbeFilter){
if(!sbeFilter){
return E_POINTER;
}
if(!m_spFileSource){
USES_CONVERSION;
CString csName(_T("SBE Playback"));
QIFileSource qiFSource;
HRESULT hr = qiFSource.CoCreateInstance(CLSID_StreamBufferSource, NULL, CLSCTX_INPROC_SERVER);
if (FAILED(hr)){
_ASSERT(false);
return E_UNEXPECTED;
}
if(!qiFSource){
_ASSERT(false);
return E_UNEXPECTED;
}
m_spFileSource = qiFSource;
}
CComPtr<IUnknown> pUnk(m_spFileSource);
if(!pUnk){
return E_UNEXPECTED;
}
*sbeFilter = pUnk.Detach();
return NOERROR;
}
STDMETHODIMP CMSVidStreamBufferSource::CurrentRatings(/*[out, retval]*/ EnTvRat_System *pEnSystem, /*[out, retval]*/ EnTvRat_GenericLevel *pEnRating,
/*[out, retval]*/ LONG *plbfEnAttr){
if(!pEnSystem || !pEnRating || !plbfEnAttr){
return E_POINTER;
}
DSFilterList::iterator i;
EnTvRat_System system = static_cast<EnTvRat_System>(-1);
EnTvRat_GenericLevel level = static_cast<EnTvRat_GenericLevel>(-1);
LONG attr = static_cast<LONG>(-1);
if(m_decFilters.empty()){
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
for(i = m_decFilters.begin(); i != m_decFilters.end(); ++i){
EnTvRat_System temp_system = static_cast<EnTvRat_System>(-1);
EnTvRat_GenericLevel temp_level = static_cast<EnTvRat_GenericLevel>(-1);
LONG temp_attri = static_cast<LONG>(-1);
CComQIPtr<IDTFilter> qiDT(*i);
if(!qiDT){
continue;
}
HRESULT hr = qiDT->GetCurrRating(&temp_system, &temp_level, &temp_attri);
if(FAILED(hr)){
continue;
}
if(temp_system != system ||
temp_level != level ||
temp_attri != attr){
system = temp_system;
level = temp_level;
attr = temp_attri;
}
}
if(static_cast<long>(system) < 0 || static_cast<long>(level) < 0 || static_cast<long>(attr) < 0){
return E_FAIL;
}
*pEnSystem = system;
*pEnRating = level;
*plbfEnAttr = attr;
return S_OK;
}
// ------------------
STDMETHODIMP CMSVidStreamBufferSource::MaxRatingsLevel(/*[in]*/ EnTvRat_System enSystem, /*[in]*/ EnTvRat_GenericLevel enRating,
/*[in]*/ LONG plbfEnAttr){
DSFilterList::iterator i;
if(m_decFilters.empty()){
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
for(i = m_decFilters.begin(); i != m_decFilters.end(); ++i){
CComQIPtr<IDTFilter> qiDT(*i);
if(!qiDT){
continue;
}
HRESULT hr = qiDT->put_BlockedRatingAttributes(enSystem, enRating, plbfEnAttr);
if(FAILED(hr)){
return hr;
}
}
return S_OK;
}
STDMETHODIMP CMSVidStreamBufferSource::put_BlockUnrated(/*[in]*/ VARIANT_BOOL bBlock){
DSFilterList::iterator i;
bool block = (bBlock == VARIANT_TRUE) ? true : false;
if(m_decFilters.empty()){
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
for(i = m_decFilters.begin(); i != m_decFilters.end(); ++i){
CComQIPtr<IDTFilter> qiDT(*i);
if(!qiDT){
continue;
}
HRESULT hr = qiDT->put_BlockUnRated(block);
if(FAILED(hr)){
return hr;
}
}
return S_OK;
}
STDMETHODIMP CMSVidStreamBufferSource::put_UnratedDelay(/*[in]*/ long dwDelay){
DSFilterList::iterator i;
if(m_decFilters.empty()){
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
for(i = m_decFilters.begin(); i != m_decFilters.end(); ++i){
CComQIPtr<IDTFilter> qiDT(*i);
if(!qiDT){
continue;
}
HRESULT hr = qiDT->put_BlockUnRatedDelay(dwDelay);
if(FAILED(hr)){
return hr;
}
}
return S_OK;
}
STDMETHODIMP CMSVidStreamBufferSource::Unload(void) {
BroadcastUnadvise();
m_decFilters.clear();
HRESULT hr = IMSVidGraphSegmentImpl<CMSVidStreamBufferSource, MSVidSEG_SOURCE, &GUID_NULL>::Unload();
m_iReader = -1;
m_spFileSource = reinterpret_cast<IFileSourceFilter*>(NULL);
return hr;
}
STDMETHODIMP CMSVidStreamBufferSource::put_Init(IUnknown *pInit){
HRESULT hr = IMSVidGraphSegmentImpl<CMSVidStreamBufferSource, MSVidSEG_SOURCE, &GUID_NULL>::put_Init(pInit);
if (FAILED(hr)) {
return hr;
}
if (pInit) {
m_fInit = false;
return E_NOTIMPL;
}
return NOERROR;
}
STDMETHODIMP CMSVidStreamBufferSource::get_Name(BSTR * Name){
if (!m_fInit) {
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSource), CO_E_NOTINITIALIZED);
}
if (Name == NULL)
return E_POINTER;
try {
*Name = m_Name.Copy();
} catch(...) {
return E_POINTER;
}
return NOERROR;
}
// IMSVidInputDevice
STDMETHODIMP CMSVidStreamBufferSource::IsViewable(VARIANT* pv, VARIANT_BOOL *pfViewable)
{
if (!m_fInit) {
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSource), CO_E_NOTINITIALIZED);
}
if (!pv) {
return E_POINTER;
}
return E_NOTIMPL;
}
STDMETHODIMP CMSVidStreamBufferSource::View(VARIANT* pv) {
if (!m_fInit) {
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSource), CO_E_NOTINITIALIZED);
}
if (!pv) {
return E_POINTER;
}
if (!_wcsnicmp(pv->bstrVal, L"DVD:", 4)) {
return E_FAIL;
}
return put_FileName(pv->bstrVal);
}
STDMETHODIMP CMSVidStreamBufferSource::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IMSVidStreamBufferSource
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP CMSVidStreamBufferSource::put_Container(IMSVidGraphSegmentContainer *pCtl){
try {
HRESULT hr = S_OK;
if (!m_fInit) {
return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidStreamBufferSource), CO_E_NOTINITIALIZED);
}
if (!pCtl) {
#ifdef BUILD_WITH_DRM
CComQIPtr<IServiceProvider> spServiceProvider(m_pGraph);
if (spServiceProvider != NULL) {
CComPtr<IDRMSecureChannel> spSecureService;
hr = spServiceProvider->QueryService(SID_DRMSecureServiceChannel,
IID_IDRMSecureChannel,
reinterpret_cast<LPVOID*>(&spSecureService));
if(S_OK == hr){
// Found existing Secure Server
CComQIPtr<IRegisterServiceProvider> spRegServiceProvider(m_pGraph);
if(spRegServiceProvider == NULL){
// no service provider interface on the graph - fatal!
hr = E_NOINTERFACE;
}
if(SUCCEEDED(hr)){
hr = spRegServiceProvider->RegisterService(SID_DRMSecureServiceChannel, NULL);
}
}
_ASSERT(SUCCEEDED(hr));
}
#endif
return Unload();
}
if (m_pContainer) {
if (!m_pContainer.IsEqualObject(VWSegmentContainer(pCtl))) {
return Error(IDS_OBJ_ALREADY_INIT, __uuidof(IMSVidStreamBufferSource), CO_E_ALREADYINITIALIZED);
} else {
return NO_ERROR;
}
}
// DON'T addref the container. we're guaranteed nested lifetimes
// and an addref creates circular refcounts so we never unload.
m_pContainer.p = pCtl;
m_pGraph = m_pContainer.GetGraph();
hr = BroadcastAdvise();
if (FAILED(hr)) {
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::put_Container() can't advise for broadcast events");
return E_UNEXPECTED;
}
#if 0 // code for testing wm content
CComPtr<IUnknown> pUnkCert;
hr = WMCreateCertificate(&pUnkCert);
if (FAILED(hr)){
_ASSERT(false);
}
CComQIPtr<IMSVidCtl>tempCtl(pCtl);
if(tempCtl){
hr = tempCtl->put_ServiceProvider(pUnkCert);
if (FAILED(hr)){
_ASSERT(false);
}
}
#endif
#ifdef BUILD_WITH_DRM
#ifdef USE_TEST_DRM_CERT
{
DWORD dwDisableDRMCheck = 0;
CRegKey c;
CString keyname(_T("SOFTWARE\\Debug\\MSVidCtl"));
DWORD rc = c.Open(HKEY_LOCAL_MACHINE, keyname, KEY_READ);
if (rc == ERROR_SUCCESS) {
rc = c.QueryValue(dwDisableDRMCheck, _T("DisableDRMCheck"));
if (rc != ERROR_SUCCESS) {
dwDisableDRMCheck = 0;
}
}
if(dwDisableDRMCheck == 1){
return S_OK;
}
}
#endif
CComQIPtr<IServiceProvider> spServiceProvider(m_pGraph);
if (spServiceProvider == NULL) {
return E_NOINTERFACE;
}
CComPtr<IDRMSecureChannel> spSecureService;
hr = spServiceProvider->QueryService(SID_DRMSecureServiceChannel,
IID_IDRMSecureChannel,
reinterpret_cast<LPVOID*>(&spSecureService));
if(S_OK == hr){
// Found existing Secure Server
return S_OK;
}
else{
// if it's not there or failed for ANY reason
// lets create it and register it
CComQIPtr<IRegisterServiceProvider> spRegServiceProvider(m_pGraph);
if(spRegServiceProvider == NULL){
// no service provider interface on the graph - fatal!
hr = E_NOINTERFACE;
}
else{
// Create the Client
CComPtr<IDRMSecureChannel> spSecureServiceServer;
hr = DRMCreateSecureChannel( &spSecureServiceServer);
if(spSecureServiceServer == NULL){
hr = E_OUTOFMEMORY;
}
if(FAILED(hr)){
return hr;
}
// Init keys
hr = spSecureServiceServer->DRMSC_SetCertificate((BYTE *)pabCert2, cBytesCert2);
if(FAILED(hr)){
return hr;
}
hr = spSecureServiceServer->DRMSC_SetPrivateKeyBlob((BYTE *)pabPVK2, cBytesPVK2);
if(FAILED(hr)){
return hr;
}
hr = spSecureServiceServer->DRMSC_AddVerificationPubKey((BYTE *)abEncDecCertRoot, sizeof(abEncDecCertRoot) );
if(FAILED(hr)){
return hr;
}
// Register It
// note RegisterService does not addref pUnkSeekProvider
hr = spRegServiceProvider->RegisterService(SID_DRMSecureServiceChannel, spSecureServiceServer);
}
}
#endif // BUILD_WITH_DRM
return NOERROR;
} catch (ComException &e) {
return e;
} catch (...) {
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: get_CanStep(VARIANT_BOOL, VARIANT_BOOL*)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::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(!pfCan){
// Passed a NULL Pointer
return E_POINTER;
}
if (!m_pGraph) {
// graph not valid
return Error(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 Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
if(fBackwards == VARIANT_TRUE){
*pfCan = VARIANT_TRUE;
return S_OK;
}
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 Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: Step(long)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::Step(long lStep){
try{
// Checking args and interfaces
long tempStep = lStep;
if (!m_pGraph || !m_pContainer) {
// graph not valid
return Error(IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
PQVideoFrameStep pVFS(m_pGraph);
if(!pVFS){
// Could Not QI
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
if(lStep < 0){
PQMediaControl pmc(m_pGraph);
if (!pmc) {
return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidPlayback), E_UNEXPECTED);
}
HRESULT hr = pmc->Pause();
if (FAILED(hr)) {
TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Pause() hr = " << std::hex << hr), "");
return Error(IDS_CANT_PAUSE_GRAPH, __uuidof(IMSVidPlayback), hr);
}
long cur = 0;
long stepVal = (/*half a second in 100ths of a second*/ 50 * lStep);
PositionModeList curMode;
hr = get_PositionMode(&curMode);
if(FAILED(hr)){
return hr;
}
if(curMode == FrameMode){
stepVal = (stepVal/100) * 30; // hard coded to 30 fps for now
}
hr = get_CurrentPosition(&cur);
if(FAILED(hr)){
return hr;
}
if(cur == 0){
return Error(IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
cur = cur + stepVal; // stepVal is negative, duh
hr = put_CurrentPosition(cur);
if(FAILED(hr)){
return hr;
}
// Set tempStep and then step to refresh the current frame
tempStep = 1;
}
// Make it step
return pVFS->Step(tempStep, NULL);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: get_Start(long)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::get_Start(/*[out, retval]*/long *lStart){
HRESULT hr = S_OK;
LONGLONG tempfirst, templatest;
PositionModeList curMode;
try{
// Checking args and init'ing interfaces
if (!lStart){
return E_POINTER;
}
if (!m_pGraph) {
// graph not valid
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
// See if object supports ISBEMediaSeeking
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){ // not not'ing smart pointer, they assert if p == 0
// Find out what postion mode is being used
hr = get_PositionMode(&curMode);
if(FAILED(hr)){
return hr;
}
hr = PQIMSeeking->GetAvailable(&tempfirst, &templatest);
if(FAILED(hr)){
return hr;
}
// If it is FrameMode no conversion needed
if(tempfirst == 0){
*lStart = 0;
hr = S_OK;
return hr;
}
if(curMode == FrameMode){
*lStart = static_cast<long>(tempfirst);
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::get_Start() return=" << (unsigned long)(*lStart) << " longlong=" << (double)(tempfirst)), "");
hr = S_OK;
return hr;
}
// If it is TenthsSecondsMode need to be converted from 100 nanosecond units
if(curMode == TenthsSecondsMode){
*lStart = static_cast<long>(tempfirst / nano_to_hundredths);
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::get_Start() return=" << (unsigned long)(*lStart) << " longlong=" << (double)(tempfirst)), "");
hr = S_OK;
return hr;
}
// If it is some other mode not supported by the vidctl
else{
return E_UNEXPECTED;
}
}
// Could Not QI IMedia Seeking or Position
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
STDMETHODIMP CMSVidStreamBufferSource::get_RecordingAttribute(/*[out, retval]*/ IUnknown **pRecordingAttribute){
if(!pRecordingAttribute){
return E_POINTER;
}
CComPtr<IUnknown> pRecUnk(m_spFileSource);
if(!pRecUnk){
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
*pRecordingAttribute = pRecUnk.Detach();
return S_OK;
}
//-----------------------------------------------------------------------------------------
// Name: get_Length(long)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::get_Length(/*[out, retval]*/long *lLength){
HRESULT hr = S_OK;
LONGLONG tempfirst, templatest;
PositionModeList curMode;
try{
// Checking args and init'ing interfaces
if (!lLength){
return E_POINTER;
}
if (!m_pGraph) {
// graph not valid
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
// See if object supports ISBEMediaSeeking
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){ // not not'ing smart pointer, they assert if p == 0
// Find out what postion mode is being used
hr = get_PositionMode(&curMode);
if(FAILED(hr)){
return hr;
}
hr = PQIMSeeking->GetAvailable(&tempfirst, &templatest);
if(FAILED(hr)){
return hr;
}
// If it is FrameMode no conversion needed
if(curMode == FrameMode){
*lLength = static_cast<long>(templatest);
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::get_Length() return=" << (unsigned long)(*lLength) << " longlong=" << (double)(templatest)), "");
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>(templatest / nano_to_hundredths);
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::get_Length() return=" << (unsigned long)(*lLength) << " longlong=" << (double)(templatest)), "");
hr = S_OK;
return hr;
}
// If it is some other mode not supported by the vidctl
else{
return E_UNEXPECTED;
}
}
// Could Not QI IMedia Seeking
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: get_CurrentPosition(LONGLONG*)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::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_spFileSource) {
// graph not valid
return Error(IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
// See if object supports ISBEMediaSeeking
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){// not not'ing smart pointer, they assert if p == 0
// 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);
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::get_CurrentPosition() return=" << (unsigned long)(*lPosition) << " longlong=" << (double)(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);
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::get_CurrentPosition() return=" << (unsigned long)(*lPosition) << " longlong=" << (double)(tempval)), "");
hr = S_OK;
return hr;
}
// If it is some other mode not supported by the vidctl
else{
return E_UNEXPECTED;
}
}
// Could Not QI IMedia Seeking
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: put_CurrentPosition(LONGLONG)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::put_CurrentPosition(/*[in]*/long lPosition) {
HRESULT hr = S_OK;
LONGLONG tempval;
PositionModeList curMode;
try{
// Checking args and interfaces
if (!m_spFileSource) {
return Error(IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
// Check for a ISBEMediaSeeking Interface
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){ // not not'ing smart pointer, they assert if p == 0
// 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 = (tempval) * nano_to_hundredths;
}
// If it is in some other mode
else if(curMode != FrameMode){
return E_UNEXPECTED;
}
// Set the new Position
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::put_CurrentPosition() set to: input=" << (unsigned long)(lPosition) << " longlong=" << (double)(tempval)), "");
hr = PQIMSeeking->SetPositions(&tempval, AM_SEEKING_AbsolutePositioning, NULL, 0);
TRACELSM(TRACE_ERROR, (dbgDump << "StreamBufferSource::put_CurrentPosition() actually set to:" << (double)(tempval)), "");
return hr;
}
// Could Not QI Media Position
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: put_PositionMode(LONGLONG)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::put_PositionMode(/*[in]*/PositionModeList lPositionMode) {
HRESULT hr = S_OK;
double testval;
get_Rate(&testval);
try{
// Checking args and interfaces
if (!m_spFileSource) {
// graph not valid
return Error(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 ISBEMediaSeeking
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){// not not'ing smart pointer, they assert if p == 0
// Set the new mode
if(lPositionMode == FrameMode){
hr = PQIMSeeking->SetTimeFormat( &( static_cast<GUID>(TIME_FORMAT_FRAME) ) );
return hr;
}
if(lPositionMode == TenthsSecondsMode){
hr = PQIMSeeking->SetTimeFormat(&(static_cast<GUID>(TIME_FORMAT_MEDIA_TIME)));
return hr;
}
}
// Could Not QI
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: get_PositionMode(LONGLONG*)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::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_spFileSource) {
// graph not valid
return Error(IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
// Get an ISBEMediaSeeking Interface
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){// not not'ing smart pointer, they assert if p == 0
// 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;
}
}
// Could Not QI
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: put_Rate(double)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::put_Rate(double lRate){
HRESULT hr = S_OK;
try{
/*** Checking args and init'ing interfaces ***/
if (!m_spFileSource) {
// graph not valid
return Error(IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
// Attempt to set the rate using ISBEMediaSeeking
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){// not not'ing smart pointer, they assert if p == 0
return PQIMSeeking->SetRate(lRate);
}
// Could Not QI set the error
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
//-----------------------------------------------------------------------------------------
// Name: get_Rate(double*)
//-----------------------------------------------------------------------------------------
STDMETHODIMP CMSVidStreamBufferSource::get_Rate(double *plRate){
HRESULT hr = S_OK;
try{
/*** Checking args and init'ing interfaces ***/
if (!plRate){
return E_POINTER;
}
if (!m_spFileSource) {
// graph not valid
return Error(IDS_INVALID_STATE, __uuidof(IMSVidPlayback), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
PQISBEMSeeking PQIMSeeking(m_spFileSource);
if(!( !PQIMSeeking)){// not not'ing smart pointer, they assert if p == 0
return PQIMSeeking->GetRate(plRate);
}
// Could Not QI
return Error(IDS_E_CANTQI , __uuidof(IMSVidPlayback), E_NOINTERFACE);
}
catch(HRESULT hrTmp){
// Something went bad, threw a HRESULT
return Error(IDS_INVALID_STATE , __uuidof(IMSVidPlayback), hrTmp);
}
catch(...){
// Something went bad, dont know what it threw
return E_UNEXPECTED;
}
}
STDMETHODIMP CMSVidStreamBufferSource::PostStop(){
HRESULT hr = S_OK;
try {
#if 0
// If the graph is not is stopped state
// we make sure it is
if (!m_pGraph.IsStopped()) {
HRESULT hr = PQVidCtl(m_pContainer)->Stop();
}
#endif
// If m_fEnableResetOnStop is true then we need to reset
// the postion back to the beggining
// else do nothing
if(m_fEnableResetOnStop){
return put_CurrentPosition(0);
}
}
catch(HRESULT hrTmp){
hr = hrTmp;
}
catch(...){
hr = E_UNEXPECTED;
}
return hr;
}
STDMETHODIMP CMSVidStreamBufferSource::Decompose() {
return put_Container(NULL);
}
STDMETHODIMP CMSVidStreamBufferSource::Build() {
if (!m_FileName) {
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
QIFileSource qiFSource;
HRESULT hr = S_OK;
DSFilter pfr;
if(!m_spFileSource){
USES_CONVERSION;
hr = qiFSource.CoCreateInstance(CLSID_StreamBufferSource, NULL, CLSCTX_INPROC_SERVER);
if (FAILED(hr)){
_ASSERT(false);
return E_UNEXPECTED;
}
if(!qiFSource){
_ASSERT(false);
return E_UNEXPECTED;
}
m_spFileSource = qiFSource;
hr = m_spFileSource->QueryInterface(&pfr);
if (FAILED(hr) || !pfr) {
_ASSERT(false);
TRACELSM(TRACE_ERROR, (dbgDump << "MSVidStreamBufferSource::Build() Could not create StreamBufferSource hr = " << std::hex << hr), "");
return Error(IDS_CANT_PLAY_FILE, __uuidof(IMSVidStreamBufferSource), hr);
}
}
else{
qiFSource = m_spFileSource;
if(!qiFSource){
_ASSERT(false);
return E_UNEXPECTED;
}
hr = m_spFileSource->QueryInterface(&pfr);
if (FAILED(hr) || !pfr) {
_ASSERT(false);
TRACELSM(TRACE_ERROR, (dbgDump << "MSVidStreamBufferSource::Build() Could not create StreamBufferSource hr = " << std::hex << hr), "");
return Error(IDS_CANT_PLAY_FILE, __uuidof(IMSVidStreamBufferSource), hr);
}
}
CString csName(_T("SBE Playback"));
m_Filters.clear();
hr = m_pGraph.AddFilter(pfr, csName);
if(FAILED(hr)){
_ASSERT(false);
return E_UNEXPECTED;
}
hr = qiFSource->Load(m_FileName, NULL);
if (FAILED(hr)) {
bool rc = m_pGraph.RemoveFilter(pfr);
if (!rc) {
return E_UNEXPECTED;
}
TRACELSM(TRACE_ERROR, (dbgDump << "MSVidStreamBufferSource::Build() Could not create StreamBufferSource hr = " << std::hex << hr), "");
return Error(IDS_CANT_PLAY_FILE, __uuidof(IMSVidStreamBufferSource), hr);
}
m_Filters.push_back(pfr);
m_iReader = m_Filters.size() - 1;
#if ENCRYPT_NEEDED
DSFilterList intermediates;
for(DSFilter::iterator i = pfr.begin(); i != pfr.end(); ++i){
if((*i).GetDirection() == DOWNSTREAM && !(*i).IsConnected()){
// Create and add a decoder Tagger Filter
CComPtr<IUnknown> spEncTagD(CLSID_DTFilter, NULL, CLSCTX_INPROC_SERVER);
if (!spEncTagD) {
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSink::Build() can't load Tagger filter");
return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), E_UNEXPECTED);
}
DSFilter vrD(spEncTagD);
if (!vrD) {
ASSERT(false);
return ImplReportError(__uuidof(IMSVidStreamBufferSink), IDS_CANT_CREATE_FILTER, __uuidof(IStreamBufferSink), E_UNEXPECTED);
}
m_Filters.push_back(vrD);
m_decFilters.push_back(vrD);
csName = _T("Decoder/Tagger Filter");
m_pGraph.AddFilter(vrD, csName);
// Connect pin to the Tagger
hr = (*i).IntelligentConnect(vrD, intermediates);
if(FAILED(hr)){
TRACELM(TRACE_DETAIL, "CAnaSinComp::Compose() if you see this line more than once something must have gone wrong");
}
}
}
ASSERT(intermediates.begin() == intermediates.end());
m_Filters.insert(m_Filters.end(), intermediates.begin(), intermediates.end());
#endif
return NOERROR;
}
STDMETHODIMP CMSVidStreamBufferSource::PreRun(){
#if 0
if(m_iReader == -1 || m_Filters.empty()){
return Error(IDS_INVALID_STATE, __uuidof(IMSVidStreamBufferSource), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
}
CComQIPtr<IReferenceClock> pq_IRClock(m_Filters[m_iReader]);
if(!pq_IRClock){
return S_FALSE;
}
CComQIPtr<IMediaFilter> pq_MFGph(m_pGraph);
if(!pq_MFGph){
return E_NOINTERFACE;
}
HRESULT hr = pq_MFGph->SetSyncSource(pq_IRClock);
if(FAILED(hr)){
ASSERT(false);
}
return hr;
#endif
return E_NOTIMPL;
}
STDMETHODIMP CMSVidStreamBufferSource::OnEventNotify(long lEvent, LONG_PTR lParam1, LONG_PTR lParam2) {
if (lEvent == EC_COMPLETE) {
double curRate = 0;
HRESULT hr = S_OK;
hr = get_Rate(&curRate);
if(SUCCEEDED(hr)){
if(curRate < 0){
hr = put_Rate(1);
if(FAILED(hr)){
_ASSERT(false);
}
// We need to transition to pause then back to play to flush all of the buffers
// It appears to be a decoder issue, mostly
PQVidCtl sp_VidCtl(m_pContainer);
if(sp_VidCtl){
hr = sp_VidCtl->Pause();
if(FAILED(hr)){
_ASSERT(false); // Failed to pause this is really bad
}
hr = sp_VidCtl->Run();
if(FAILED(hr)){
_ASSERT(false); // Failed to run this is really bad
}
}
else{
_ASSERT(false); // We got events with no vidctl hosting us, really weird
}
CComQIPtr<IMSVidPlayback> ppb(this);
Fire_EndOfMedia(ppb);
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::OnEventNotify Tossed EndOfMedia at start of sbe stream");
return NOERROR;
}
}
}
if(lEvent == STREAMBUFFER_EC_RATE_CHANGED){
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::OnEventNotify STREAMBUFFER_EC_RATE_CHANGED");
HRESULT hr = S_OK;
#if 0 // code to try to make up for the lack of a rate change event on the vidctl
MSVidCtlStateList curState = STATE_UNBUILT;
hr = PQVidCtl(m_pContainer)->get_State(&curState);
if(SUCCEEDED(hr) && curState == STATE_PLAY){
CComQIPtr<IMSVidDevice> pd(this);
if (!pd) {
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::OnEventNotify Could not qi SBE Source Segment for IMSVidDevice");
}
else{
Fire_StateChange(pd, STATE_PLAY, STATE_PLAY);
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::OnEventNotify Tossed StateChange STATE_PLAY STATE_PLAY for rate change");
}
}
#endif
long len;
long curPos;
curPos = len = 0;
hr = get_Length(&len);
if(SUCCEEDED(hr)){
hr = get_CurrentPosition(&curPos);
if(SUCCEEDED(hr)){
if(len <= (curPos + CLOSE_TO_LIVE)){ // if current position is with in CLOSE_TO_LIVE of the len the we just bounced off of the end of the stream
CComQIPtr<IMSVidPlayback> ppb(this);
if (!ppb) {
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::OnEventNotify Could not qi SBE Source Segment for IMSVidPlayback");
}
else{
Fire_EndOfMedia(ppb);
TRACELM(TRACE_ERROR, "CMSVidStreamBufferSource::OnEventNotify Tossed EndOfMedia at end of sbe stream");
return NOERROR;
}
}
}
}
}
if(lEvent == STREAMBUFFER_EC_TIMEHOLE){
Fire_TimeHole(lParam1, lParam2);
return NOERROR;
}
if(lEvent == STREAMBUFFER_EC_STALE_DATA_READ){
Fire_StaleDataRead();
return NOERROR;
}
if(lEvent == STREAMBUFFER_EC_STALE_FILE_DELETED){
Fire_StaleFilesDeleted();
return NOERROR;
}
if(lEvent == STREAMBUFFER_EC_CONTENT_BECOMING_STALE){
Fire_ContentBecomingStale();
return NOERROR;
}
return IMSVidPBGraphSegmentImpl<CMSVidStreamBufferSource, MSVidSEG_SOURCE, &GUID_NULL>::OnEventNotify(lEvent, lParam1, lParam2);
}
HRESULT CMSVidStreamBufferSource::Fire(GUID gEventID) {
TRACELSM(TRACE_DETAIL, (dbgDump << "CMSVidStreamBufferSource::Fire() guid = " << GUID2(gEventID)), "");
if (gEventID == EVENTID_ETDTFilterLicenseFailure) {
Fire_CertificateFailure();
} else if (gEventID == EVENTID_ETDTFilterLicenseOK) {
Fire_CertificateSuccess();
} else if (gEventID == EVENTID_DTFilterRatingsBlock) {
Fire_RatingsBlocked();
} else if (gEventID == EVENTID_DTFilterRatingsUnblock) {
Fire_RatingsUnblocked();
} else if (gEventID == EVENTID_DTFilterRatingChange) {
Fire_RatingsChanged();
}
return NOERROR;
}
#endif