home *** CD-ROM | disk | FTP | other *** search
- //==========================================================================;
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
- // PURPOSE.
- //
- // Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
- //
- //--------------------------------------------------------------------------;
-
- // media.c
-
- #include "stdwin.h"
- #include <evcode.h>
- #include "cplay.h"
- #include "file.h"
- #include "media.h"
- #include "toolbar.h"
- #include "resource.h"
-
- // current multimedia variables
- static Media media;
-
- /* State enquiries/changes */
- BOOL CanPlay( void ){
- /* return true if we can go to a playing state from our current state */
- return media.state==Stopped || media.state==Paused;
- };
-
- BOOL CanStop( void ){
- /* return true if we can go to a stopped state from our current state */
- return media.state==Playing || media.state==Paused;
- };
-
- BOOL CanPause( void ){
- /* return true if we can go to a paused state from our current state */
- return media.state==Playing || media.state==Stopped;
- };
-
- BOOL IsInitialized( void ){
- /* return true if we have loaded and initialized a multimedia file */
- return media.state!=Uninitialized;
- }
-
- void ChangeStateTo( State newState ){
- media.state = newState;
-
- // update the toolbar
- UpdateToolbar();
-
- }
-
- /* Initialization */
- BOOL InitMedia( void ){
- ChangeStateTo( Uninitialized );
-
- media.hGraphNotifyEvent = NULL;
- media.pGraph = NULL;
-
- return TRUE;
- }
-
- BOOL CreateFilterGraph( void ){
- IMediaEvent *pME;
- HRESULT hr; // return code
-
- ASSERT(media.pGraph == NULL);
-
- hr = CoCreateInstance( &CLSID_FilterGraph, // get this documents graph object
- NULL,
- CLSCTX_INPROC_SERVER,
- & IID_IGraphBuilder,
- (void **) &media.pGraph);
- if (FAILED(hr)){
- media.pGraph = NULL;
- return FALSE;
- }
-
- // Set up an event file so that we can be notified when the
- // graph stops playing
-
- hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaEvent, (void **) &pME);
- if (FAILED(hr)) {
- DeleteContents();
- return FALSE;
- }
-
- hr = pME->lpVtbl->GetEventHandle(pME, (OAEVENT*) &media.hGraphNotifyEvent);
- pME->lpVtbl->Release( pME );
-
- if (FAILED(hr)) {
- DeleteContents();
- return FALSE;
- }
-
- return TRUE;
- }
-
- /* Destruction */
- void DeleteContents( void ){
-
- if (media.pGraph != NULL) {
- media.pGraph->lpVtbl->Release( media.pGraph );
- media.pGraph = NULL;
- }
-
- // this event is owned by the filter graph and is thus invalid
- media.hGraphNotifyEvent = NULL;
-
- ChangeStateTo( Uninitialized );
- }
-
- BOOL RenderFile( LPSTR szFileName ){
- HRESULT hr;
- WCHAR wPath[MAX_PATH];
-
- DeleteContents();
-
- if ( !CreateFilterGraph() ) {
- PlayerMessageBox( IDS_CANT_INIT_QUARTZ );
- return FALSE;
- }
-
- MultiByteToWideChar( CP_ACP, 0, szFileName, -1, wPath, MAX_PATH );
-
- SetCursor( LoadCursor( NULL, IDC_WAIT ) );
- hr = media.pGraph->lpVtbl->RenderFile(media.pGraph, wPath, NULL);
- SetCursor( LoadCursor( NULL, IDC_ARROW ) );
-
- if (FAILED( hr )) {
- PlayerMessageBox( IDS_CANT_RENDER_FILE );
- return FALSE;
- }
-
- return TRUE;
-
- }
-
- void SetTitle( HWND hwnd, char *szFile ){
- /* Update the title of hwnd to "Player - szFile" */
- char szNewTitle[ _MAX_FNAME + _MAX_EXT + 20 ];
-
- strcpy( szNewTitle, APP_NAME );
- strcat( szNewTitle, " - " );
- strcat( szNewTitle, szFile );
-
- // Update the window's title
- SetWindowText( hwnd, szNewTitle );
- }
-
- void OpenMediaFile( HWND hwnd, LPSTR szFile ){
- /* File..Open has been selected */
- static char szFileName[ _MAX_PATH ];
- static char szTitleName[ _MAX_FNAME + _MAX_EXT ];
-
- if( szFile!=NULL && RenderFile( szFile ) ){
- LPSTR szTitle;
-
- // Work out the full path name and the file name from the
- // specified file
- GetFullPathName( szFile, _MAX_PATH, szFileName, &szTitle );
- strncpy( szTitleName, szTitle, _MAX_FNAME + _MAX_EXT );
- szTitleName[ _MAX_FNAME + _MAX_EXT -1 ] = '\0';
-
- // Set the main window title and update the state
- SetTitle( hwnd, szTitleName );
- ChangeStateTo( Stopped );
-
- } else if( DoFileOpenDialog( hwnd, szFileName, szTitleName )
- && RenderFile( szFileName ) ){
-
- // Set the main window title and update the state
- SetTitle( hwnd, szTitleName );
- ChangeStateTo( Stopped );
-
- }
-
- }
-
- /* Command handlers */
-
- // there are two possible UI strategies: you either play from the start
- // each time you stop, or you play from the current position, in which
- // case you have to explicitly rewind at the end.
- // If you want the play from current and rewind at end, enable this code
- // if you want the other, then enable FROM_START in OnMediaStop and OnAbortStop.
- #undef REWIND
- #define FROM_START
- void OnMediaPlay( void ){
- if( CanPlay() ){
- HRESULT hr;
- IMediaControl *pMC;
-
- // Obtain the interface to our filter graph
- hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
-
- if( SUCCEEDED(hr) ){
- #ifdef REWIND
- IMediaPosition * pMP;
- hr = media.pGraph->lpVtbl->QueryInterface(
- media.pGraph,
- &IID_IMediaPosition,
- (void**) &pMP);
- if (SUCCEEDED(hr)) {
- // start from last position, but rewind if near the
- // end
- REFTIME tCurrent, tLength;
- hr = pMP->lpVtbl->get_Duration(pMP, &tLength);
- if (SUCCEEDED(hr)) {
- hr = pMP->lpVtbl->get_CurrentPosition(pMP, &tCurrent);
- if (SUCCEEDED(hr)) {
- // within 1sec of end? (or past end?)
- if ((tLength - tCurrent) < 1) {
- pMP->lpVtbl->put_CurrentPosition(pMP, 0);
- }
- }
- }
- pMP->lpVtbl->Release(pMP);
- }
- #endif
-
-
- // Ask the filter graph to play and release the interface
- hr = pMC->lpVtbl->Run( pMC );
- pMC->lpVtbl->Release( pMC );
-
- if( SUCCEEDED(hr) ){
- ChangeStateTo( Playing );
- return;
- }
- }
-
- // Inform the user that an error occurred
- PlayerMessageBox( IDS_CANT_PLAY );
-
- }
- }
-
- void OnMediaPause( void ){
- if( CanPause() ){
- HRESULT hr;
- IMediaControl *pMC;
-
- // Obtain the interface to our filter graph
- hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
-
- if( SUCCEEDED(hr) ){
- // Ask the filter graph to pause and release the interface
- hr = pMC->lpVtbl->Pause( pMC );
- pMC->lpVtbl->Release( pMC );
-
- if( SUCCEEDED(hr) ){
- ChangeStateTo( Paused );
- return;
- }
- }
-
- // Inform the user that an error occurred
- PlayerMessageBox( IDS_CANT_PAUSE );
- }
-
- }
-
- // if you want the behaviour of playing from the beginning each time, then
- // define FROM_START. Otherwise see the ifdef REWIND above
- void OnMediaAbortStop(void)
- {
- if(CanStop())
- {
- HRESULT hr;
- IMediaControl *pMC;
-
- // Obtain the interface to our filter graph
- hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
-
- if( SUCCEEDED(hr) ){
- #ifdef FROM_START
- IMediaPosition * pMP;
- #endif
- // Ask the filter graph to stop and release the interface
- hr = pMC->lpVtbl->Stop( pMC );
- pMC->lpVtbl->Release( pMC );
-
- #ifdef FROM_START
-
- // if we want always to play from the beginning
- // then we should seek back to the start here
- // (on app or user stop request, and also after EC_COMPLETE).
- hr = media.pGraph->lpVtbl->QueryInterface(
- media.pGraph,
- &IID_IMediaPosition,
- (void**) &pMP);
- if (SUCCEEDED(hr)) {
- pMP->lpVtbl->put_CurrentPosition(pMP, 0);
- pMP->lpVtbl->Release(pMP);
- }
-
- // no visible rewind or we will re-show the window!
-
- #endif
-
- if( SUCCEEDED(hr) ){
- ChangeStateTo( Stopped );
- return;
- }
- }
- // Inform the user that an error occurred
- PlayerMessageBox( IDS_CANT_STOP );
- }
- }
-
-
- // There are two different ways to stop a graph. We can stop and then when we
- // are later paused or run continue from the same position. Alternatively the
- // graph can be set back to the start of the media when it is stopped to have
- // a more CDPLAYER style interface. These are both offered here conditionally
- // compiled using the FROM_START definition. The main difference is that in
- // the latter case we put the current position to zero while we change states
-
- void OnMediaStop( void ){
-
- if( CanStop() ){
- HRESULT hr;
- IMediaControl *pMC;
-
- // Obtain the interface to our filter graph
- hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
- if( SUCCEEDED(hr) ){
-
- #ifdef FROM_START
- IMediaPosition * pMP;
- OAFilterState state;
-
- // Ask the filter graph to pause
- hr = pMC->lpVtbl->Pause( pMC );
-
- // if we want always to play from the beginning
- // then we should seek back to the start here
- // (on app or user stop request, and also after EC_COMPLETE).
- hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph,
- &IID_IMediaPosition,
- (void**) &pMP);
- if (SUCCEEDED(hr)) {
- pMP->lpVtbl->put_CurrentPosition(pMP, 0);
- pMP->lpVtbl->Release(pMP);
- }
-
- // wait for pause to complete
- pMC->lpVtbl->GetState(pMC, INFINITE, &state);
- #endif
-
- // now really do the stop
- pMC->lpVtbl->Stop( pMC );
- pMC->lpVtbl->Release( pMC );
- ChangeStateTo( Stopped );
- return;
- }
-
- // Inform the user that an error occurred
- PlayerMessageBox( IDS_CANT_STOP );
- }
- }
-
- HANDLE GetGraphEventHandle( void )
- {
- return media.hGraphNotifyEvent;
-
- }
-
- //
- // If the event handle is valid, ask the graph
- // if anything has happened. eg the graph has stopped...
- void OnGraphNotify(void) {
- IMediaEvent *pME;
- long lEventCode, lParam1, lParam2;
-
- ASSERT( media.hGraphNotifyEvent != NULL );
-
- if( SUCCEEDED(media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaEvent, (void **) &pME))){
- if( SUCCEEDED(pME->lpVtbl->GetEvent(pME, &lEventCode, &lParam1, &lParam2, 0))) {
- if (lEventCode == EC_COMPLETE) {
- OnMediaStop();
- } else if ((lEventCode == EC_USERABORT) ||
- (lEventCode == EC_ERRORABORT)) {
- OnMediaAbortStop();
- }
- }
- pME->lpVtbl->Release( pME );
- }
- }
-
-