RtspSourceFilter.cpp

Go to the documentation of this file.
00001 
00034 #include "stdafx.h"
00035 
00036 // STL
00037 #include <iostream>
00038 
00039 // RTVC
00040 #include "RtspSourceFilter.h"
00041 #include "RtspSourceOutputPin.h"
00042 
00043 // LiveMedia
00044 #include <liveMedia.hh>
00045 #include <BasicUsageEnvironment.hh>
00046 #include <GroupsockHelper.hh>
00047 #include <RTSPClient.hh>
00048 
00049 #include "RtspDataSession.h"
00050 #include "RtspSnifferSession.h"
00051 
00052 #include <Shared/StringUtil.h>
00053 
00054 RtspSourceFilter::RtspSourceFilter( IUnknown* pUnk, HRESULT* phr )
00055 : CSource(NAME("RTVC Live Media RTSP Source Filter"), pUnk, CLSID_RTVC_RtspAudioSourceFilter),
00056 m_tStreamTimeOffset(0),
00057 m_dStreamTimeOffset(0.0),
00058 m_pRtspDataSession(NULL)
00059 
00060 {
00061         // Init CSettingsInterface
00062         initParameters();
00063         m_bStreaming = false;
00064 }
00065 
00066 RtspSourceFilter::~RtspSourceFilter(void)
00067 {
00068         for (int i = 0; i < m_vOutputPins.size();i++)
00069         {
00070                 delete m_vOutputPins[i];
00071                 m_vOutputPins[i] = NULL;
00072         }
00073 }
00074 
00075 CUnknown *WINAPI RtspSourceFilter::CreateInstance( IUnknown* pUnk, HRESULT* phr )
00076 {
00077         RtspSourceFilter* pAdvertSource = new RtspSourceFilter(pUnk, phr);
00078         if (!pAdvertSource)
00079         {
00080                 *phr = E_OUTOFMEMORY;
00081         }
00082         return pAdvertSource;
00083 }
00084 
00085 STDMETHODIMP RtspSourceFilter::NonDelegatingQueryInterface( REFIID riid, void **ppv )
00086 {
00087         if(riid == (IID_ISettingsInterface))
00088         {
00089                 return GetInterface((ISettingsInterface*) this, ppv);
00090         }
00091         else if (riid == IID_IStatusInterface)
00092         {
00093                 return GetInterface((IStatusInterface*) this, ppv);
00094         }
00095         else if (riid == IID_IFileSourceFilter)
00096         {
00097                 return GetInterface((IFileSourceFilter*) this, ppv);
00098         }
00099         else if (riid == IID_ISpecifyPropertyPages)
00100         {
00101                 return GetInterface(static_cast<ISpecifyPropertyPages*>(this), ppv);
00102         }
00103         else
00104         {
00105                 return CSource::NonDelegatingQueryInterface(riid, ppv);
00106         }
00107 }
00108 
00109 
00110 STDMETHODIMP RtspSourceFilter::Load( LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt )
00111 {
00112 
00113         // Store the URL
00114         m_sUrl = StringUtil::wideToStl(lpwszFileName);
00115 
00116         // Sniff the current media parameters such as width and height of the video
00117         RtspSnifferSession rtspSnifferSession;
00118 
00119         bool bSuccess = rtspSnifferSession.getMediaSessionInformation(m_sUrl);
00120         if (bSuccess)
00121         {
00122                 HRESULT hr = S_OK;
00123                 std::vector<MediaSubsession*> vSubsessions = rtspSnifferSession.getMediaSubsessions();
00124                 // Iterate over all subsessions and create an output pin if possible
00125                 for (std::vector<MediaSubsession*>::iterator it = vSubsessions.begin(); it!= vSubsessions.end(); ++it)
00126                 {
00127                         createOutputPin(*it, &hr);
00128                         if (FAILED(hr))
00129                         {
00130                                 break;
00131                         }
00132                 }
00133                 return hr;
00134         }
00135         else
00136         {
00137                 std::string sError = rtspSnifferSession.getLastError();
00138                 SetLastError(sError.c_str(), true);
00139                 return E_FAIL;
00140         }
00141 }
00142 
00143 STDMETHODIMP RtspSourceFilter::GetCurFile( LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt )
00144 {
00145         // If RTSP exchange has successfully been completed
00146         // TOREVISE: It does not make sense since this filter will hardly ever have only one media type.
00147         if (pmt != NULL)
00148         {
00149                 // Get media type from pin
00150                 if (m_vOutputPins.size() > 0)
00151                 {
00152                         // Get media type from pin
00153                         CMediaType* pMediaType = m_vOutputPins[0]->m_pMediaType;
00154                         if (pMediaType == NULL)
00155                         {
00156                                 //some error has occurred
00157                                 return E_FAIL;
00158                         }
00159                         else
00160                         {
00161                                 // copy media type
00162                                 HRESULT hr = CopyMediaType(pmt, (AM_MEDIA_TYPE*) pMediaType);
00163                                 if (hr = E_UNEXPECTED)
00164                                 {
00165                                         return E_FAIL;
00166                                 }
00167                         }
00168                 }
00169                 else
00170                 {
00171                         return E_FAIL;
00172                 }
00173         }
00174         // Copied from Async filter sample
00175         *ppszFileName = NULL;
00176 
00177         if (m_sUrl.length()!=0) 
00178         {
00179                 WCHAR* pFileName = (StringUtil::stlToWide(m_sUrl));     
00180 
00181                 DWORD n = sizeof(WCHAR)*(1+lstrlenW(pFileName));
00182 
00183                 *ppszFileName = (LPOLESTR) CoTaskMemAlloc( n );
00184                 if (*ppszFileName!=NULL) {
00185                         CopyMemory(*ppszFileName, pFileName, n);
00186                 }
00187                 delete[] pFileName;
00188         }
00189 
00190         return NOERROR;
00191 }
00192 
00193 void RtspSourceFilter::createOutputPin(MediaSubsession *pSubsession, HRESULT* pHr)
00194 {
00195         // Create the output pin using the size of the output pin vector as an ID
00196         // This ID will be used by the pins buffer processing loop to query the packet manager for packets
00197         RtspSourceOutputPin* pPin = new RtspSourceOutputPin(pHr, this, pSubsession, m_vOutputPins.size());
00198         // Add to list
00199         m_vOutputPins.push_back(pPin);
00200         // Refresh enumerator
00201         IncrementPinVersion();
00202 }
00203 
00204 int RtspSourceFilter::GetPinCount()
00205 {
00206         return (int)(m_vOutputPins.size());
00207 }
00208 
00209 CBasePin * RtspSourceFilter::GetPin( int n )
00210 {
00211         if ((n >= GetPinCount()) || (n < 0))
00212                 return NULL;
00213 
00214         return m_vOutputPins[n];
00215 }
00216 
00217 STDMETHODIMP RtspSourceFilter::FindPin( LPCWSTR Id, IPin **ppPin )
00218 {
00219         //Find pin according to it's name
00220         CheckPointer(ppPin,E_POINTER);
00221         ValidateReadWritePtr(ppPin,sizeof(IPin *));
00222         //Todo: Modify for this MUX: Check what ids this method is called with
00223 
00224         const char* szInput = StringUtil::wideToStl(Id).c_str();
00225 
00226         char szTemp[10];
00227         ZeroMemory(szTemp, 10);
00228         memcpy(szTemp, szInput, 6);
00229         szTemp[6] = '\0';
00230         if (0==strcmp(szTemp, "Output")) 
00231         {
00232                 const char* szID = szInput + 7;
00233                 int nId = atoi(szID);
00234                 *ppPin = GetPin(nId);
00235         } 
00236         else 
00237         {
00238                 *ppPin = NULL;
00239                 return VFW_E_NOT_FOUND;
00240         }
00241 
00242         HRESULT hr = NOERROR;
00243         //  AddRef() returned pointer - but GetPin could fail if memory is low.
00244         if (*ppPin) 
00245         {
00246                 (*ppPin)->AddRef();
00247         } 
00248         else 
00249         {
00250                 hr = E_OUTOFMEMORY;  // probably.  There's no pin anyway.
00251         }
00252         return hr;
00253 }
00254 
00255 STDMETHODIMP RtspSourceFilter::Stop()
00256 {
00257         CAutoLock cAutoLock(&m_stateLock);
00258         // Update streaming state
00259         m_bStreaming = false;
00260         // This will cause the liveMedia loop to exit
00261         m_pRtspDataSession->setWatchVariable();
00262 
00263         // Wait for the liveMedia eventloop to finish
00264         DWORD result = WaitForSingleObject(m_hLiveMediaStopEvent, INFINITE);
00265         return CSource::Stop();
00266 }
00267 
00268 STDMETHODIMP RtspSourceFilter::Pause()
00269 {
00270         CAutoLock cAutoLock(&m_stateLock);
00271         StartRtspServerThreadIfNotStarted();
00272         return CSource::Pause();
00273 }
00274 
00276 static DWORD WINAPI LiveRTSPServerThreadFunc(LPVOID pvParam);
00277 
00278 
00279 void RtspSourceFilter::StartRtspServerThreadIfNotStarted()
00280 {
00281         CAutoLock cAutoLock(&m_stateLock);
00282         if (!m_bStreaming)
00283         {
00284                 m_bStreaming = true;
00285                 // Create Live Media Event loop handle - this will be used to notify the main thread that the live Media RTSP thread has finished
00286                 m_hLiveMediaStopEvent = CreateEvent(
00287                         NULL,               // default security attributes
00288                         FALSE,              // auto-reset event
00289                         FALSE,              // initial state is nonsignaled
00290                         TEXT("LiveMediaEventLoop")  // object name
00291                         );
00292 
00293                 DWORD dwThreadID = 0;
00294                 // Create a new thread for the RTSP liveMedia event loop
00295                 HANDLE hThread = CreateThread(0, 0, LiveRTSPServerThreadFunc, (void*)this, 0, &dwThreadID);
00296         }
00297 }
00298 
00299 static DWORD WINAPI LiveRTSPServerThreadFunc(LPVOID pvParam)
00300 {
00301         RtspSourceFilter* pSourceFilter = (RtspSourceFilter*)pvParam;
00302         pSourceFilter->StartRtspSession();
00303         return S_OK;
00304 }
00305 
00306 void RtspSourceFilter::StartRtspSession()
00307 {
00308         ASSERT(m_pRtspDataSession == NULL);
00309         // Encapsulating RTSP code into RtspClientSession class 
00310         // Create RTSP Client Session object
00311         m_pRtspDataSession = new RtspDataSession(&m_rtpPacketManager);
00312         m_pRtspDataSession->streamUsingTCP(m_bStreamUsingTCP);
00313         // Start the liveMedia thread: this method does not return until the liveMedia watch variable is set in the STOP method
00314         m_pRtspDataSession->startRetrievingData(m_sUrl);
00315         delete m_pRtspDataSession;
00316         m_pRtspDataSession = NULL;
00317         // The Stop method waits for this event
00318         SetEvent(m_hLiveMediaStopEvent);
00319 }
00320 
00321 STDMETHODIMP RtspSourceFilter::GetState( DWORD dwMilliSecsTimeout, FILTER_STATE *pState )
00322 {
00323         // Edit: 24/09/2008
00324         // From http://msdn.microsoft.com/en-us/library/ms787518(VS.85).aspx
00325         CheckPointer(pState, E_POINTER);
00326         *pState = m_State;
00327         if (m_State == State_Paused)
00328                 return VFW_S_CANT_CUE;
00329         else
00330                 return S_OK;
00331 }
00332 
00333 void RtspSourceFilter::notifyFilterAboutOffset( double dOffset)
00334 {
00335         CAutoLock cAutoLock(&m_stateLock);
00336 
00337         // Get the current stream time to make sure that we always generate samples that have a starting time in the future
00338         // Otherwise the samples might be late by the time they reach the renderer
00339 
00340         // Add stream time + 50ms as further offset to make sure sample is rendered at the correct time
00341         // Get the current stream time
00342         CRefTime streamTime;
00343         StreamTime(streamTime);
00344         // Add a tiny offset to put us into the future
00345         m_tStreamTimeOffset = streamTime.GetUnits() + 500000;
00346         // Convert to double
00347         m_dStreamTimeOffset = m_tStreamTimeOffset / 10000000.0;
00348 
00349         //TOREVISE: add the streamtime offset here: it hasn't been added yet!!!
00350         // Iterate over all pins and set the offset
00351         for (int i = 0; i < m_vOutputPins.size(); i++)
00352         {
00353                 m_vOutputPins[i]->setOffset(dOffset);
00354         }
00355 }

Generated on Fri Mar 13 14:12:38 2009 for RTVC by  doxygen 1.5.3