123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583 |
- //
- // This file contains code that supports an alternate method playing dshow data...
- // This will have dshow take control of rendering the data (audio or video).
- // Used for mms streams
- //
- #ifdef WINAMPX
- #include <windows.h>
- #include <math.h>
- #include "message.h"
- #include "../jnetlib/jnetlib.h"
- #include "in2.h"
- #include <AtlBase.h>
- #include <streams.h>
- #include <qedit.h>
- #include <qnetwork.h>
- #ifdef DEFGUID
- #include <initguid.h> // declares DEFINE_GUID to declare an EXTERN_C const.
- #endif
- #define IPC_GET_IVIDEOOUTPUT 500
- // Externs
- extern HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister);
- extern void RemoveFromRot(DWORD pdwRegister);
- extern bool ReportMissingCodec(char *fn);
- extern In_Module mod; // the output module (filled in near the bottom of this file)
- extern char lastfn[MAX_PATH]; // currently playing file (used for getting info on the current file)
- extern char lastfn_status[256];
- extern int file_length; // file length, in bytes
- extern int decode_pos_ms; // current decoding position, in milliseconds.
- extern int paused; // are we paused?
- extern volatile int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
- extern int m_length;
- extern int paused; // are we paused?
- extern bool s_using_dsr;
- // Static Vars and Defines
- class IVideoOutput
- {
- public:
- virtual ~IVideoOutput() { }
- virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0;
- virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { }
- virtual void close()=0;
- virtual void draw(void *frame)=0;
- virtual void drawSubtitle(/*SubsItem **/ void *item) { }
- virtual void showStatusMsg(const char *text) { }
- virtual int get_latency() { return 0; }
- virtual void notifyBufferState(int bufferstate) { } /* 0-255*/
-
- virtual int extended(int param1, int param2, int param3) { return 0; } // Dispatchable, eat this!
- };
- static IVideoOutput * m_video_output;
- static CComPtr<IGraphBuilder> s_pGraphBuilder;
- static CComPtr<IMediaEventEx> s_pMediaEventEx;
- static CComPtr<IMediaControl> s_pMediaControl;
- static CComPtr<IVideoWindow> s_pVideoWindow;
- static CComPtr<IBasicAudio> s_pBasicAudio;
- static CComPtr<IBasicVideo> s_pBasicVideo;
- static CComPtr<IMediaSeeking> s_pMediaSeeking;
- static HWND s_dsr_notif_hwnd = NULL;
- static HWND s_hVideoWnd = NULL;
- static WNDPROC s_OriginalVideoWndProc = NULL;
- static RECT s_parentRect;
- static DWORD GraphEdit_dwRegister = 0;
- static int s_buffering = 0;
- static int s_bufferstat = 0;
- static BOOL s_bAudioOnly;
- static int s_setVolumeOnStart = -1;
- // Forward Declarations
- LRESULT CALLBACK dsr_TimerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- LRESULT CALLBACK dsr_SubclassParentWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- void dsr_setvolume(int volume);
- void dsr_handleNotifyEvents();
- void dsr_stop();
- // Macros
- #define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \
- {CComPtr<IEnumFilters> pEnumFilters; \
- if(pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) \
- { \
- for(CComPtr<IBaseFilter> pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = NULL) \
- { \
-
- #define EndEnumFilters }}}
- static void SendStatus(int status, int arg ) {
- mod.fire_winampstatus( status, arg );
- }
- //------------------------------------------------------------------------------
- // Name: CheckVisibility()
- // Desc: Set global values for presence of video window.
- //------------------------------------------------------------------------------
- bool CheckVisibility(void) // returns false for failure
- {
- HRESULT hr;
- if ((!s_pVideoWindow) || (!s_pBasicVideo))
- {
- s_bAudioOnly = TRUE; // Audio-only files have no video interfaces.
- return TRUE;
- }
- s_bAudioOnly = FALSE;
- long lVisible;
- hr = s_pVideoWindow->get_Visible(&lVisible); // If this is an audio-only clip, get_Visible() won't work.
- if ((FAILED(hr)) && (hr == E_NOINTERFACE))
- {
- s_bAudioOnly = TRUE;
- return TRUE;
- }
- return !FAILED(hr);
- }
- static RECT fitMediaToWindow(RECT rectWindow, int mediaWidth, int mediaHeight)
- {
- RECT retval;
- int windowWidth = rectWindow.right - rectWindow.left;
- int windowHeight = rectWindow.bottom - rectWindow.top;
- if (mediaHeight*windowWidth > mediaWidth*windowHeight)
- {
- // Gap is on left&right sides
- int nOutWidth = windowHeight* mediaWidth / mediaHeight;
- int nGap = (windowWidth - nOutWidth)/2;
- retval.top = rectWindow.top;
- retval.bottom = retval.top + windowHeight;
- retval.left = rectWindow.left + nGap;
- retval.right = retval.left + nOutWidth;
- }
- else
- {
- // Gap is on the top/bottom sides
- int nOutHeight = windowWidth* mediaHeight / mediaWidth;
- int nGap = (windowHeight - nOutHeight)/2;
- retval.left = rectWindow.left;
- retval.right = retval.left + windowWidth;
- retval.top = rectWindow.top + nGap;
- retval.bottom = retval.top + nOutHeight;
- }
- return retval;
- }
- void dsr_releaseObjects()
- {
- if(s_dsr_notif_hwnd)
- {
- KillTimer(s_dsr_notif_hwnd,112);
- DestroyWindow(s_dsr_notif_hwnd);
- }
- s_dsr_notif_hwnd=NULL;
- if ((s_OriginalVideoWndProc) && (s_hVideoWnd))
- {
- SetWindowLong(s_hVideoWnd, GWL_WNDPROC, (LONG_PTR)s_OriginalVideoWndProc);
- s_OriginalVideoWndProc = NULL;
- s_hVideoWnd = NULL;
- }
- s_pMediaEventEx = NULL;
- s_pGraphBuilder = NULL;
- s_pMediaControl = NULL;
- s_pVideoWindow = NULL;
- s_pBasicAudio = NULL;
- s_pBasicVideo = NULL;
- s_pMediaSeeking = NULL;
- s_using_dsr = false;
- }
- // Prefix used for functions here are dsd_ (
- int dsr_play(char *fn)
- {
- HRESULT hr;
-
- hr = s_pGraphBuilder.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);
- if (FAILED(hr)) return 1;
- #ifdef _DEBUG
- AddToRot(s_pGraphBuilder, &GraphEdit_dwRegister);
- #endif
- s_pGraphBuilder->QueryInterface(IID_IMediaEvent, (void **)&s_pMediaEventEx);
- if(!s_pMediaEventEx)
- {
- dsr_releaseObjects();
- return 1;
- }
-
- m_video_output=(IVideoOutput *)SendMessage(mod.hMainWindow,WM_USER,0,IPC_GET_IVIDEOOUTPUT);
- if(!m_video_output)
- {
- dsr_releaseObjects();
- return -200; // Can't play file
- }
- // Create window that will receive filter notifications
- static int classReg=0;
- if(!classReg)
- {
- WNDCLASS wc={0,};
- wc.style = CS_DBLCLKS;
- wc.lpfnWndProc = dsr_TimerWndProc;
- wc.hInstance = mod.hDllInstance;
- wc.hIcon = NULL;
- wc.hCursor = NULL;
- wc.lpszClassName = "in_dshowClass2";
- if (!RegisterClass(&wc))
- {
- dsr_releaseObjects();
- return 1;
- }
- classReg=1;
- }
- s_dsr_notif_hwnd=CreateWindow("in_dshowClass2","dshow_notif2",NULL,0,0,1,1,NULL,NULL,mod.hDllInstance,NULL);
- SetTimer(s_dsr_notif_hwnd,112,500,0);
- // Build a normal graph (start rendering)
- WCHAR f[4096];
- MultiByteToWideChar(CP_ACP,0,fn,lstrlen(fn)+1,f,4096);
- hr = s_pGraphBuilder->RenderFile(f,NULL);
- if (FAILED(hr)) {
- dsr_handleNotifyEvents();
- dsr_releaseObjects();
- if ((hr == CLASS_E_CLASSNOTAVAILABLE) || (hr == VFW_E_UNSUPPORTED_VIDEO) || (hr == VFW_E_NO_DECOMPRESSOR))
- {
- if (ReportMissingCodec(fn)) // returns true if we sent a message
- return -500; // Unsupported format
- return -200; // Can't play file
- }
- return 1;
- }
- // Check if it's a partial playing of the file (likely video codec missing)
- if ((hr == VFW_S_PARTIAL_RENDER) || (hr == VFW_S_VIDEO_NOT_RENDERED))
- {
- if (!ReportMissingCodec(fn)) // Report the missing codec if we can determine it
- mod.fire_winampstatus(WINAMPX_STATUS_MISSING_AVI_CODEC, 0); // If we can't report a null codec missing
- }
-
- if (FAILED(s_pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&s_pMediaControl)) ||
- FAILED(s_pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void **)&s_pMediaSeeking)) ||
- FAILED(s_pMediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME)))
- {
- dsr_releaseObjects();
- return 1;
- }
-
- // Get length of file
- int mylength = -1;
- LONGLONG length;
- if (SUCCEEDED(s_pMediaSeeking->GetDuration(&length)))
- {
- mylength=(int)(length/10000);
- }
- m_length = mylength;
- // Query for video interfaces, which may not be relevant for audio files
- s_pGraphBuilder->QueryInterface(IID_IVideoWindow, (void **)&s_pVideoWindow);
- s_pGraphBuilder->QueryInterface(IID_IBasicVideo, (void **)&s_pBasicVideo);
- // Query for audio interfaces, which may not be relevant for video-only files
- s_pGraphBuilder->QueryInterface(IID_IBasicAudio, (void **)&s_pBasicAudio);
- if (s_setVolumeOnStart != -1)
- {
- dsr_setvolume(s_setVolumeOnStart);
- s_setVolumeOnStart = -1;
- }
- // Is this an audio-only file (no video component)?
- CheckVisibility();
- if (!s_bAudioOnly)
- {
- m_video_output->open(1, 1, 0, 1.0f, VIDEO_MAKETYPE('N','O','N','E')); // Dummy Size of 1x1
- s_hVideoWnd = (HWND)m_video_output->extended(VIDUSER_GET_VIDEOHWND, 0, 0);
- InvalidateRect(s_hVideoWnd, NULL, TRUE);
- // Setup the video window
- s_pVideoWindow->put_Owner((OAHWND) s_hVideoWnd);
- s_pVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
- RECT grc;
- GetClientRect(s_hVideoWnd, &grc);
- s_parentRect = grc;
- if ((s_pBasicVideo) && (s_pVideoWindow))
- {
- long videoWidth, videoHeight;
- if (SUCCEEDED(s_pBasicVideo->GetVideoSize(&videoWidth, &videoHeight)))
- {
- RECT r = fitMediaToWindow(grc, videoWidth, videoHeight);
- s_pVideoWindow->SetWindowPosition(r.left, r.top, r.right-r.left, r.bottom-r.top);
- }
- }
- // Intercept resize messages
- s_OriginalVideoWndProc = (WNDPROC) SetWindowLong(s_hVideoWnd, GWL_WNDPROC, (LONG_PTR)dsr_SubclassParentWndProc);
- }
- // Run the graph to play the media file
- hr = s_pMediaControl->Run();
- if (FAILED(hr))
- {
- dsr_stop();
- return 1;
- }
- return 0;
- }
- // stop playing.
- void dsr_stop()
- {
- if (s_pMediaControl)
- s_pMediaControl->Stop();
- if (s_pVideoWindow)
- {
- s_pVideoWindow->put_Visible(OAFALSE);
- s_pVideoWindow->put_Owner(NULL);
- }
- if (m_video_output)
- m_video_output->close();
- mod.outMod->Close();
- mod.SAVSADeInit();
- dsr_releaseObjects();
- m_length=-1;
- lastfn[0]=0;
- }
- // Standard Pause Routines
- void dsr_pause() {
- paused=1;
- if (s_pMediaControl)
- {
- s_pMediaControl->Pause();
- }
- }
- void dsr_unpause() {
- paused=0;
- if (s_pMediaControl)
- {
- s_pMediaControl->Run();
- }
- }
- int dsr_getoutputtime() {
- if (s_bufferstat)
- return s_bufferstat;
- if (s_pMediaSeeking)
- {
- LONGLONG pos;
- if (SUCCEEDED(s_pMediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME)) &&
- SUCCEEDED(s_pMediaSeeking->GetCurrentPosition(&pos)))
- {
- return (int)(pos/10000);
- }
- }
- return 0;
- }
- void dsr_setoutputtime(int time_in_ms) {
- if(s_pMediaSeeking) {
- DWORD dwCaps = AM_SEEKING_CanSeekAbsolute;
- if (s_pMediaSeeking->CheckCapabilities(&dwCaps) == S_OK)
- {
- int oldpause=paused;
- if(oldpause) dsr_unpause();
- LONGLONG l=((LONGLONG)time_in_ms)*10000;
- s_pMediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
- s_pMediaSeeking->SetPositions(&l,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
- mod.outMod->Flush(time_in_ms);
- if(oldpause) dsr_pause();
- }
- }
- }
- void dsr_setvolume(int volume)
- {
- if (s_pBasicAudio)
- {
- volume = min(volume, 255);
- volume = max(volume, 0);
- s_pBasicAudio->put_Volume(log(volume+1)/log(256)*10000-10000); // Map (0,255) to (-10000,0) log scale (as ActiveX is in DB's)
- }
- else
- {
- s_setVolumeOnStart = volume;
- }
- }
- LRESULT CALLBACK dsr_TimerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- if(uMsg==WM_TIMER && wParam==112 && s_dsr_notif_hwnd)
- {
- dsr_handleNotifyEvents();
- if(s_buffering)
- {
- BeginEnumFilters(s_pGraphBuilder, pEF, pBF)
- {
- if(CComQIPtr<IAMNetworkStatus, &IID_IAMNetworkStatus> pAMNS = pBF)
- {
- long BufferingProgress = 0;
- if(SUCCEEDED(pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0)
- {
- wsprintf(lastfn_status,"Buffering (%ld%%)",BufferingProgress);
- if(m_video_output) m_video_output->extended(VIDUSER_SET_INFOSTRING,(int)&lastfn_status,0);
- int bpos=BufferingProgress;
- int csa = mod.SAGetMode();
- char tempdata[75*2]={0,};
- int x;
- if (csa&1)
- {
- for (x = 0; x < bpos*75/100; x ++)
- {
- tempdata[x]=x*16/75;
- }
- }
- if (csa&2)
- {
- int offs=(csa&1) ? 75 : 0;
- x=0;
- while (x < bpos*75/100)
- {
- tempdata[offs + x++]=-6+x*14/75;
- }
- while (x < 75)
- {
- tempdata[offs + x++]=0;
- }
- }
- if (csa==4)
- {
- tempdata[0]=tempdata[1]=(bpos*127/100);
- }
- if (csa) mod.SAAdd(tempdata,++s_bufferstat,(csa==3)?0x80000003:csa);
-
- PostMessage(mod.hMainWindow,WM_USER,0,243);
- SendStatus(WINAMPX_STATUS_PREBUFFERING_PCT, 255*BufferingProgress/100);
- break;
- }
- }
- }
- EndEnumFilters
- }
- }
- return (DefWindowProc(hwnd, uMsg, wParam, lParam));
- }
- void dsr_handleNotifyEvents()
- {
- // char s[256];
- for (;;) {
- long evCode, param1, param2;
- HRESULT h = s_pMediaEventEx->GetEvent(&evCode, ¶m1, ¶m2, 0);
- if (FAILED(h)) break;
- switch(evCode) {
- case EC_BUFFERING_DATA:
- {
- // sprintf(s, "Handling Event: EC_BUFFERING_DATA: %d\n", param1);
- // OutputDebugString(s);
- s_buffering=param1;
- if(!s_buffering)
- {
- lastfn_status[0]=0;
- s_bufferstat=0;
- PostMessage(mod.hMainWindow,WM_USER,0,243);
- break;
- }
- }
- break;
- case EC_COMPLETE:
- {
- // OutputDebugString("Handling Event: EC_COMPLETE\n");
- PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
- }
- default:
- {
- // sprintf(s, "Handling Event: 0x%x : param1=0x%x; param2 = 0x%x\n", evCode, param1, param2);
- // OutputDebugString(s);
- }
- }
- s_pMediaEventEx->FreeEventParams(evCode, param1, param2);
- }
- }
- // Subclass of the Window containing the code. (Used to check if the parent got resized)
- LRESULT CALLBACK dsr_SubclassParentWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- LRESULT retval = CallWindowProc(s_OriginalVideoWndProc, hwnd, uMsg, wParam, lParam);
- if ((uMsg == WM_SIZE) && (s_hVideoWnd))
- {
- RECT grc;
- GetClientRect(s_hVideoWnd, &grc);
-
- if (!EqualRect(&grc, &s_parentRect))
- {
- s_parentRect = grc;
- if ((s_pBasicVideo) && (s_pVideoWindow))
- {
- long videoWidth, videoHeight;
- if (SUCCEEDED(s_pBasicVideo->GetVideoSize(&videoWidth, &videoHeight)))
- {
- RECT r = fitMediaToWindow(grc, videoWidth, videoHeight);
- s_pVideoWindow->SetWindowPosition(r.left, r.top, r.right-r.left, r.bottom-r.top);
- }
- }
- }
- }
- if ((uMsg == WM_PARENTNOTIFY) && (LOWORD(wParam)==WM_RBUTTONDOWN))
- {
- SendStatus(WINAMPX_STATUS_VIDEO_RIGHT_CLICK, lParam);
- }
- if ((uMsg == WM_PARENTNOTIFY) && (LOWORD(wParam)==WM_LBUTTONDOWN))
- {
- static DWORD dwLastTime = 0;
- int dwTimeNow = GetTickCount();
- if (((dwTimeNow - dwLastTime) < GetDoubleClickTime()) && (dwLastTime != 0))
- {
- PostMessage(hwnd, WM_USER_DSR_LBUTTONDBLCLK, 0, 0); // Notify the video window that we double clicked
- dwLastTime = 0;
- }
- else
- dwLastTime = dwTimeNow;
- }
- if ((uMsg == WM_USER_DSR_FULLSCREEN) && (s_pVideoWindow))
- {
- s_pVideoWindow->HideCursor(wParam ? OATRUE : OAFALSE);
- }
- return retval;
- }
- #endif // WINAMPX
|