2009年10月30日 星期五

影片播放器


#pragma comment (lib, "comctl32.lib") 
#pragma comment (lib, "dxguid.lib")
#pragma comment (lib, "strmiids.lib")
#ifndef UNICODE
#define UNICODE
#endif
#define daviddr 090430
#include <windows.h>
#include <commctrl.h>
#include <dshow.h>

#include <cstdio>
extern"C" WINBASEAPI HWND WINAPI GetConsoleWindow();
#define MsgBox(s) MessageBox (0,s,0,MB_OK)

WCHAR e_str[256];
void cdecl MsgBox_ (wchar_t* fmt, ...)
   {swprintf_s (e_str, 256, fmt, (char*)(&fmt+1)); MsgBox(e_str);}

namespace FileDlg
{
    WCHAR title[256] = L"*.*";
    WCHAR filter[256] = 
        L"AVI File (*.avi)\0*.avi\0"   
        L"MPEG File (*.mpg)\0*.mpg\0"   
        L"Mp3 File (*.mp3)\0*.mp3\0"   
        L"Wave File (*.wav)\0*.wav\0"   
        L"All Files (*.*)\0*.*\0\0";
    WCHAR file_name[512], init_dir[512], exe_path[512]={0}, *fname;
    OPENFILENAME ofn = {
            sizeof(OPENFILENAME), 0, 0, (LPCWSTR)filter,0,0,1, title, 
            512, file_name, 512, init_dir, 0, 6, 0,1, L"", 0,0,0
    };
    LPWSTR open (HWND hwnd)
    {
        ofn.hwndOwner    = hwnd;
        ofn.lpstrTitle   = L"開檔"; 
        ofn.lpstrFilter  = filter;
        ofn.Flags        = 6; 
        ofn.lpstrFile[0] = 0;               //若開檔後仍為0表示按了[Cancel]

        if (!GetOpenFileName (&ofn)) { 
            if(*ofn.lpstrFile) 
                MsgBox_ (L"Fail to open: %d", CommDlgExtendedError()); 
            return 0;
        }
        return fname = ofn.lpstrFile;       //取個短名字        
    }
}


#define DO(b) if (FAILED(b)) \
              {MsgBox_(L"fail in %s line %d",__FILE__,__LINE__);}


struct Player
{
    bool bPlaying; 
    long evCode;
    LONGLONG pos, duration;           
    IMediaEvent*   pEvent;
    IGraphBuilder* pGraph;
    IMediaControl* pCtrl;
    IVideoWindow*  pVideo;
    IMediaSeeking* pSeek;

    void init()
    {
        bPlaying = false;
        DO (CoCreateInstance (CLSID_FilterGraph, 0, CLSCTX_INPROC, 
                        IID_IGraphBuilder, (void**) &pGraph));
        DO (pGraph->QueryInterface (IID_IMediaControl, (void**) &pCtrl));
        DO (pGraph->QueryInterface (IID_IVideoWindow,  (void**) &pVideo));
        DO (pGraph->QueryInterface (IID_IMediaEvent,   (void**) &pEvent));
        DO (pGraph->QueryInterface (IID_IMediaSeeking, (void**) &pSeek));
    }
    void free()
    {
        if (bPlaying) {
            setTimeInfo (0);
            pCtrl->Stop();
        }
        pVideo->put_Visible (OAFALSE);
        pVideo->put_Owner (0);
        pSeek->Release();
        pCtrl->Release();
        pGraph->Release();        
    }
    void run (WCHAR* path, HWND hwnd)
    {
        bPlaying = true;
        DO (pGraph->RenderFile (path, 0));
        DO (pVideo->put_Owner ((OAHWND)hwnd));
        resize (hwnd);
        DO (pCtrl->Run());
    }
    void resize (HWND hwnd)
    {
        if (!bPlaying) return;
        RECT rc; GetClientRect (hwnd, &rc);
        DO (pVideo->put_WindowStyle (WS_CHILD| WS_CLIPSIBLINGS));
        DO (pVideo->SetWindowPosition (0, 0, rc.right, rc.bottom-20));
    }
    void getTimeInfo()
    {
        pSeek->GetCurrentPosition (&pos);
        pSeek->GetDuration (&duration);   
    }
    void setTimeInfo (double pos_)
    {
        LONGLONG duration = 1;
        pSeek->GetDuration (&duration);
        duration *= pos_;
        pSeek->SetPositions (&duration,
            AM_SEEKING_AbsolutePositioning,
            NULL, AM_SEEKING_NoPositioning);
    }
    void pause (bool b) {b?pCtrl->Pause():pCtrl->Run();}
};

//-------------------------- 主程式 -------------------------------

HINSTANCE  e_hInst;

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static enum {ID_TIMER, ID_OPEN, ID_PAUSE, ID_SLIDER};
    static bool bPause;
    static int w,h;
    static Player player;
    static HMENU  hMenu;  
    static HWND   hSlider;             //scroll handle
    
    switch (msg)
    {
      case WM_CREATE:
           hMenu = (HMENU) CreateMenu();
           AppendMenu (hMenu, MF_STRING, ID_OPEN,  L"開檔");
           AppendMenu (hMenu, MF_STRING, ID_PAUSE, L"暫停");
           SetMenu (hwnd, hMenu);
           hSlider = CreateWindow (TRACKBAR_CLASS, L"",
                     WS_CHILD| WS_VISIBLE| TBS_AUTOTICKS, 216,4,256,16,
                     hwnd, (HMENU)ID_SLIDER, e_hInst, 0);
           SendMessage (hSlider, TBM_SETRANGE, TRUE, MAKELONG(1,1000));
           SendMessage (hSlider, TBM_SETPOS, TRUE, 1);
           return 0;

      case WM_CLOSE:           
           if (player.bPlaying) {
               player.free();
               KillTimer (hwnd, ID_TIMER);                   
           }
           PostQuitMessage(0);
           return 0;  

      case WM_SIZE:
           player.resize (hwnd);
           w = LOWORD (lParam);
           h = HIWORD (lParam);
           MoveWindow (hSlider, 2, h-20, w-4, 20, TRUE);     
           return 0;

      case WM_KEYDOWN:
           switch (wParam) {
             case VK_ESCAPE: SendMessage (hwnd, WM_CLOSE, 0, 0); break;
             case VK_RETURN: player.pause (bPause = !bPause); break;
           }
           return 0;

      case WM_HSCROLL:
           player.setTimeInfo (
               double(SendMessage (hSlider, TBM_GETPOS, 0, 0))/1000);
           return 0;

      case WM_TIMER:
           player.getTimeInfo();
           SendMessage (hSlider, TBM_SETPOS, TRUE,
               player.pos * 1000 / player.duration);
           return 0;

      case WM_COMMAND:
           if (ID_OPEN == LOWORD(wParam)) {           
               if (FileDlg::open (hwnd)) {               //若開檔成功
                   if (player.bPlaying) {                //關閉計時器
                       player.free();
                       KillTimer (hwnd, ID_TIMER);
                   }
                   bPause = false;
                   swprintf_s (e_str, L"%s", FileDlg::fname);
                   SetWindowText (hwnd, e_str);   
                   player.init();           
                   player.run (FileDlg::fname, hwnd);
                   SetTimer (hwnd, ID_TIMER, 20, 0);     //啟動計時器
               }    
           }else if (ID_PAUSE == LOWORD(wParam))           
               player.pause (bPause = !bPause);
           return 0;
          
      default: return  DefWindowProc (hwnd, msg, wParam, lParam);
    }
    return 0;          
}

int WINAPI WinMain (HINSTANCE hInst, HINSTANCE, PSTR, int nShow)
{
    CoInitialize (0);            
    WNDCLASSEX wc = {0x30,3,WndProc,0,0,hInst,0,0,(HBRUSH)1,0,L"DS",0};
    if (!RegisterClassEx(&wc)) return 0;  
    HWND hwnd = CreateWindow (L"DS",L"Player",
        13565952,100,50,560,500,0,0,hInst,0);
    if (!hwnd) return 0;  
    e_hInst = hInst;
    MSG msg; ShowWindow (hwnd, nShow);
    while (GetMessage (&msg, 0,0,0)) {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    CoUninitialize();
    return msg.wParam;
}

沒有留言:

張貼留言