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 + -
显示快捷键?