bgmusic.cpp
上传用户:quanyuan
上传日期:2022-04-13
资源大小:19k
文件大小:18k
源码类别:

mpeg/mp3

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // File: BGMusic.cpp
  3. //
  4. // Desc: A simple playback applicaiton that plays a cyclic set of media
  5. //       files of the same type. This is the code required to use DirectShow
  6. //       to play compressed audio in the background of your title in a
  7. //       seamless manner.
  8. //
  9. // Copyright (c) Microsoft Corporation. All rights reserved.
  10. //------------------------------------------------------------------------------
  11. #include <windows.h>
  12. #include <dshow.h>
  13. #include <tchar.h>
  14. #include <atlbase.h>
  15. #include "resource.h"
  16. //------------------------------------------------------------------------------
  17. // Forward Declarations
  18. //------------------------------------------------------------------------------
  19. HRESULT GraphInit(void);
  20. HRESULT SwapSourceFilter(void); 
  21. HWND AppInit(HINSTANCE hInstance);
  22. void AppMessageLoop(void);
  23. void AppCleanUp(void);
  24. void ShowCurrentFile(HWND hWnd);
  25. const TCHAR* DXUtil_GetDXSDKMediaPath();
  26. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  27. VOID CALLBACK MyTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);
  28. void AddAboutMenuItem(HWND hWnd);
  29. LRESULT CALLBACK AboutDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  30. //------------------------------------------------------------------------------
  31. // Macros
  32. //------------------------------------------------------------------------------
  33. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  34. //------------------------------------------------------------------------------
  35. // Constants
  36. //------------------------------------------------------------------------------
  37. #define CLASSNAME       TEXT("BGMusicPlayer")
  38. #define APPNAME         TEXT("BGMusic Player")
  39. #define APPWIDTH        200
  40. #define APPHEIGHT       100
  41. #define MEDIA_TIMEOUT   (10 * 1000)  // 10 seconds, represented in milliseconds
  42. //------------------------------------------------------------------------------
  43. // Global Variables
  44. //------------------------------------------------------------------------------
  45. // DirectShow Graph, Filter & Pins used
  46. IGraphBuilder *g_pGraphBuilder  = NULL;
  47. IMediaControl *g_pMediaControl  = NULL;
  48. IMediaSeeking *g_pMediaSeeking  = NULL;
  49. IBaseFilter   *g_pSourceCurrent = NULL;
  50. IBaseFilter   *g_pSourceNext    = NULL;
  51. TCHAR          g_szCurrentFile[128];
  52. HWND           g_hwndApp=0;
  53. HINSTANCE      g_hInstance=0;
  54. // File names & variables to track current file
  55. // These files are installed with the DirectX SDK into the samples media folder
  56. LPCTSTR pstrFiles[] = 
  57. {
  58.     TEXT("track1.mp3"),
  59.     TEXT("track2.mp3"),
  60.     TEXT("track3.mp3"),
  61. };
  62. int g_iNumFiles = 3, g_iNextFile = 0;
  63. //------------------------------------------------------------------------------
  64. // Name: WinMain()
  65. // Desc: Main Entry point for the app. Calls the Initialization routines and
  66. //       then calls the main processing loop.
  67. //------------------------------------------------------------------------------
  68. int APIENTRY WinMain(HINSTANCE hInstance,
  69.                      HINSTANCE hPrevInstance,
  70.                      LPSTR     lpCmdLine,
  71.                      int       nCmdShow)
  72. {
  73.     // Initialize application window
  74.     if(! AppInit(hInstance))
  75.         return 0;
  76.     // Initialize DirectShow components and build initial graph
  77.     if(SUCCEEDED(GraphInit()))
  78.     {
  79.         // Main Message Loop
  80.         AppMessageLoop();
  81.     }
  82.     // Clean up
  83.     AppCleanUp();
  84.     return 0;
  85. }
  86. //------------------------------------------------------------------------------
  87. // Name: GraphInit()
  88. // Desc: Initialization of DirectShow components and initial graph
  89. //------------------------------------------------------------------------------
  90. HRESULT GraphInit(void)
  91. {
  92.     HRESULT hr;
  93.     // Initialize COM
  94.     if(FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
  95.         return hr;
  96.     // Create DirectShow Graph
  97.     if(FAILED(hr = CoCreateInstance(CLSID_FilterGraph, NULL,
  98.         CLSCTX_INPROC, IID_IGraphBuilder,
  99.         reinterpret_cast<void **>(&g_pGraphBuilder))))
  100.         return hr;
  101.     // Get the IMediaControl Interface
  102.     if(FAILED(hr = g_pGraphBuilder->QueryInterface(IID_IMediaControl,
  103.         reinterpret_cast<void **>(&g_pMediaControl))))
  104.         return hr;
  105.     // Get the IMediaControl Interface
  106.     if(FAILED(hr = g_pGraphBuilder->QueryInterface(IID_IMediaSeeking,
  107.         reinterpret_cast<void **>(&g_pMediaSeeking))))
  108.         return hr;
  109.     // Create Source Filter for first file
  110.     g_iNextFile = 0;
  111.     // Create the intial graph
  112.     if(FAILED(hr = SwapSourceFilter()))
  113.         return hr;
  114.     // Set a timer for switching the sources
  115.     if(!SetTimer(g_hwndApp, 0, MEDIA_TIMEOUT, (TIMERPROC) MyTimerProc))
  116.         return E_FAIL;
  117.     return S_OK;
  118. }
  119. //------------------------------------------------------------------------------
  120. // Name: AppInit()
  121. // Desc: Initialization of application window
  122. //------------------------------------------------------------------------------
  123. HWND AppInit(HINSTANCE hInstance)
  124. {
  125.     WNDCLASS wc;
  126.     // Register the window class
  127.     ZeroMemory(&wc, sizeof wc);
  128.     wc.lpfnWndProc   = WndProc;
  129.     wc.hInstance     = hInstance;
  130.     wc.lpszClassName = CLASSNAME;
  131.     wc.lpszMenuName  = NULL;
  132.     wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  133.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  134.     wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BGMUSIC));
  135.     if(!RegisterClass(&wc))
  136.         return 0;
  137.     // Create the main window without support for resizing
  138.     g_hwndApp = CreateWindow(CLASSNAME, APPNAME,
  139.                              WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
  140.                                            | WS_MINIMIZEBOX | WS_VISIBLE,
  141.                              CW_USEDEFAULT, CW_USEDEFAULT,
  142.                              APPWIDTH, APPHEIGHT,
  143.                              0, 0, hInstance, 0);
  144.     // Add a menu item to the app's system menu
  145.     AddAboutMenuItem(g_hwndApp);
  146.     g_hInstance = hInstance;
  147.     return g_hwndApp;
  148. }
  149. //------------------------------------------------------------------------------
  150. // Name: WndProcLoop()
  151. // Desc: Main Message Processor for the Application
  152. //------------------------------------------------------------------------------
  153. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  154. {
  155.     switch(message)
  156.     {
  157.         case WM_PAINT:
  158.             ShowCurrentFile(hWnd);
  159.             break;
  160.         case WM_CLOSE:
  161.         case WM_DESTROY:
  162.             PostQuitMessage(0);
  163.             break;
  164.         case WM_SYSCOMMAND:
  165.         {
  166.             switch (wParam)
  167.             {
  168.                 case IDM_ABOUTBOX:
  169.                     DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, 
  170.                              (DLGPROC) AboutDlgProc);
  171.             }
  172.             break;
  173.         }
  174.     }
  175.     return DefWindowProc(hWnd, message, wParam, lParam);
  176. }
  177. //------------------------------------------------------------------------------
  178. // Name: AppMessageLoop()
  179. // Desc: Main Message Loop for the Application
  180. //------------------------------------------------------------------------------
  181. void AppMessageLoop(void)
  182. {
  183.     MSG msg;
  184.     BOOL bRet = 0;
  185.     // Main message loop:
  186.     while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
  187.     {
  188.         if(bRet == -1)     // Error in GetMessage
  189.             break;
  190.         TranslateMessage(&msg) ;
  191.         DispatchMessage(&msg) ;
  192.     }
  193.     return;
  194. }
  195. //------------------------------------------------------------------------------
  196. // Name: AppCleanUp)
  197. // Desc: Clean up the application
  198. //------------------------------------------------------------------------------
  199. void AppCleanUp(void)
  200. {
  201.     // Stop playback
  202.     if(g_pMediaControl)
  203.         g_pMediaControl->Stop();
  204.     // Release all remaining pointers
  205.     SAFE_RELEASE(g_pSourceNext);
  206.     SAFE_RELEASE(g_pSourceCurrent);
  207.     SAFE_RELEASE(g_pMediaSeeking);
  208.     SAFE_RELEASE(g_pMediaControl);
  209.     SAFE_RELEASE(g_pGraphBuilder);
  210.     // Clean up COM
  211.     CoUninitialize();
  212.     return;
  213. }
  214. //------------------------------------------------------------------------------
  215. // MyTimerProc - Callback when the timer goes off
  216. //------------------------------------------------------------------------------
  217. VOID CALLBACK MyTimerProc(
  218.                           HWND hwnd,     // handle to window
  219.                           UINT uMsg,     // WM_TIMER message
  220.                           UINT idEvent,  // timer identifier
  221.                           DWORD dwTime   // current system time
  222. )
  223. {
  224.     SwapSourceFilter();
  225.     // Update the "current file" text message
  226.     RECT rc;
  227.     GetWindowRect(hwnd, &rc);
  228.     InvalidateRect(hwnd, &rc, TRUE);
  229. }
  230. //------------------------------------------------------------------------------
  231. // Name: ShowCurrentFile()
  232. // Desc: Display the currently playing media file in the main window
  233. //------------------------------------------------------------------------------
  234. void ShowCurrentFile(HWND hWnd)
  235. {
  236.     PAINTSTRUCT ps;
  237.     RECT rc;
  238.     TCHAR szMsg[128];
  239.     BeginPaint(hWnd, &ps);
  240.     HDC hdc = GetDC(hWnd);
  241.     GetWindowRect(hWnd, &rc);
  242.     // Set the text color to bright green against black background
  243.     SetTextColor(hdc, RGB(80, 255, 80));
  244.     SetBkColor(hdc, RGB(0,0,0));
  245.     // Decide where to place the text (centered in window)
  246.     int X = (rc.right - rc.left) / 2;
  247.     int Y = (rc.bottom - rc.top) / 3;
  248.     SetTextAlign(hdc, TA_CENTER | VTA_CENTER);
  249.     // Update the text string
  250.     wsprintf(szMsg, _T("Playing %s"), g_szCurrentFile);
  251.     ExtTextOut(hdc, X, Y, (UINT) ETO_OPAQUE, NULL, 
  252.                szMsg, (UINT) _tcslen(szMsg), 0);
  253.     EndPaint(hWnd, &ps);
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Name: AboutDlgProc()
  257. // Desc: Message handler for About box
  258. //-----------------------------------------------------------------------------
  259. LRESULT CALLBACK AboutDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  260. {
  261.     switch (message)
  262.     {
  263.         case WM_INITDIALOG:
  264.             return TRUE;
  265.         case WM_COMMAND:
  266.             if (wParam == IDOK)
  267.             {
  268.                 EndDialog(hWnd, TRUE);
  269.                 return TRUE;
  270.             }
  271.             break;
  272.     }
  273.     return FALSE;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Name: AddAboutMenuItem()
  277. // Desc: Adds a menu item to the end of the app's system menu
  278. //-----------------------------------------------------------------------------
  279. void AddAboutMenuItem(HWND hWnd)
  280. {
  281.     // Add About box menu item
  282.     HMENU hwndMain = GetSystemMenu(hWnd, FALSE);
  283.     // Add separator
  284.     BOOL rc = AppendMenu(hwndMain, MF_SEPARATOR, 0, NULL);
  285.     // Add menu item
  286.     rc = AppendMenu(hwndMain, MF_STRING | MF_ENABLED, 
  287.                     IDM_ABOUTBOX,
  288.                     TEXT("About BGMusic..."));
  289. }
  290. //------------------------------------------------------------------------------
  291. // Name: SwapSourceFilter()
  292. // Desc: This routine is used to change the source file in the current graph.
  293. //       First the graph is stopped, then the current source filter is removed.
  294. //       The new source filter is added, the output pin on this filter is
  295. //       rendered, and playback is restarted.
  296. //
  297. //       When this routine is called during initialization, there is no
  298. //       currently running graph. In that case, Stop becomes a no-op. The source
  299. //       filter is added to an empty graph. Then during the render call, all
  300. //       necessary filters required to play this source are added to the graph.
  301. //
  302. //       On subsequent calls, Stopping the graph allows filters to be removed.
  303. //       When the old source filter is removed, all other filters are still
  304. //       left in the graph. The new source filter is added, and then the render
  305. //       operation reconnects the graph. Since all of the necessary filters for
  306. //       playback are already in the graph (if the two files have the same file
  307. //       type), these filters are reused. Existing filters in the graph are
  308. //       always used first, if possible, during a Render operation. This avoids
  309. //       having to create new filter instances with each change.
  310. //------------------------------------------------------------------------------
  311. HRESULT SwapSourceFilter(void)
  312. {
  313.     HRESULT hr = S_OK;
  314.     IPin *pPin = NULL;
  315.     int nNextFileIndex=0;
  316.     TCHAR szFilename[MAX_PATH];
  317.     WCHAR wFileName[MAX_PATH];
  318.     // Determine the file to load based on DirectX Media path (from SDK)
  319.     nNextFileIndex = g_iNextFile % g_iNumFiles;
  320.     _tcsncpy(szFilename, DXUtil_GetDXSDKMediaPath(), NUMELMS(szFilename));
  321.     _tcscat(szFilename, pstrFiles[nNextFileIndex]);
  322.     szFilename[MAX_PATH-1] = 0;     // Ensure NULL termination
  323.     _tcsncpy(g_szCurrentFile, pstrFiles[nNextFileIndex], NUMELMS(g_szCurrentFile));
  324.     g_iNextFile++;
  325.     // Make sure that this file exists
  326.     DWORD dwAttr = GetFileAttributes(szFilename);
  327.     if(dwAttr == (DWORD) -1)
  328.     {
  329.         TCHAR szMsg[MAX_PATH + 64];
  330.         wsprintf(szMsg, TEXT("Can't find the media file [%s]."), szFilename);
  331.         MessageBox(NULL, szMsg, TEXT("BGMusic Sample Error"), MB_OK | MB_ICONEXCLAMATION);
  332.         return E_FAIL;
  333.     }
  334.     USES_CONVERSION;
  335.     wcsncpy(wFileName, T2W(szFilename), MAX_PATH);
  336.     // OPTIMIZATION OPPORTUNITY
  337.     // This will open the file, which is expensive. To optimize, this
  338.     // should be done earlier, ideally as soon as we knew this was the
  339.     // next file to ensure that the file load doesn't add to the
  340.     // filter swapping time & cause a hiccup.
  341.     //
  342.     // Add the new source filter to the graph. (Graph can still be running)
  343.     hr = g_pGraphBuilder->AddSourceFilter(wFileName, wFileName, &g_pSourceNext);
  344.     // Get the first output pin of the new source filter. Audio sources 
  345.     // typically have only one output pin, so for most audio cases finding 
  346.     // any output pin is sufficient.
  347.     if(SUCCEEDED(hr))
  348.     {
  349.         hr = g_pSourceNext->FindPin(L"Output", &pPin);  
  350.     }
  351.     // Stop the graph
  352.     if(SUCCEEDED(hr))
  353.     {
  354.         hr = g_pMediaControl->Stop();
  355.     }
  356.     // Break all connections on the filters. You can do this by adding 
  357.     // and removing each filter in the graph
  358.     if(SUCCEEDED(hr))
  359.     {
  360.         IEnumFilters *pFilterEnum = NULL;
  361.         if(SUCCEEDED(hr = g_pGraphBuilder->EnumFilters(&pFilterEnum)))
  362.         {
  363.             int iFiltCount = 0;
  364.             int iPos = 0;
  365.             // Need to know how many filters. If we add/remove filters during the
  366.             // enumeration we'll invalidate the enumerator
  367.             while(S_OK == pFilterEnum->Skip(1))
  368.             {
  369.                 iFiltCount++;
  370.             }
  371.             // Allocate space, then pull out all of the 
  372.             IBaseFilter **ppFilters = reinterpret_cast<IBaseFilter **>
  373.                                       (_alloca(sizeof(IBaseFilter *) * iFiltCount));
  374.             pFilterEnum->Reset();
  375.             while(S_OK == pFilterEnum->Next(1, &(ppFilters[iPos++]), NULL));
  376.             SAFE_RELEASE(pFilterEnum);
  377.             for(iPos = 0; iPos < iFiltCount; iPos++)
  378.             {
  379.                 g_pGraphBuilder->RemoveFilter(ppFilters[iPos]);
  380.                 // Put the filter back, unless it is the old source
  381.                 if(ppFilters[iPos] != g_pSourceCurrent)
  382.                 {
  383.                     g_pGraphBuilder->AddFilter(ppFilters[iPos], NULL);
  384.                 }
  385.                 SAFE_RELEASE(ppFilters[iPos]);
  386.             }
  387.         }
  388.     }
  389.     // We have the new output pin. Render it
  390.     if(SUCCEEDED(hr))
  391.     {
  392.         // Release the old source filter, if it exists
  393.         SAFE_RELEASE(g_pSourceCurrent)
  394.         hr = g_pGraphBuilder->Render(pPin);
  395.         g_pSourceCurrent = g_pSourceNext;
  396.         g_pSourceNext = NULL;
  397.     }
  398.     SAFE_RELEASE(pPin);
  399.     SAFE_RELEASE(g_pSourceNext); // In case of errors
  400.     // Re-seek the graph to the beginning
  401.     if(SUCCEEDED(hr))
  402.     {
  403.         LONGLONG llPos = 0;
  404.         hr = g_pMediaSeeking->SetPositions(&llPos, AM_SEEKING_AbsolutePositioning,
  405.                                            &llPos, AM_SEEKING_NoPositioning);
  406.     } 
  407.     // Start the graph
  408.     if(SUCCEEDED(hr))
  409.     {
  410.         hr = g_pMediaControl->Run();
  411.     }
  412.     return S_OK;   
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Name: DXUtil_GetDXSDKMediaPath()
  416. // Desc: Returns the DirectX SDK media path
  417. //-----------------------------------------------------------------------------
  418. const TCHAR* DXUtil_GetDXSDKMediaPath()
  419. {
  420.     static TCHAR strNull[2] = _T("");
  421.     static TCHAR strPath[MAX_PATH + 10];
  422.     HKEY  hKey;
  423.     DWORD type, size=MAX_PATH;
  424.     // Open the appropriate registry key
  425.     LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  426.                                _T("Software\Microsoft\DirectX SDK"),
  427.                                0, KEY_READ, &hKey);
  428.     if(ERROR_SUCCESS != result)
  429.         return strNull;
  430.     result = RegQueryValueEx(hKey, _T("DX9J3SDK Samples Path"), NULL,
  431.                              &type, (BYTE*)strPath, &size);
  432.     if(ERROR_SUCCESS != result)
  433.     {
  434.         result = RegQueryValueEx(hKey, _T("DX81SDK Samples Path"), NULL,
  435.                                  &type, (BYTE*)strPath, &size);
  436.         if(ERROR_SUCCESS != result)
  437.         {
  438.             result = RegQueryValueEx(hKey, _T("DX8SDK Samples Path"), NULL,
  439.                                      &type, (BYTE*)strPath, &size);
  440.             if(ERROR_SUCCESS != result)
  441.             {
  442.                 RegCloseKey(hKey);
  443.                 return strNull;
  444.             }
  445.         }
  446.     }
  447.     RegCloseKey(hKey);
  448.     lstrcat(strPath, _T("\Media\"));
  449.     return strPath;
  450. }