home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / media.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-11  |  10.2 KB  |  393 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11.  
  12. // media.c
  13.  
  14. #include "stdwin.h"
  15. #include <evcode.h>
  16. #include "cplay.h"
  17. #include "file.h"
  18. #include "media.h"
  19. #include "toolbar.h"
  20. #include "resource.h"
  21.  
  22. // current multimedia variables
  23. static Media media;
  24.  
  25. /* State enquiries/changes */
  26. BOOL CanPlay( void ){
  27. /* return true if we can go to a playing state from our current state */
  28.     return media.state==Stopped || media.state==Paused;
  29. };
  30.  
  31. BOOL CanStop( void ){
  32. /* return true if we can go to a stopped state from our current state */
  33.     return media.state==Playing || media.state==Paused;
  34. };
  35.  
  36. BOOL CanPause( void ){
  37. /* return true if we can go to a paused state from our current state */
  38.     return media.state==Playing || media.state==Stopped;
  39. };
  40.  
  41. BOOL IsInitialized( void ){
  42. /* return true if we have loaded and initialized a multimedia file */
  43.     return media.state!=Uninitialized;
  44. }
  45.  
  46. void ChangeStateTo( State newState ){
  47.     media.state = newState;
  48.  
  49.     // update the toolbar
  50.     UpdateToolbar();
  51.  
  52. }
  53.  
  54. /* Initialization */
  55. BOOL InitMedia( void ){
  56.     ChangeStateTo( Uninitialized );
  57.  
  58.     media.hGraphNotifyEvent = NULL;
  59.     media.pGraph = NULL;
  60.  
  61.     return TRUE;
  62. }
  63.  
  64. BOOL CreateFilterGraph( void ){
  65.     IMediaEvent *pME;
  66.     HRESULT hr; // return code
  67.  
  68.     ASSERT(media.pGraph == NULL);
  69.  
  70.     hr = CoCreateInstance( &CLSID_FilterGraph,          // get this documents graph object
  71.               NULL,
  72.               CLSCTX_INPROC_SERVER,
  73.               & IID_IGraphBuilder,
  74.               (void **) &media.pGraph);
  75.     if (FAILED(hr)){
  76.     media.pGraph = NULL;
  77.     return FALSE;
  78.     }
  79.  
  80.     // Set up an event file so that we can be notified when the
  81.     // graph stops playing
  82.  
  83.     hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaEvent, (void **) &pME);
  84.     if (FAILED(hr)) {
  85.     DeleteContents();
  86.     return FALSE;
  87.     }
  88.  
  89.     hr = pME->lpVtbl->GetEventHandle(pME, (OAEVENT*) &media.hGraphNotifyEvent);
  90.     pME->lpVtbl->Release( pME );
  91.  
  92.     if (FAILED(hr)) {
  93.     DeleteContents();
  94.     return FALSE;
  95.     }
  96.  
  97.     return TRUE;
  98. }
  99.  
  100. /* Destruction */
  101. void DeleteContents( void ){
  102.  
  103.     if (media.pGraph != NULL) {
  104.     media.pGraph->lpVtbl->Release( media.pGraph );
  105.     media.pGraph = NULL;
  106.     }
  107.  
  108.     // this event is owned by the filter graph and is thus invalid
  109.     media.hGraphNotifyEvent = NULL;
  110.  
  111.     ChangeStateTo( Uninitialized );
  112. }
  113.  
  114. BOOL RenderFile( LPSTR szFileName ){
  115.     HRESULT hr;
  116.     WCHAR wPath[MAX_PATH];
  117.  
  118.     DeleteContents();
  119.  
  120.     if ( !CreateFilterGraph() ) {
  121.     PlayerMessageBox( IDS_CANT_INIT_QUARTZ );
  122.     return FALSE;
  123.     }
  124.  
  125.     MultiByteToWideChar( CP_ACP, 0, szFileName, -1, wPath, MAX_PATH );
  126.  
  127.     SetCursor( LoadCursor( NULL, IDC_WAIT ) );
  128.     hr = media.pGraph->lpVtbl->RenderFile(media.pGraph, wPath, NULL);
  129.     SetCursor( LoadCursor( NULL, IDC_ARROW ) );
  130.  
  131.     if (FAILED( hr )) {
  132.     PlayerMessageBox( IDS_CANT_RENDER_FILE );
  133.     return FALSE;
  134.     }
  135.  
  136.     return TRUE;
  137.  
  138. }
  139.  
  140. void SetTitle( HWND hwnd, char *szFile ){
  141. /* Update the title of hwnd to "Player - szFile" */
  142.     char szNewTitle[ _MAX_FNAME + _MAX_EXT  + 20 ];
  143.  
  144.     strcpy( szNewTitle, APP_NAME );
  145.     strcat( szNewTitle, " - " );
  146.     strcat( szNewTitle, szFile );
  147.  
  148.     // Update the window's title
  149.     SetWindowText( hwnd, szNewTitle );
  150. }
  151.  
  152. void OpenMediaFile( HWND hwnd, LPSTR szFile ){
  153. /* File..Open has been selected */
  154.     static char szFileName[ _MAX_PATH ];
  155.     static char szTitleName[ _MAX_FNAME + _MAX_EXT ];
  156.  
  157.     if( szFile!=NULL && RenderFile( szFile ) ){
  158.     LPSTR szTitle;
  159.  
  160.     // Work out the full path name and the file name from the
  161.     // specified file
  162.     GetFullPathName( szFile, _MAX_PATH, szFileName, &szTitle );
  163.     strncpy( szTitleName, szTitle, _MAX_FNAME + _MAX_EXT );
  164.     szTitleName[ _MAX_FNAME + _MAX_EXT -1 ] = '\0';
  165.  
  166.     // Set the main window title and update the state
  167.     SetTitle( hwnd, szTitleName );
  168.     ChangeStateTo( Stopped );
  169.  
  170.     } else if( DoFileOpenDialog( hwnd, szFileName, szTitleName )
  171.            && RenderFile( szFileName ) ){
  172.  
  173.     // Set the main window title and update the state
  174.     SetTitle( hwnd, szTitleName );
  175.     ChangeStateTo( Stopped );
  176.  
  177.     }
  178.  
  179. }
  180.  
  181. /* Command handlers */
  182.  
  183. // there are two possible UI strategies: you either play from the start
  184. // each time you stop, or you play from the current position, in which
  185. // case you have to explicitly rewind at the end.
  186. // If you want the play from current and rewind at end, enable this code
  187. // if you want the other, then enable FROM_START in OnMediaStop and OnAbortStop.
  188. #undef REWIND
  189. #define FROM_START
  190. void OnMediaPlay( void ){
  191.     if( CanPlay() ){
  192.     HRESULT hr;
  193.     IMediaControl *pMC;
  194.  
  195.     // Obtain the interface to our filter graph
  196.     hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
  197.  
  198.     if( SUCCEEDED(hr) ){
  199. #ifdef REWIND
  200.         IMediaPosition * pMP;
  201.         hr = media.pGraph->lpVtbl->QueryInterface(
  202.             media.pGraph,
  203.             &IID_IMediaPosition,
  204.             (void**) &pMP);
  205.         if (SUCCEEDED(hr)) {
  206.         // start from last position, but rewind if near the
  207.         // end
  208.         REFTIME tCurrent, tLength;
  209.         hr = pMP->lpVtbl->get_Duration(pMP, &tLength);
  210.         if (SUCCEEDED(hr)) {
  211.             hr = pMP->lpVtbl->get_CurrentPosition(pMP, &tCurrent);
  212.             if (SUCCEEDED(hr)) {
  213.             // within 1sec of end? (or past end?)
  214.             if ((tLength - tCurrent) < 1) {
  215.                 pMP->lpVtbl->put_CurrentPosition(pMP, 0);
  216.             }
  217.             }
  218.         }
  219.         pMP->lpVtbl->Release(pMP);
  220.         }
  221. #endif
  222.  
  223.  
  224.         // Ask the filter graph to play and release the interface
  225.         hr = pMC->lpVtbl->Run( pMC );
  226.         pMC->lpVtbl->Release( pMC );
  227.  
  228.         if( SUCCEEDED(hr) ){
  229.         ChangeStateTo( Playing );
  230.         return;
  231.         }
  232.     }
  233.  
  234.     // Inform the user that an error occurred
  235.     PlayerMessageBox( IDS_CANT_PLAY );
  236.  
  237.     }   
  238. }
  239.  
  240. void OnMediaPause( void ){
  241.     if( CanPause() ){
  242.     HRESULT hr;
  243.     IMediaControl *pMC;
  244.  
  245.     // Obtain the interface to our filter graph
  246.     hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
  247.  
  248.     if( SUCCEEDED(hr) ){
  249.         // Ask the filter graph to pause and release the interface
  250.         hr = pMC->lpVtbl->Pause( pMC );
  251.         pMC->lpVtbl->Release( pMC );
  252.  
  253.         if( SUCCEEDED(hr) ){
  254.         ChangeStateTo( Paused );
  255.         return;
  256.         }
  257.     }
  258.  
  259.     // Inform the user that an error occurred
  260.     PlayerMessageBox( IDS_CANT_PAUSE );
  261.     }
  262.  
  263. }
  264.  
  265. // if you want the behaviour of playing from the beginning each time, then
  266. // define FROM_START. Otherwise see the ifdef REWIND above
  267. void OnMediaAbortStop(void)
  268. {
  269.     if(CanStop())
  270.     {
  271.     HRESULT hr;
  272.     IMediaControl *pMC;
  273.  
  274.     // Obtain the interface to our filter graph
  275.     hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
  276.  
  277.     if( SUCCEEDED(hr) ){
  278. #ifdef FROM_START
  279.         IMediaPosition * pMP;
  280. #endif
  281.         // Ask the filter graph to stop and release the interface
  282.         hr = pMC->lpVtbl->Stop( pMC );
  283.         pMC->lpVtbl->Release( pMC );
  284.  
  285. #ifdef FROM_START
  286.  
  287.         // if we want always to play from the beginning
  288.         // then we should seek back to the start here
  289.         // (on app or user stop request, and also after EC_COMPLETE).
  290.         hr = media.pGraph->lpVtbl->QueryInterface(
  291.             media.pGraph,
  292.             &IID_IMediaPosition,
  293.             (void**) &pMP);
  294.         if (SUCCEEDED(hr)) {
  295.         pMP->lpVtbl->put_CurrentPosition(pMP, 0);
  296.         pMP->lpVtbl->Release(pMP);
  297.         }
  298.  
  299.         // no visible rewind or we will re-show the window!
  300.  
  301. #endif
  302.  
  303.         if( SUCCEEDED(hr) ){
  304.         ChangeStateTo( Stopped );
  305.         return;
  306.         }
  307.     }
  308.     // Inform the user that an error occurred
  309.     PlayerMessageBox( IDS_CANT_STOP );
  310.     }
  311. }
  312.  
  313.  
  314. // There are two different ways to stop a graph. We can stop and then when we
  315. // are later paused or run continue from the same position. Alternatively the
  316. // graph can be set back to the start of the media when it is stopped to have
  317. // a more CDPLAYER style interface. These are both offered here conditionally
  318. // compiled using the FROM_START definition. The main difference is that in
  319. // the latter case we put the current position to zero while we change states
  320.  
  321. void OnMediaStop( void ){
  322.  
  323.     if( CanStop() ){
  324.     HRESULT hr;
  325.     IMediaControl *pMC;
  326.  
  327.     // Obtain the interface to our filter graph
  328.     hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaControl, (void **) &pMC);
  329.     if( SUCCEEDED(hr) ){
  330.  
  331. #ifdef FROM_START
  332.         IMediaPosition * pMP;
  333.         OAFilterState state;
  334.  
  335.         // Ask the filter graph to pause
  336.         hr = pMC->lpVtbl->Pause( pMC );
  337.  
  338.         // if we want always to play from the beginning
  339.         // then we should seek back to the start here
  340.         // (on app or user stop request, and also after EC_COMPLETE).
  341.         hr = media.pGraph->lpVtbl->QueryInterface(media.pGraph,
  342.                               &IID_IMediaPosition,
  343.                               (void**) &pMP);
  344.         if (SUCCEEDED(hr)) {
  345.         pMP->lpVtbl->put_CurrentPosition(pMP, 0);
  346.         pMP->lpVtbl->Release(pMP);
  347.         }
  348.  
  349.         // wait for pause to complete
  350.         pMC->lpVtbl->GetState(pMC, INFINITE, &state);
  351. #endif
  352.  
  353.         // now really do the stop
  354.         pMC->lpVtbl->Stop( pMC );
  355.         pMC->lpVtbl->Release( pMC );
  356.         ChangeStateTo( Stopped );
  357.         return;
  358.     }
  359.  
  360.     // Inform the user that an error occurred
  361.     PlayerMessageBox( IDS_CANT_STOP );
  362.     }
  363. }
  364.  
  365. HANDLE GetGraphEventHandle( void )
  366. {
  367.     return media.hGraphNotifyEvent;
  368.  
  369. }
  370.  
  371. //
  372. // If the event handle is valid, ask the graph
  373. // if anything has happened. eg the graph has stopped...
  374. void OnGraphNotify(void) {
  375.     IMediaEvent *pME;
  376.     long lEventCode, lParam1, lParam2;
  377.  
  378.     ASSERT( media.hGraphNotifyEvent != NULL );
  379.  
  380.     if( SUCCEEDED(media.pGraph->lpVtbl->QueryInterface(media.pGraph, &IID_IMediaEvent, (void **) &pME))){
  381.     if( SUCCEEDED(pME->lpVtbl->GetEvent(pME, &lEventCode, &lParam1, &lParam2, 0))) {
  382.         if (lEventCode == EC_COMPLETE) {
  383.         OnMediaStop();
  384.         } else if ((lEventCode == EC_USERABORT) ||
  385.                (lEventCode == EC_ERRORABORT)) {
  386.         OnMediaAbortStop();
  387.         }
  388.     }
  389.     pME->lpVtbl->Release( pME );
  390.     }
  391. }
  392.  
  393.