调用多个接口方法实现的Media Player该用何模式?

时间:2022-11-13 17:55:21
正在用DirectShow做一个media player。
特色是每种功能有一专门的接口提供。Player已经拥有这些接口。即:
class CMyPlayer
{
   IMediaControl* pControl;
   IAudioControl* pAudioControl;
   IVideoControl* pVideoControl;
   ISeekingControl* pSeeking;
.....};



主要功能是:
1,Seeking方面的控制。
由ISeekingControl提供。得到当前是否可以Seeking,当前位置,设置新位置等。
2,IVideoControl
设置全屏,查询全屏状态。
3,IAudioControl
设置音量,静音。
4,IMediaControl
play,stop,pause

我现在的做法是:
每个接口用一个类来封装,
ISeeking ---> 
CSeeking
{
  ISeeking* pSeeking;
};

然后在类中实现方法。

最后就是:
class CPlayer
{
CSeeking* pSeeking;
CAudioControl * pAudio
.....
};


最后,客户通过CPlayer来控制媒体播放。由CPlayer将动作转发到各自封装的类中。
如: 
CPlayer::Play()
{
  pMediaControl->Play();
}

我感觉这么做很繁琐,应该有什么模式可以套用的吧,可是不知道该用什么模式。现在组长要求我实现查看媒体播放的状态信息,就是看当前的播放速率,媒体格式等。假设该功能又需要一个新的接口提供,是不是又得新封装类,加实例?有简单的方法么?

9 个解决方案

#1


我也在学习ing,好方法我也没有.

#2


一个media palyer的类,的声明

//
// CDXGraph.h
//

#ifndef __H_CDXGraph__
#define __H_CDXGraph__
#include <streams.h>
// Filter graph notification to the specified window
#define WM_GRAPHNOTIFY  (WM_USER+20)

class CDXGraph
{
private:
IGraphBuilder *     mGraph;  
IMediaControl * mMediaControl;
IMediaEventEx * mEvent;
IBasicVideo * mBasicVideo;
IBasicAudio * mBasicAudio;
IVideoWindow  * mVideoWindow;
IMediaSeeking * mSeeking;

DWORD mObjectTableEntry; 
long m_handle;
char* file;
public:
void SetHandle(long h){m_handle = h;}
long GetHandle(){return m_handle;}
void SetFile(char* str){file = str;}
char* GetFile(){return file;}
void DeleteFile(){delete file; file = NULL;}
public:
CDXGraph();
virtual ~CDXGraph();

public:
virtual bool Create(void);
virtual void Release(void);
virtual bool Attach(IGraphBuilder * inGraphBuilder);

IGraphBuilder * GetGraph(void); // Not outstanding reference count
IMediaEventEx * GetEventHandle(void);

bool ConnectFilters(IPin * inOutputPin, IPin * inInputPin, const AM_MEDIA_TYPE * inMediaType = 0);
void DisconnectFilters(IPin * inOutputPin);

bool SetDisplayWindow(HWND inWindow);
bool SetNotifyWindow(HWND inWindow);
bool ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight);
void HandleEvent(WPARAM inWParam, LPARAM inLParam);

bool Run(void);        // Control filter graph
bool Stop(void);
bool Pause(void);
bool IsRunning(void);  // Filter graph status
bool IsStopped(void);
bool IsPaused(void);

bool SetFullScreen(BOOL inEnabled);
bool GetFullScreen(void);

// IMediaSeeking
bool GetCurrentPosition(double * outPosition);
bool GetStopPosition(double * outPosition);
bool SetCurrentPosition(double inPosition);
bool SetStartStopPosition(double inStart, double inStop);
bool GetDuration(double * outDuration);
bool SetPlaybackRate(double inRate);

// Attention: range from -10000 to 0, and 0 is FULL_VOLUME.
bool SetAudioVolume(long inVolume);
long GetAudioVolume(void);
// Attention: range from -10000(left) to 10000(right), and 0 is both.
bool SetAudioBalance(long inBalance);
long GetAudioBalance(void);

bool RenderFile(const char * inFile);
bool SnapshotBitmap(const char * outFile);

private:
void AddToObjectTable(void) ;
void RemoveFromObjectTable(void);

bool QueryInterfaces(void);
};

#endif // __H_CDXGraph__

#3


类的定义

//
// CDXGraph.cpp
//

#include "stdafx.h"
#include <streams.h>
#include "CDXGraph.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

////////////////////////////////////////////////////////////////////////////////
CDXGraph::CDXGraph()
{
mGraph        = NULL;
mMediaControl = NULL;
mEvent        = NULL;
mBasicVideo   = NULL;
mBasicAudio   = NULL;
mVideoWindow  = NULL;
mSeeking      = NULL;

mObjectTableEntry = 0;
}

CDXGraph::~CDXGraph()
{
Release();
}

bool CDXGraph::Create(void)
{
if (!mGraph)
{
if (SUCCEEDED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&mGraph)))
{
AddToObjectTable();

return QueryInterfaces();
}
mGraph = 0;
}
return false;
}

bool CDXGraph::QueryInterfaces(void)
{
if (mGraph)
{
HRESULT hr = NOERROR;
hr |= mGraph->QueryInterface(IID_IMediaControl, (void **)&mMediaControl);
hr |= mGraph->QueryInterface(IID_IMediaEventEx, (void **)&mEvent);
hr |= mGraph->QueryInterface(IID_IBasicVideo, (void **)&mBasicVideo);
hr |= mGraph->QueryInterface(IID_IBasicAudio, (void **)&mBasicAudio);
hr |= mGraph->QueryInterface(IID_IVideoWindow, (void **)&mVideoWindow);
hr |= mGraph->QueryInterface(IID_IMediaSeeking, (void **)&mSeeking);
if (mSeeking)
{
mSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
}
return SUCCEEDED(hr);
}
return false;
}

void CDXGraph::Release(void)
{
if (mSeeking)
{
mSeeking->Release();
mSeeking = NULL;
}
if (mMediaControl)
{
mMediaControl->Release();
mMediaControl = NULL;
}
if (mEvent)
{
mEvent->Release();
mEvent = NULL;
}
if (mBasicVideo)
{
mBasicVideo->Release();
mBasicVideo = NULL;
}
if (mBasicAudio)
{
mBasicAudio->Release();
mBasicAudio = NULL;
}
if (mVideoWindow)
{
mVideoWindow->put_Visible(OAFALSE);
mVideoWindow->put_MessageDrain((OAHWND)NULL);
mVideoWindow->put_Owner(OAHWND(0));
mVideoWindow->Release();
mVideoWindow = NULL;
}
RemoveFromObjectTable();
if (mGraph) 
{
mGraph->Release(); 
mGraph = NULL;
}
}

bool CDXGraph::Attach(IGraphBuilder * inGraphBuilder)
{
Release();

if (inGraphBuilder)
{
inGraphBuilder->AddRef();
mGraph = inGraphBuilder;

AddToObjectTable();
return QueryInterfaces();
}
return true;
}

IGraphBuilder * CDXGraph::GetGraph(void)
{
return mGraph;
}

IMediaEventEx * CDXGraph::GetEventHandle(void)
{
return mEvent;
}

// Connect filter from the upstream output pin to the downstream input pin
bool CDXGraph::ConnectFilters(IPin * inOutputPin, IPin * inInputPin, 
  const AM_MEDIA_TYPE * inMediaType)
{
if (mGraph && inOutputPin && inInputPin)
{
HRESULT hr = mGraph->ConnectDirect(inOutputPin, inInputPin, inMediaType);
return SUCCEEDED(hr) ? true : false;
}
return false;
}

void CDXGraph::DisconnectFilters(IPin * inOutputPin)
{
if (mGraph && inOutputPin)
{
HRESULT hr = mGraph->Disconnect(inOutputPin);
}
}

bool CDXGraph::SetDisplayWindow(HWND inWindow)
{
if (mVideoWindow)
{
// long lVisible;
// mVideoWindow->get_Visible(&lVisible);
// Hide the video window first
mVideoWindow->put_Visible(OAFALSE);
mVideoWindow->put_Owner((OAHWND)inWindow);

RECT windowRect;
::GetClientRect(inWindow, &windowRect);
mVideoWindow->put_Left(0);
mVideoWindow->put_Top(0);
mVideoWindow->put_Width(windowRect.right - windowRect.left);
mVideoWindow->put_Height(windowRect.bottom - windowRect.top);
mVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);

mVideoWindow->put_MessageDrain((OAHWND) inWindow);
// Restore the video window
if (inWindow != NULL)
{
// mVideoWindow->put_Visible(lVisible);
mVideoWindow->put_Visible(OATRUE);
}
else
{
mVideoWindow->put_Visible(OAFALSE);
}
return true;
}
return false;
}

bool CDXGraph::ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight)
{
if (mVideoWindow)
{
long lVisible = OATRUE;
mVideoWindow->get_Visible(&lVisible);
// Hide the video window first
mVideoWindow->put_Visible(OAFALSE);

mVideoWindow->put_Left(inLeft);
mVideoWindow->put_Top(inTop);
mVideoWindow->put_Width(inWidth);
mVideoWindow->put_Height(inHeight);

// Restore the video window
mVideoWindow->put_Visible(lVisible);
return true;
}
return false;
}

bool CDXGraph::SetNotifyWindow(HWND inWindow)
{
if (mEvent)
{
mEvent->SetNotifyWindow((OAHWND)inWindow, WM_GRAPHNOTIFY, 0);
return true;
}
return false;
}

void CDXGraph::HandleEvent(WPARAM inWParam, LPARAM inLParam)
{
if (mEvent)
{
LONG eventCode = 0, eventParam1 = 0, eventParam2 = 0;
while (SUCCEEDED(mEvent->GetEvent(&eventCode, &eventParam1, &eventParam2, 0)))
{
mEvent->FreeEventParams(eventCode, eventParam1, eventParam2);
switch (eventCode)
{
case EC_COMPLETE:
break;

case EC_USERABORT:
case EC_ERRORABORT:
break;

default:
break;
}
}
}
}

bool CDXGraph::Run(void)
{
if (mGraph && mMediaControl)
{
if (!IsRunning())
{
if (SUCCEEDED(mMediaControl->Run()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}

bool CDXGraph::Stop(void)
{
if (mGraph && mMediaControl)
{
if (!IsStopped())
{
if (SUCCEEDED(mMediaControl->Stop()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}

bool CDXGraph::Pause(void)
{
if (mGraph && mMediaControl)
{
if (!IsPaused())
{
if (SUCCEEDED(mMediaControl->Pause()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}

bool CDXGraph::IsRunning(void)
{
if (mGraph && mMediaControl)
{
OAFilterState state = State_Stopped;
if (SUCCEEDED(mMediaControl->GetState(10, &state)))
{
return state == State_Running;
}
}
return false;
}

bool CDXGraph::IsStopped(void)
{
if (mGraph && mMediaControl)
{
OAFilterState state = State_Stopped;
if (SUCCEEDED(mMediaControl->GetState(10, &state)))
{
return state == State_Stopped;
}
}
return false;
}

bool CDXGraph::IsPaused(void)
{
if (mGraph && mMediaControl)
{
OAFilterState state = State_Stopped;
if (SUCCEEDED(mMediaControl->GetState(10, &state)))
{
return state == State_Paused;
}
}
return false;
}

bool CDXGraph::SetFullScreen(BOOL inEnabled)
{
if (mVideoWindow)
{
HRESULT hr = mVideoWindow->put_FullScreenMode(inEnabled ? OATRUE : OAFALSE);
return SUCCEEDED(hr);
}
return false;
}

#4


接上面
bool CDXGraph::GetFullScreen(void)
{
if (mVideoWindow)
{
long  fullScreenMode = OAFALSE;
mVideoWindow->get_FullScreenMode(&fullScreenMode);
return (fullScreenMode == OATRUE);
}
return false;
}

// IMediaSeeking features
bool CDXGraph::GetCurrentPosition(double * outPosition)
{
if (mSeeking)
{
__int64 position = 0;
if (SUCCEEDED(mSeeking->GetCurrentPosition(&position)))
{
*outPosition = ((double)position) / 10000000.;
return true;
}
}
return false;
}

bool CDXGraph::GetStopPosition(double * outPosition)
{
if (mSeeking)
{
__int64 position = 0;
if (SUCCEEDED(mSeeking->GetStopPosition(&position)))
{
*outPosition = ((double)position) / 10000000.;
return true;
}
}
return false;
}

bool CDXGraph::SetCurrentPosition(double inPosition)
{
if (mSeeking)
{
__int64 one = 10000000;
__int64 position = (__int64)(one * inPosition);
HRESULT hr = mSeeking->SetPositions(&position, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 
0, AM_SEEKING_NoPositioning);
return SUCCEEDED(hr);
}
return false;
}

bool CDXGraph::SetStartStopPosition(double inStart, double inStop)
{
if (mSeeking)
{
__int64 one = 10000000;
__int64 startPos = (__int64)(one * inStart);
__int64 stopPos  = (__int64)(one * inStop);
HRESULT hr = mSeeking->SetPositions(&startPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 
&stopPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame);
return SUCCEEDED(hr);
}
return false;
}

bool CDXGraph::GetDuration(double * outDuration)
{
if (mSeeking)
{
__int64 length = 0;
if (SUCCEEDED(mSeeking->GetDuration(&length)))
{
*outDuration = ((double)length) / 10000000.;
return true;
}
}
return false;
}

bool CDXGraph::SetPlaybackRate(double inRate)
{
if (mSeeking)
{
if (SUCCEEDED(mSeeking->SetRate(inRate)))
{
return true;
}
}
return false;
}

// Attention: range from -10000 to 0, and 0 is FULL_VOLUME.
bool CDXGraph::SetAudioVolume(long inVolume)
{
if (mBasicAudio)
{
HRESULT hr = mBasicAudio->put_Volume(inVolume);
return SUCCEEDED(hr);
}
return false;
}

long CDXGraph::GetAudioVolume(void)
{
long volume = 0;
if (mBasicAudio)
{
mBasicAudio->get_Volume(&volume);
}
return volume;
}

// Attention: range from -10000(left) to 10000(right), and 0 is both.
bool CDXGraph::SetAudioBalance(long inBalance)
{
if (mBasicAudio)
{
HRESULT hr = mBasicAudio->put_Balance(inBalance);
return SUCCEEDED(hr);
}
return false;
}

long CDXGraph::GetAudioBalance(void)
{
long balance = 0;
if (mBasicAudio)
{
mBasicAudio->get_Balance(&balance);
}
return balance;
}

bool CDXGraph::RenderFile(const char * inFile)
{
if (mGraph)
{
WCHAR    szFilePath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, inFile, -1, szFilePath, MAX_PATH);
if (SUCCEEDED(mGraph->RenderFile(szFilePath, NULL)))
{
return true;
}
}
return false;
}

bool CDXGraph::SnapshotBitmap(const char * outFile)
{
if (mBasicVideo)
{
long bitmapSize = 0;
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))
{
bool pass = false;
unsigned char * buffer = new unsigned char[bitmapSize];
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer)))
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;

lpbi = (LPBITMAPINFOHEADER)buffer;

int nColors = 1 << lpbi->biBitCount;
if (nColors > 256)
nColors = 0;

hdr.bfType = ((WORD) ('M' << 8) | 'B'); //always is "BM"
hdr.bfSize = bitmapSize + sizeof( hdr );
hdr.bfReserved1  = 0;
hdr.bfReserved2  = 0;
hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize +
nColors * sizeof(RGBQUAD));

CFile bitmapFile(outFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary);
bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER));
bitmapFile.Write(buffer, bitmapSize);
bitmapFile.Close();
pass = true;
}
delete [] buffer;
return pass;
}
}
return false;
}



//////////////////////// For GraphEdit Dubug purpose /////////////////////////////
void CDXGraph::AddToObjectTable(void)
{
IMoniker * pMoniker = 0;
    IRunningObjectTable * objectTable = 0;
    if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
{
WCHAR wsz[256];
wsprintfW(wsz, L"FilterGraph %08p pid %08x", (DWORD_PTR)mGraph, GetCurrentProcessId());
HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
if (SUCCEEDED(hr)) 
{
hr = objectTable->Register(0, mGraph, pMoniker, &mObjectTableEntry);
pMoniker->Release();
}
objectTable->Release();
}
}

void CDXGraph::RemoveFromObjectTable(void)
{
IRunningObjectTable * objectTable = 0;
    if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
{
        objectTable->Revoke(mObjectTableEntry);
        objectTable->Release();
mObjectTableEntry = 0;
    }
}

#5


谢谢 UPCC(杂食动物) 
可惜文不对题。我想要的是用什么模式。

#6


呵呵,UPCC强人啊

#7


class wizard --> automation -->add class --> from a type libaray

#8


按照接口最小的原则,把一个大的类的所有接口分成若干组是合理的。

但是没有必要用一个类实现一个接口。直接用CPlayer继承这些接口就可以了,这个也是com编程的标准做法.
BEGIN_INTERFACE_PART(Player, ISeeking)
...
END_INTERFACE_PART()

STDMETHOD(SomeMethod)(Para)
{
  METHOD_PROLOGUE(CPlayer, Player)
  return pThis->SomeMethod(Para);
}

另外,接口是用来封装变化的,如果以后会出现ISeeking的不同实现.

你愿意为CPlayer派生子类的话,可以把SomeMethod定义为虚函数。

如果你觉得没有必要,到时再加个CSeeking基类。SomeMethod定义为它的虚函数。代码可以写成
STDMETHOD(SomeMethod)(Para)
{
  METHOD_PROLOGUE(CPlayer, Player)
  return pThis->m_pSeeking->SomeMethod(Para);
}
不过这样有一定违背了不和陌生人讲话的规则。因此这时最好把ISeeking移到CSeeking中去。

不要过度设计,也不要仓促动手。用设计模式封装可以预期的会变化的部分。

另外,可以看看Bridge模式。

#9


不应该是用类去封装接口,而是用具体的类去实现一个接口,接口是抽象的,实现是具体的,例如:

class ISeeking {
public:
    ...
};

class CSeeking : public ISeeking {
    ...
};

对于同一个接口,你可以在你的系统中有多个实现,或者你以后要升级时重新写个新的实现替代原来的那个实现。

#1


我也在学习ing,好方法我也没有.

#2


一个media palyer的类,的声明

//
// CDXGraph.h
//

#ifndef __H_CDXGraph__
#define __H_CDXGraph__
#include <streams.h>
// Filter graph notification to the specified window
#define WM_GRAPHNOTIFY  (WM_USER+20)

class CDXGraph
{
private:
IGraphBuilder *     mGraph;  
IMediaControl * mMediaControl;
IMediaEventEx * mEvent;
IBasicVideo * mBasicVideo;
IBasicAudio * mBasicAudio;
IVideoWindow  * mVideoWindow;
IMediaSeeking * mSeeking;

DWORD mObjectTableEntry; 
long m_handle;
char* file;
public:
void SetHandle(long h){m_handle = h;}
long GetHandle(){return m_handle;}
void SetFile(char* str){file = str;}
char* GetFile(){return file;}
void DeleteFile(){delete file; file = NULL;}
public:
CDXGraph();
virtual ~CDXGraph();

public:
virtual bool Create(void);
virtual void Release(void);
virtual bool Attach(IGraphBuilder * inGraphBuilder);

IGraphBuilder * GetGraph(void); // Not outstanding reference count
IMediaEventEx * GetEventHandle(void);

bool ConnectFilters(IPin * inOutputPin, IPin * inInputPin, const AM_MEDIA_TYPE * inMediaType = 0);
void DisconnectFilters(IPin * inOutputPin);

bool SetDisplayWindow(HWND inWindow);
bool SetNotifyWindow(HWND inWindow);
bool ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight);
void HandleEvent(WPARAM inWParam, LPARAM inLParam);

bool Run(void);        // Control filter graph
bool Stop(void);
bool Pause(void);
bool IsRunning(void);  // Filter graph status
bool IsStopped(void);
bool IsPaused(void);

bool SetFullScreen(BOOL inEnabled);
bool GetFullScreen(void);

// IMediaSeeking
bool GetCurrentPosition(double * outPosition);
bool GetStopPosition(double * outPosition);
bool SetCurrentPosition(double inPosition);
bool SetStartStopPosition(double inStart, double inStop);
bool GetDuration(double * outDuration);
bool SetPlaybackRate(double inRate);

// Attention: range from -10000 to 0, and 0 is FULL_VOLUME.
bool SetAudioVolume(long inVolume);
long GetAudioVolume(void);
// Attention: range from -10000(left) to 10000(right), and 0 is both.
bool SetAudioBalance(long inBalance);
long GetAudioBalance(void);

bool RenderFile(const char * inFile);
bool SnapshotBitmap(const char * outFile);

private:
void AddToObjectTable(void) ;
void RemoveFromObjectTable(void);

bool QueryInterfaces(void);
};

#endif // __H_CDXGraph__

#3


类的定义

//
// CDXGraph.cpp
//

#include "stdafx.h"
#include <streams.h>
#include "CDXGraph.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

////////////////////////////////////////////////////////////////////////////////
CDXGraph::CDXGraph()
{
mGraph        = NULL;
mMediaControl = NULL;
mEvent        = NULL;
mBasicVideo   = NULL;
mBasicAudio   = NULL;
mVideoWindow  = NULL;
mSeeking      = NULL;

mObjectTableEntry = 0;
}

CDXGraph::~CDXGraph()
{
Release();
}

bool CDXGraph::Create(void)
{
if (!mGraph)
{
if (SUCCEEDED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&mGraph)))
{
AddToObjectTable();

return QueryInterfaces();
}
mGraph = 0;
}
return false;
}

bool CDXGraph::QueryInterfaces(void)
{
if (mGraph)
{
HRESULT hr = NOERROR;
hr |= mGraph->QueryInterface(IID_IMediaControl, (void **)&mMediaControl);
hr |= mGraph->QueryInterface(IID_IMediaEventEx, (void **)&mEvent);
hr |= mGraph->QueryInterface(IID_IBasicVideo, (void **)&mBasicVideo);
hr |= mGraph->QueryInterface(IID_IBasicAudio, (void **)&mBasicAudio);
hr |= mGraph->QueryInterface(IID_IVideoWindow, (void **)&mVideoWindow);
hr |= mGraph->QueryInterface(IID_IMediaSeeking, (void **)&mSeeking);
if (mSeeking)
{
mSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
}
return SUCCEEDED(hr);
}
return false;
}

void CDXGraph::Release(void)
{
if (mSeeking)
{
mSeeking->Release();
mSeeking = NULL;
}
if (mMediaControl)
{
mMediaControl->Release();
mMediaControl = NULL;
}
if (mEvent)
{
mEvent->Release();
mEvent = NULL;
}
if (mBasicVideo)
{
mBasicVideo->Release();
mBasicVideo = NULL;
}
if (mBasicAudio)
{
mBasicAudio->Release();
mBasicAudio = NULL;
}
if (mVideoWindow)
{
mVideoWindow->put_Visible(OAFALSE);
mVideoWindow->put_MessageDrain((OAHWND)NULL);
mVideoWindow->put_Owner(OAHWND(0));
mVideoWindow->Release();
mVideoWindow = NULL;
}
RemoveFromObjectTable();
if (mGraph) 
{
mGraph->Release(); 
mGraph = NULL;
}
}

bool CDXGraph::Attach(IGraphBuilder * inGraphBuilder)
{
Release();

if (inGraphBuilder)
{
inGraphBuilder->AddRef();
mGraph = inGraphBuilder;

AddToObjectTable();
return QueryInterfaces();
}
return true;
}

IGraphBuilder * CDXGraph::GetGraph(void)
{
return mGraph;
}

IMediaEventEx * CDXGraph::GetEventHandle(void)
{
return mEvent;
}

// Connect filter from the upstream output pin to the downstream input pin
bool CDXGraph::ConnectFilters(IPin * inOutputPin, IPin * inInputPin, 
  const AM_MEDIA_TYPE * inMediaType)
{
if (mGraph && inOutputPin && inInputPin)
{
HRESULT hr = mGraph->ConnectDirect(inOutputPin, inInputPin, inMediaType);
return SUCCEEDED(hr) ? true : false;
}
return false;
}

void CDXGraph::DisconnectFilters(IPin * inOutputPin)
{
if (mGraph && inOutputPin)
{
HRESULT hr = mGraph->Disconnect(inOutputPin);
}
}

bool CDXGraph::SetDisplayWindow(HWND inWindow)
{
if (mVideoWindow)
{
// long lVisible;
// mVideoWindow->get_Visible(&lVisible);
// Hide the video window first
mVideoWindow->put_Visible(OAFALSE);
mVideoWindow->put_Owner((OAHWND)inWindow);

RECT windowRect;
::GetClientRect(inWindow, &windowRect);
mVideoWindow->put_Left(0);
mVideoWindow->put_Top(0);
mVideoWindow->put_Width(windowRect.right - windowRect.left);
mVideoWindow->put_Height(windowRect.bottom - windowRect.top);
mVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);

mVideoWindow->put_MessageDrain((OAHWND) inWindow);
// Restore the video window
if (inWindow != NULL)
{
// mVideoWindow->put_Visible(lVisible);
mVideoWindow->put_Visible(OATRUE);
}
else
{
mVideoWindow->put_Visible(OAFALSE);
}
return true;
}
return false;
}

bool CDXGraph::ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight)
{
if (mVideoWindow)
{
long lVisible = OATRUE;
mVideoWindow->get_Visible(&lVisible);
// Hide the video window first
mVideoWindow->put_Visible(OAFALSE);

mVideoWindow->put_Left(inLeft);
mVideoWindow->put_Top(inTop);
mVideoWindow->put_Width(inWidth);
mVideoWindow->put_Height(inHeight);

// Restore the video window
mVideoWindow->put_Visible(lVisible);
return true;
}
return false;
}

bool CDXGraph::SetNotifyWindow(HWND inWindow)
{
if (mEvent)
{
mEvent->SetNotifyWindow((OAHWND)inWindow, WM_GRAPHNOTIFY, 0);
return true;
}
return false;
}

void CDXGraph::HandleEvent(WPARAM inWParam, LPARAM inLParam)
{
if (mEvent)
{
LONG eventCode = 0, eventParam1 = 0, eventParam2 = 0;
while (SUCCEEDED(mEvent->GetEvent(&eventCode, &eventParam1, &eventParam2, 0)))
{
mEvent->FreeEventParams(eventCode, eventParam1, eventParam2);
switch (eventCode)
{
case EC_COMPLETE:
break;

case EC_USERABORT:
case EC_ERRORABORT:
break;

default:
break;
}
}
}
}

bool CDXGraph::Run(void)
{
if (mGraph && mMediaControl)
{
if (!IsRunning())
{
if (SUCCEEDED(mMediaControl->Run()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}

bool CDXGraph::Stop(void)
{
if (mGraph && mMediaControl)
{
if (!IsStopped())
{
if (SUCCEEDED(mMediaControl->Stop()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}

bool CDXGraph::Pause(void)
{
if (mGraph && mMediaControl)
{
if (!IsPaused())
{
if (SUCCEEDED(mMediaControl->Pause()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}

bool CDXGraph::IsRunning(void)
{
if (mGraph && mMediaControl)
{
OAFilterState state = State_Stopped;
if (SUCCEEDED(mMediaControl->GetState(10, &state)))
{
return state == State_Running;
}
}
return false;
}

bool CDXGraph::IsStopped(void)
{
if (mGraph && mMediaControl)
{
OAFilterState state = State_Stopped;
if (SUCCEEDED(mMediaControl->GetState(10, &state)))
{
return state == State_Stopped;
}
}
return false;
}

bool CDXGraph::IsPaused(void)
{
if (mGraph && mMediaControl)
{
OAFilterState state = State_Stopped;
if (SUCCEEDED(mMediaControl->GetState(10, &state)))
{
return state == State_Paused;
}
}
return false;
}

bool CDXGraph::SetFullScreen(BOOL inEnabled)
{
if (mVideoWindow)
{
HRESULT hr = mVideoWindow->put_FullScreenMode(inEnabled ? OATRUE : OAFALSE);
return SUCCEEDED(hr);
}
return false;
}

#4


接上面
bool CDXGraph::GetFullScreen(void)
{
if (mVideoWindow)
{
long  fullScreenMode = OAFALSE;
mVideoWindow->get_FullScreenMode(&fullScreenMode);
return (fullScreenMode == OATRUE);
}
return false;
}

// IMediaSeeking features
bool CDXGraph::GetCurrentPosition(double * outPosition)
{
if (mSeeking)
{
__int64 position = 0;
if (SUCCEEDED(mSeeking->GetCurrentPosition(&position)))
{
*outPosition = ((double)position) / 10000000.;
return true;
}
}
return false;
}

bool CDXGraph::GetStopPosition(double * outPosition)
{
if (mSeeking)
{
__int64 position = 0;
if (SUCCEEDED(mSeeking->GetStopPosition(&position)))
{
*outPosition = ((double)position) / 10000000.;
return true;
}
}
return false;
}

bool CDXGraph::SetCurrentPosition(double inPosition)
{
if (mSeeking)
{
__int64 one = 10000000;
__int64 position = (__int64)(one * inPosition);
HRESULT hr = mSeeking->SetPositions(&position, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 
0, AM_SEEKING_NoPositioning);
return SUCCEEDED(hr);
}
return false;
}

bool CDXGraph::SetStartStopPosition(double inStart, double inStop)
{
if (mSeeking)
{
__int64 one = 10000000;
__int64 startPos = (__int64)(one * inStart);
__int64 stopPos  = (__int64)(one * inStop);
HRESULT hr = mSeeking->SetPositions(&startPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 
&stopPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame);
return SUCCEEDED(hr);
}
return false;
}

bool CDXGraph::GetDuration(double * outDuration)
{
if (mSeeking)
{
__int64 length = 0;
if (SUCCEEDED(mSeeking->GetDuration(&length)))
{
*outDuration = ((double)length) / 10000000.;
return true;
}
}
return false;
}

bool CDXGraph::SetPlaybackRate(double inRate)
{
if (mSeeking)
{
if (SUCCEEDED(mSeeking->SetRate(inRate)))
{
return true;
}
}
return false;
}

// Attention: range from -10000 to 0, and 0 is FULL_VOLUME.
bool CDXGraph::SetAudioVolume(long inVolume)
{
if (mBasicAudio)
{
HRESULT hr = mBasicAudio->put_Volume(inVolume);
return SUCCEEDED(hr);
}
return false;
}

long CDXGraph::GetAudioVolume(void)
{
long volume = 0;
if (mBasicAudio)
{
mBasicAudio->get_Volume(&volume);
}
return volume;
}

// Attention: range from -10000(left) to 10000(right), and 0 is both.
bool CDXGraph::SetAudioBalance(long inBalance)
{
if (mBasicAudio)
{
HRESULT hr = mBasicAudio->put_Balance(inBalance);
return SUCCEEDED(hr);
}
return false;
}

long CDXGraph::GetAudioBalance(void)
{
long balance = 0;
if (mBasicAudio)
{
mBasicAudio->get_Balance(&balance);
}
return balance;
}

bool CDXGraph::RenderFile(const char * inFile)
{
if (mGraph)
{
WCHAR    szFilePath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, inFile, -1, szFilePath, MAX_PATH);
if (SUCCEEDED(mGraph->RenderFile(szFilePath, NULL)))
{
return true;
}
}
return false;
}

bool CDXGraph::SnapshotBitmap(const char * outFile)
{
if (mBasicVideo)
{
long bitmapSize = 0;
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))
{
bool pass = false;
unsigned char * buffer = new unsigned char[bitmapSize];
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer)))
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;

lpbi = (LPBITMAPINFOHEADER)buffer;

int nColors = 1 << lpbi->biBitCount;
if (nColors > 256)
nColors = 0;

hdr.bfType = ((WORD) ('M' << 8) | 'B'); //always is "BM"
hdr.bfSize = bitmapSize + sizeof( hdr );
hdr.bfReserved1  = 0;
hdr.bfReserved2  = 0;
hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize +
nColors * sizeof(RGBQUAD));

CFile bitmapFile(outFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary);
bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER));
bitmapFile.Write(buffer, bitmapSize);
bitmapFile.Close();
pass = true;
}
delete [] buffer;
return pass;
}
}
return false;
}



//////////////////////// For GraphEdit Dubug purpose /////////////////////////////
void CDXGraph::AddToObjectTable(void)
{
IMoniker * pMoniker = 0;
    IRunningObjectTable * objectTable = 0;
    if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
{
WCHAR wsz[256];
wsprintfW(wsz, L"FilterGraph %08p pid %08x", (DWORD_PTR)mGraph, GetCurrentProcessId());
HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
if (SUCCEEDED(hr)) 
{
hr = objectTable->Register(0, mGraph, pMoniker, &mObjectTableEntry);
pMoniker->Release();
}
objectTable->Release();
}
}

void CDXGraph::RemoveFromObjectTable(void)
{
IRunningObjectTable * objectTable = 0;
    if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
{
        objectTable->Revoke(mObjectTableEntry);
        objectTable->Release();
mObjectTableEntry = 0;
    }
}

#5


谢谢 UPCC(杂食动物) 
可惜文不对题。我想要的是用什么模式。

#6


呵呵,UPCC强人啊

#7


class wizard --> automation -->add class --> from a type libaray

#8


按照接口最小的原则,把一个大的类的所有接口分成若干组是合理的。

但是没有必要用一个类实现一个接口。直接用CPlayer继承这些接口就可以了,这个也是com编程的标准做法.
BEGIN_INTERFACE_PART(Player, ISeeking)
...
END_INTERFACE_PART()

STDMETHOD(SomeMethod)(Para)
{
  METHOD_PROLOGUE(CPlayer, Player)
  return pThis->SomeMethod(Para);
}

另外,接口是用来封装变化的,如果以后会出现ISeeking的不同实现.

你愿意为CPlayer派生子类的话,可以把SomeMethod定义为虚函数。

如果你觉得没有必要,到时再加个CSeeking基类。SomeMethod定义为它的虚函数。代码可以写成
STDMETHOD(SomeMethod)(Para)
{
  METHOD_PROLOGUE(CPlayer, Player)
  return pThis->m_pSeeking->SomeMethod(Para);
}
不过这样有一定违背了不和陌生人讲话的规则。因此这时最好把ISeeking移到CSeeking中去。

不要过度设计,也不要仓促动手。用设计模式封装可以预期的会变化的部分。

另外,可以看看Bridge模式。

#9


不应该是用类去封装接口,而是用具体的类去实现一个接口,接口是抽象的,实现是具体的,例如:

class ISeeking {
public:
    ...
};

class CSeeking : public ISeeking {
    ...
};

对于同一个接口,你可以在你的系统中有多个实现,或者你以后要升级时重新写个新的实现替代原来的那个实现。