gsmedia.cpp
来自「网络泡泡被.net管理」· C++ 代码 · 共 484 行
CPP
484 行
// GsMedia.cpp: implementation of the CGsMedia class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "GsMedia.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define JIF(x) if (FAILED(hr=(x))) \
{if(g_pDebug)g_pDebug->ADD_LOG(TEXT("FAILED(0x%x) ") TEXT(#x) TEXT("\n"), hr); goto CLEANUP;}
CGsMedia::CGsMedia(CGsEngine* pEngine)
{
m_pEngine = pEngine;
m_pGB = NULL;
m_pMS = NULL;
m_pMC = NULL;
m_pME = NULL;
m_pBV = NULL;
m_pVW = NULL;
m_key_source = "";
m_isLooping = FALSE;
m_volume = 0;
m_isVideo = FALSE;
m_ID = 0;
//获取唯一的ID
std::map<ID, CGsMedia*>::iterator it = m_pEngine->m_media_cache.begin();
while(it != m_pEngine->m_media_cache.end() && m_ID == it->first)
{
m_ID++;
it++;
}
m_pEngine->m_media_cache[m_ID] = this;
}
CGsMedia::~CGsMedia()
{
std::map<ID, CGsMedia*>::iterator it = m_pEngine->m_media_cache.find(m_ID);
if(it != m_pEngine->m_media_cache.end())
{
m_pEngine->m_media_cache.erase(it);
}
Cleanup();
}
VOID CGsMedia::Cleanup()
{
m_key_source = "";
m_isLooping = FALSE;
m_volume = 0;
m_isVideo = FALSE;
FreeDirectShow();
}
HRESULT CGsMedia::InitDirectShow()
{
HRESULT hr = S_OK;
// Zero interfaces (sanity check)
m_pVW = NULL;
m_pBV = NULL;
JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB));
JIF(m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC));
JIF(m_pGB->QueryInterface(IID_IMediaSeeking, (void **)&m_pMS));
JIF(m_pGB->QueryInterface(IID_IBasicVideo, (void **)&m_pBV));
JIF(m_pGB->QueryInterface(IID_IVideoWindow, (void **)&m_pVW));
JIF(m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME));
return S_OK;
CLEANUP:
FreeDirectShow();
return(hr);
}
HRESULT CGsMedia::FreeDirectShow()
{
HRESULT hr=S_OK;
Stop();
// Hide video window and remove owner. This is not necessary here,
// since we are about to destroy the filter graph, but it is included
// for demonstration purposes. Remember to hide the video window and
// clear its owner when destroying a window that plays video.
if(m_pVW)
{
hr = m_pVW->put_Visible(OAFALSE);
hr = m_pVW->put_Owner(NULL);
}
SAFE_RELEASE(m_pMC);
SAFE_RELEASE(m_pMS);
SAFE_RELEASE(m_pVW);
SAFE_RELEASE(m_pBV);
SAFE_RELEASE(m_pME);
SAFE_RELEASE(m_pGB);
return hr;
}
HRESULT CGsMedia::HandleGraphEvent()
{
LONG evCode, evParam1, evParam2;
HRESULT hr=S_OK;
while(SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0)))
{
// Spin through the events
hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);
if(EC_COMPLETE == evCode)
{
// If looping, reset to beginning and continue playing
if (m_isLooping)
{
LONGLONG pos=0;
// Reset to first frame of movie
hr = m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
if (FAILED(hr))
{
// Some custom filters (like the Windows CE MIDI filter)
// may not implement seeking interfaces (IMediaSeeking)
// to allow seeking to the start. In that case, just stop
// and restart for the same effect. This should not be
// necessary in most cases.
Stop();
Play();
}
return S_OK;
}
if (m_isVideo)
{
m_pEngine->SetPlayVideo(NULL);
}
hr = m_pMC->Stop();
SetPositions(0);
m_filter_state = State_Stopped;
}
// If requested, display DirectShow events received
}
return hr;
}
BOOL CGsMedia::SetStreamSource(const char *strSource)
{
if(m_key_source==strSource)
return TRUE;
Cleanup();
m_key_source = strSource;
HRESULT hr = S_OK;
WCHAR wFile[MAX_PATH];
GSFILE_INFO* pfi = m_pEngine->FindSource(strSource);
if(pfi)
{
#ifndef UNICODE
MultiByteToWideChar(CP_ACP, 0, pfi->strFile, -1, wFile, MAX_PATH);
#else
lstrcpy(wFile, pfi->strFile);
#endif
}
else
{
#ifndef UNICODE
MultiByteToWideChar(CP_ACP, 0, strSource, -1, wFile, MAX_PATH);
#else
lstrcpy(wFile, strSource);
#endif
}
if(FAILED(FreeDirectShow()))
return FALSE;
if(FAILED(InitDirectShow()))
return FALSE;
// Allow DirectShow to create the FilterGraph for this media file
hr = m_pGB->RenderFile(wFile, NULL);
if (FAILED(hr))
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"),
hr, wFile);
FreeDirectShow();
return FALSE;
// return hr;
}
// We'll manually set the video to be visible, so disable autoshow
hr = m_pVW->put_AutoShow(OAFALSE);
// Set the message drain of the video window to point to our main
// application window.
//
// If this is an audio-only or MIDI file, then put_MessageDrain will fail.
//
hr = m_pVW->put_MessageDrain((OAHWND) m_pEngine->GetEngineWnd());
m_isVideo = FALSE;
if (SUCCEEDED(hr))
{
m_isVideo = TRUE;
}
if (m_isVideo)
{
hr = m_pVW->put_Owner((OAHWND) m_pEngine->GetEngineWnd());
hr = m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
}
// Have the graph signal event via window callbacks
hr = m_pME->SetNotifyWindow((OAHWND)(m_pEngine->GetEngineWnd()), GS_MEDIA_GRAPHNOTIFY+m_ID, 0);
// Place video window within the bounding rectangle
UpdateBounds();
// Make the video window visible within the screen window.
// If this is an audio-only file, then there won't be a video interface.
if (m_isVideo)
{
hr = m_pVW->put_Visible(OATRUE);
hr = m_pVW->SetWindowForeground(-1);
}
return SUCCEEDED(hr);
}
HRESULT CGsMedia::Play()
{
if(m_filter_state==State_Running)
return S_OK;
if (!m_pMC)
return S_OK;
HRESULT hr;
if (m_isVideo)
{
m_pEngine->SetPlayVideo(this);
m_pVW->put_Owner((OAHWND)m_pEngine->GetEngineWnd());
}
// Start playback
hr = m_pMC->Run();
if (FAILED(hr))
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("\r\n*** Failed(%08lx) in Run()!\r\n"), hr);
return hr;
}
// Remember play state
m_filter_state = State_Running;
SetVolume(m_pEngine->GetMediaVolume());
return hr;
}
HRESULT CGsMedia::Stop()
{
HRESULT hr;
if (!m_pMC)
return S_OK;
// If we're already stopped, don't check again
if (m_filter_state == State_Stopped)
return S_OK;
// Stop playback
hr = m_pMC->Stop();
SetPositions(0);
if (FAILED(hr))
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("\r\n*** Failed(%08lx) in Stop()!\r\n"), hr);
return hr;
}
// Remember play state
m_filter_state = State_Stopped;
if (m_isVideo)
{
m_pEngine->SetPlayVideo(NULL);
}
return hr;
}
HRESULT CGsMedia::Pause()
{
HRESULT hr=S_OK;
if (!m_pMC)
return S_OK;
// Play/pause
if(m_filter_state != State_Running)
return S_OK;
hr = m_pMC->Pause();
if (FAILED(hr))
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("\r\n*** Failed(%08lx) in Pause()!\r\n"), hr);
return hr;
}
else
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("*** Media is PAUSED.\r\n"));
}
// Remember play state
m_filter_state = State_Paused;
return hr;
}
HRESULT CGsMedia::Resume()
{
if(IsPause())
return Play();
return S_OK;
}
//HRESULT CGsMedia::PlayLoop(LONG volume)
//{
//
// m_isLooping = TRUE;
// return Play(volume);
//}
LONG CGsMedia::GetVolume()
{
return m_volume;
}
HRESULT CGsMedia::SetVolume(LONG volume)
{
HRESULT hr=S_OK;
IBasicAudio *pBA=NULL;
if (!m_pGB)
return S_OK;
hr = m_pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA);
if (FAILED(hr))
return S_OK;
// Read current volume
/*
hr = pBA->get_Volume(&m_volume);
if (hr == E_NOTIMPL)
{
// Fail quietly if this is a video-only media file
pBA->Release();
return hr;
}
else if (FAILED(hr))
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("Failed in pBA->get_Volume! hr=0x%x\r\n"), hr);
pBA->Release();
return hr;
}
m_volume = VOLUME_FULL;
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("*** Media is Resuming normal audio\r\n"));
*/
m_volume = volume;
if(m_volume>0)
m_volume = 0;
if(m_volume<-10000)
m_volume = -10000;
// Set new volume
hr = pBA->put_Volume(m_volume);
if (FAILED(hr))
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("Failed in pBA->put_Volume! hr=0x%x\r\n"), hr);
}
pBA->Release();
return hr;}
HRESULT CGsMedia::GetPositions(LONGLONG &Current, LONGLONG &length)
{
if(NULL==m_pMS)
return E_FAIL;
return m_pMS->GetPositions(&Current, &length);
}
VOID CGsMedia::UpdateBounds()
{
// if (m_pVW && (m_filter_state != State_Running))
// {
// m_pVW->put_Visible(OAFALSE);
// m_pVW->put_Visible(OATRUE);
// }
if (m_isVideo && m_pVW)
{
// m_pVW->put_Visible(OAFALSE);
// m_pVW->put_Visible(OATRUE);
LONG width, height;
// Read coordinates of video container window
RECT rc;
::GetClientRect(m_pEngine->GetEngineWnd(), &rc);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
// Ignore the video's original size and stretch to fit bounding rectangle
// m_pVW->SetWindowPosition(rc.left, rc.top, 0, 0);
HRESULT hr = m_pVW->SetWindowPosition(rc.left, rc.top, width, height);
if (FAILED(hr))
{
if(g_pDebug)
g_pDebug->ADD_LOG(TEXT("Failed to set window position! hr=0x%x\r\n"), hr);
return;
}
}
}
HRESULT CGsMedia::GetDuration(LONGLONG &duration)
{
if (!m_pMS)
return E_NOINTERFACE;
HRESULT hr;
// Is media time supported for this file?
if (S_OK != m_pMS->IsFormatSupported(&TIME_FORMAT_MEDIA_TIME))
return E_NOINTERFACE;
// Read the time format to restore later
GUID guidOriginalFormat;
hr = m_pMS->GetTimeFormat(&guidOriginalFormat);
if (FAILED(hr))
return hr;
// Set to time format for easy display
hr = m_pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
if (FAILED(hr))
return hr;
// Read the file's duration
hr = m_pMS->GetDuration(&duration);
if (FAILED(hr))
return hr;
// Return to the original format
if (guidOriginalFormat != TIME_FORMAT_MEDIA_TIME)
{
hr = m_pMS->SetTimeFormat(&guidOriginalFormat);
if (FAILED(hr))
return hr;
}
return hr;
}
HRESULT CGsMedia::SetPositions(LONGLONG pos)
{
if(NULL==m_pMS)
return E_NOINTERFACE;
// Reset to first frame of movie
return m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
}
VOID CGsMedia::UpdateOwner()
{
if(m_isVideo)
m_pVW->put_Owner((OAHWND)m_pEngine->GetEngineWnd());
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?