| 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// Externsextern 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 bytesextern 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 Definesclass 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 DeclarationsLRESULT 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 Routinesvoid 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
 |