ShoutcastSource.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:15k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "stdafx.h"
  22. #include <initguid.h>
  23. #include "shoutcastsource.h"
  24. #include "......DSUtilDSUtil.h"
  25. #include "........includemoreuuids.h"
  26. #define MAXFRAMESIZE ((144 * 320000 / 8000) + 1)
  27. #define BUFFERS 2
  28. #define MINBUFFERLENGTH 1000000i64
  29. #define AVGBUFFERLENGTH 30000000i64
  30. #define MAXBUFFERLENGTH 100000000i64
  31. static const DWORD s_bitrate[2][16] =
  32. {
  33. {1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},
  34. {1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}
  35. };
  36. static const DWORD s_freq[4][4] =
  37. {
  38. {11025,12000,8000,0},
  39. {0,0,0,0},
  40. {22050,24000,16000,0},
  41. {44100,48000,32000,0}
  42. };
  43. static const BYTE s_channels[4] =
  44. {
  45. 2,2,2,1 // stereo, joint stereo, dual, mono
  46. };
  47. typedef struct
  48. {
  49. WORD sync;
  50. BYTE version;
  51. BYTE layer;
  52. DWORD bitrate;
  53. DWORD freq;
  54. BYTE channels;
  55. DWORD framesize;
  56. bool ExtractHeader(CSocket& socket)
  57. {
  58. BYTE buff[4];
  59. if(4 != socket.Receive(buff, 4, MSG_PEEK))
  60. return(false);
  61. sync = (buff[0]<<4)|(buff[1]>>4)|1;
  62. version = (buff[1]>>3)&3;
  63. layer = 4 - ((buff[1]>>1)&3);
  64. bitrate = s_bitrate[version&1][buff[2]>>4]*1000;
  65. freq = s_freq[version][(buff[2]>>2)&3];
  66. channels = s_channels[(buff[3]>>6)&3];
  67. framesize = freq ? ((((version&1)?144:72) * bitrate / freq) + ((buff[2]>>1)&1)) : 0;
  68. return(sync == 0xfff && layer == 3 && bitrate != 0 && freq != 0);
  69. }
  70. } mp3hdr;
  71. #ifdef REGISTER_FILTER
  72. const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
  73. {
  74. {&MEDIATYPE_Audio, &MEDIASUBTYPE_MP3},
  75. };
  76. const AMOVIESETUP_PIN sudOpPin[] =
  77. {
  78. {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
  79. };
  80. const AMOVIESETUP_FILTER sudFilter[] =
  81. {
  82. {&__uuidof(CShoutcastSource), L"ShoutcastSource", MERIT_UNLIKELY, countof(sudOpPin), sudOpPin}
  83. };
  84. CFactoryTemplate g_Templates[] =
  85. {
  86. {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CShoutcastSource>, NULL, &sudFilter[0]}
  87. };
  88. int g_cTemplates = countof(g_Templates);
  89. STDAPI DllRegisterServer()
  90. {
  91. return AMovieDllRegisterServer2(TRUE);
  92. }
  93. STDAPI DllUnregisterServer()
  94. {
  95. return AMovieDllRegisterServer2(FALSE);
  96. }
  97. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  98. BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
  99. {
  100. if(dwReason == DLL_PROCESS_ATTACH)
  101. {
  102. if(!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
  103. {
  104. AfxMessageBox(_T("AfxWinInit failed!"));
  105. return FALSE;
  106. }
  107. if(!AfxSocketInit(NULL))
  108. {
  109. AfxMessageBox(_T("AfxSocketInit failed!"));
  110. return FALSE;
  111. }
  112. }
  113. else if(dwReason == DLL_PROCESS_DETACH)
  114. {
  115. AfxWinTerm();
  116. }
  117.     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
  118. }
  119. #endif
  120. //
  121. // CShoutcastSource
  122. //
  123. CShoutcastSource::CShoutcastSource(LPUNKNOWN lpunk, HRESULT* phr)
  124. : CSource(NAME("CShoutcastSource"), lpunk, __uuidof(this))
  125. {
  126. #ifndef REGISTER_FILTER
  127. AfxSocketInit();
  128. #endif
  129. }
  130. CShoutcastSource::~CShoutcastSource()
  131. {
  132. }
  133. STDMETHODIMP CShoutcastSource::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  134. {
  135.     CheckPointer(ppv, E_POINTER);
  136. return 
  137. QI(IFileSourceFilter)
  138. QI(IAMFilterMiscFlags)
  139. QI(IAMOpenProgress)
  140. QI2(IAMMediaContent)
  141. __super::NonDelegatingQueryInterface(riid, ppv);
  142. }
  143. // IFileSourceFilter
  144. STDMETHODIMP CShoutcastSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) 
  145. {
  146. if(GetPinCount() > 0)
  147. return VFW_E_ALREADY_CONNECTED;
  148. HRESULT hr = E_OUTOFMEMORY;
  149. if(!(new CShoutcastStream(pszFileName, this, &hr)) || FAILED(hr))
  150. return hr;
  151. m_fn = pszFileName;
  152. return S_OK;
  153. }
  154. STDMETHODIMP CShoutcastSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt)
  155. {
  156. if(!ppszFileName) return E_POINTER;
  157. if(!(*ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength()+1)*sizeof(WCHAR))))
  158. return E_OUTOFMEMORY;
  159. wcscpy(*ppszFileName, m_fn);
  160. return S_OK;
  161. }
  162. // IAMFilterMiscFlags
  163. ULONG CShoutcastSource::GetMiscFlags()
  164. {
  165. return AM_FILTER_MISC_FLAGS_IS_SOURCE;
  166. }
  167. // IAMOpenProgress
  168. STDMETHODIMP CShoutcastSource::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent)
  169. {
  170. if(m_iPins == 1)
  171. {
  172.         if(pllTotal) *pllTotal = 100;
  173. if(pllCurrent) *pllCurrent = ((CShoutcastStream*)m_paStreams[0])->GetBufferFullness();
  174. return S_OK;
  175. }
  176. return E_UNEXPECTED;
  177. }
  178. STDMETHODIMP CShoutcastSource::AbortOperation()
  179. {
  180. return E_NOTIMPL;
  181. }
  182. // IAMMediaContent
  183. STDMETHODIMP CShoutcastSource::get_Title(BSTR* pbstrTitle)
  184. {
  185. CheckPointer(pbstrTitle, E_POINTER);
  186. if(m_iPins == 1)
  187. {
  188. *pbstrTitle = ((CShoutcastStream*)m_paStreams[0])->GetTitle().AllocSysString();
  189. return S_OK;
  190. }
  191. return E_UNEXPECTED;
  192. }
  193. // CShoutcastStream
  194. CShoutcastStream::CShoutcastStream(const WCHAR* wfn, CShoutcastSource* pParent, HRESULT* phr)
  195. : CSourceStream(NAME("ShoutcastStream"), phr, pParent, L"Output")
  196. , m_fBuffering(false)
  197. {
  198. ASSERT(phr);
  199. *phr = S_OK;
  200. CString fn(wfn);
  201. if(fn.Find(_T("://")) < 0) fn = _T("http://") + fn;
  202. #if defined(REGISTER_FILTER) && defined(DEBUG)
  203. //fn = _T("http://localhost:8000/");
  204. //fn = _T("http://64.236.34.141/stream/1005");
  205. //fn = _T("http://218.145.30.106:11000"); // 128kbps korean
  206. //fn = _T("http://65.206.46.110:8020"); // 96kbps
  207. //fn = _T("http://64.236.34.72:80/stream/1003");
  208. fn = _T("http://64.236.34.72:80/stream/1011");
  209. //fn = _T("http://218.145.30.106:11000");
  210. //fn = _T("http://radio.sluchaj.com:8000/radio.ogg"); // ogg
  211. // http://www.oddsock.org/icecast2yp/ // more ogg via icecast2
  212. #endif
  213. if(!m_url.CrackUrl(fn))
  214. {
  215. *phr = E_FAIL;
  216. return;
  217. }
  218. if(m_url.GetUrlPathLength() == 0)
  219. m_url.SetUrlPath(_T("/"));
  220. if(m_url.GetPortNumber() == ATL_URL_INVALID_PORT_NUMBER)
  221. m_url.SetPortNumber(ATL_URL_DEFAULT_HTTP_PORT);
  222. if(m_url.GetScheme() != ATL_URL_SCHEME_HTTP)
  223. {
  224. *phr = E_FAIL;
  225. return;
  226. }
  227. if(!m_socket.Create() || !m_socket.Connect(m_url))
  228. {
  229. *phr = E_FAIL;
  230. return;
  231. }
  232. m_socket.Close();
  233. }
  234. CShoutcastStream::~CShoutcastStream()
  235. {
  236. }
  237. void CShoutcastStream::EmptyBuffer()
  238. {
  239. CAutoLock cAutoLock(&m_queue);
  240. m_queue.RemoveAll();
  241. }
  242. LONGLONG CShoutcastStream::GetBufferFullness()
  243. {
  244. CAutoLock cAutoLock(&m_queue);
  245. if(!m_fBuffering) return 100;
  246. if(m_queue.IsEmpty()) return 0;
  247. LONGLONG ret = 100i64*(m_queue.GetTail().rtStart - m_queue.GetHead().rtStart) / AVGBUFFERLENGTH;
  248. return(min(ret, 100));
  249. }
  250. CString CShoutcastStream::GetTitle()
  251. {
  252. CAutoLock cAutoLock(&m_queue);
  253. return(m_title);
  254. }
  255. HRESULT CShoutcastStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
  256. {
  257.     ASSERT(pAlloc);
  258.     ASSERT(pProperties);
  259.     HRESULT hr = NOERROR;
  260. pProperties->cBuffers = BUFFERS;
  261. pProperties->cbBuffer = MAXFRAMESIZE;
  262.     ALLOCATOR_PROPERTIES Actual;
  263.     if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr;
  264.     if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
  265.     ASSERT(Actual.cBuffers == pProperties->cBuffers);
  266.     return NOERROR;
  267. }
  268. HRESULT CShoutcastStream::FillBuffer(IMediaSample* pSample)
  269. {
  270. HRESULT hr;
  271. BYTE* pData = NULL;
  272. if(FAILED(hr = pSample->GetPointer(&pData)) || !pData)
  273. return S_FALSE;
  274. do
  275. {
  276. // do we have to refill our buffer?
  277. {
  278. CAutoLock cAutoLock(&m_queue);
  279. if(!m_queue.IsEmpty() && m_queue.GetHead().rtStart < m_queue.GetTail().rtStart - MINBUFFERLENGTH)
  280. break; // nope, that's great
  281. }
  282. TRACE(_T("START BUFFERINGn"));
  283. m_fBuffering = true;
  284. while(1)
  285. {
  286. if(fExitThread) // playback stopped?
  287. return S_FALSE;
  288. Sleep(50);
  289. CAutoLock cAutoLock(&m_queue);
  290. if(!m_queue.IsEmpty() && m_queue.GetHead().rtStart < m_queue.GetTail().rtStart - AVGBUFFERLENGTH)
  291. break; // this is enough
  292. }
  293. pSample->SetDiscontinuity(TRUE);
  294. DeliverBeginFlush();
  295. DeliverEndFlush();
  296. DeliverNewSegment(0, ~0, 1.0);
  297. TRACE(_T("END BUFFERINGn"));
  298. m_fBuffering = false;
  299. }
  300. while(false);
  301. {
  302. CAutoLock cAutoLock(&m_queue);
  303. ASSERT(!m_queue.IsEmpty());
  304. if(!m_queue.IsEmpty())
  305. {
  306. mp3frame f = m_queue.RemoveHead();
  307. DWORD len = min(pSample->GetSize(), f.len);
  308. memcpy(pData, f.pData, len);
  309. pSample->SetActualDataLength(len);
  310. pSample->SetTime(&f.rtStart, &f.rtStop);
  311. m_title = f.title;
  312. }
  313. }
  314. pSample->SetSyncPoint(TRUE);
  315. return S_OK;
  316. }
  317. HRESULT CShoutcastStream::GetMediaType(int iPosition, CMediaType* pmt)
  318. {
  319.     CAutoLock cAutoLock(m_pFilter->pStateLock());
  320.     if(iPosition < 0) return E_INVALIDARG;
  321.     if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
  322.     pmt->SetType(&MEDIATYPE_Audio);
  323.     pmt->SetSubtype(&MEDIASUBTYPE_MP3);
  324.     pmt->SetFormatType(&FORMAT_WaveFormatEx);
  325. WAVEFORMATEX* wfe = (WAVEFORMATEX*)pmt->AllocFormatBuffer(sizeof(WAVEFORMATEX));
  326. memset(wfe, 0, sizeof(WAVEFORMATEX));
  327. wfe->wFormatTag = (WORD)MEDIASUBTYPE_MP3.Data1;
  328. wfe->nChannels = (WORD)m_socket.m_channels;
  329. wfe->nSamplesPerSec = m_socket.m_freq;
  330. wfe->nAvgBytesPerSec = m_socket.m_bitrate/8;
  331. wfe->nBlockAlign = 1;
  332. wfe->wBitsPerSample = 0;
  333.     return NOERROR;
  334. }
  335. HRESULT CShoutcastStream::CheckMediaType(const CMediaType* pmt)
  336. {
  337. if(pmt->majortype == MEDIATYPE_Audio
  338. && pmt->subtype == MEDIASUBTYPE_MP3
  339. && pmt->formattype == FORMAT_WaveFormatEx) return S_OK;
  340. return E_INVALIDARG;
  341. }
  342. static UINT SocketThreadProc(LPVOID pParam)
  343. {
  344. return ((CShoutcastStream*)pParam)->SocketThreadProc();
  345. }
  346. UINT CShoutcastStream::SocketThreadProc()
  347. {
  348. fExitThread = false;
  349. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  350. AfxSocketInit();
  351. CAutoVectorPtr<BYTE> pData;
  352. if(!m_socket.Create() || !m_socket.Connect(m_url)
  353. || !pData.Allocate(max(m_socket.m_metaint, MAXFRAMESIZE)))
  354. {
  355. m_socket.Close(); 
  356. return 1;
  357. }
  358. REFERENCE_TIME m_rtSampleTime = 0;
  359. while(!fExitThread)
  360. {
  361. int len = MAXFRAMESIZE;
  362. len = m_socket.Receive(pData, len);
  363. if(len <= 0) break;
  364. mp3frame f(len);
  365. memcpy(f.pData, pData, len);
  366. f.rtStop = (f.rtStart = m_rtSampleTime) + (10000000i64 * len * 8/m_socket.m_bitrate);
  367. m_rtSampleTime = f.rtStop;
  368. f.title = m_socket.m_title;
  369. CAutoLock cAutoLock(&m_queue);
  370. m_queue.AddTail(f);
  371. }
  372. m_socket.Close();
  373. return 0;
  374. }
  375. HRESULT CShoutcastStream::OnThreadCreate()
  376. {
  377. EmptyBuffer();
  378. fExitThread = true;
  379. m_hSocketThread = AfxBeginThread(::SocketThreadProc, this)->m_hThread;
  380. while(fExitThread) Sleep(10);
  381. return NOERROR;
  382. }
  383. HRESULT CShoutcastStream::OnThreadDestroy()
  384. {
  385. EmptyBuffer();
  386. fExitThread = true;
  387. m_socket.CancelBlockingCall();
  388. WaitForSingleObject(m_hSocketThread, -1);
  389. return NOERROR;
  390. }
  391. HRESULT CShoutcastStream::Inactive()
  392. {
  393. fExitThread = true;
  394. return __super::Inactive();
  395. }
  396. //
  397. int CShoutcastStream::CShoutcastSocket::Receive(void* lpBuf, int nBufLen, int nFlags)
  398. {
  399. if(nFlags&MSG_PEEK) 
  400. return __super::Receive(lpBuf, nBufLen, nFlags);
  401. if(m_metaint > 0 && m_nBytesRead + nBufLen > m_metaint)
  402. nBufLen = m_metaint - m_nBytesRead;
  403. int len = __super::Receive(lpBuf, nBufLen, nFlags);
  404. if(len <= 0) return len;
  405. if((m_nBytesRead += len) == m_metaint)
  406. {
  407. m_nBytesRead = 0;
  408. static BYTE buff[255*16], b = 0;
  409. memset(buff, 0, sizeof(buff));
  410. if(1 == __super::Receive(&b, 1) && b && b*16 == __super::Receive(buff, b*16))
  411. {
  412. CStringA str = (LPCSTR)buff, title("StreamTitle='");
  413. TRACE(_T("Metainfo: %sn"), CString(str));
  414. int i = str.Find(title);
  415. if(i >= 0)
  416. {
  417. i += title.GetLength();
  418. int j = str.Find(''', i);
  419. if(j > i) m_title = str.Mid(i, j - i);
  420. }
  421. else
  422. {
  423. TRACE(_T("!!!!!!!!!Missing StreamTitle!!!!!!!!!n"));
  424. }
  425. }
  426. }
  427. else if(m_metaint > 0)
  428. {
  429. char* p = (char*)lpBuf;
  430. char* p0 = p;
  431. char* pend = p + len - 13;
  432. for(; p < pend; p++)
  433. {
  434. if(strncmp(p, "StreamTitle='", 13))
  435. continue;
  436. TRACE(_T("!!!!!!!!!StreamTitle found inside mp3 data!!!!!!!!! offset=%dn"), p - p0);
  437. TRACE(_T("resyncing...n"));
  438. while(p-- > p0)
  439. {
  440. if((BYTE)*p >= 0x20)
  441. continue;
  442. TRACE(_T("found possible length byte: %d, skipping %d bytesn"), *p, 1 + *p*16);
  443. p += 1 + *p*16;
  444. len = (p0 + len) - p;
  445. TRACE(_T("returning the remaining bytes in the packet: %dn"), len);
  446. if(len <= 0)
  447. {
  448. TRACE(_T("nothing to return, reading a bit more inn"));
  449. if(len < 0) __super::Receive(lpBuf, -len, nFlags);
  450. int len = __super::Receive(lpBuf, nBufLen, nFlags);
  451. if(len <= 0) return len;
  452. }
  453. m_nBytesRead = len; 
  454. memcpy(lpBuf, p, len);
  455. break;
  456. }
  457. break;
  458. }
  459. }
  460. return len;
  461. }
  462. bool CShoutcastStream::CShoutcastSocket::Connect(CUrl& url)
  463. {
  464. if(!__super::Connect(url.GetHostName(), url.GetPortNumber()))
  465. return(false);
  466. CStringA str;
  467. str.Format(
  468. "GET %s HTTP/1.0rn"
  469. "Icy-MetaData:1rn"
  470. "User-Agent: shoutcastsourcern"
  471. "Host: %srn"
  472. "Accept: */*rn"
  473. "Connection: Keep-Alivern"
  474. "rn", CStringA(url.GetUrlPath()), CStringA(url.GetHostName()));
  475. bool fOK = false;
  476. bool fTryAgain = false;
  477. int metaint = 0;
  478. do
  479. {
  480. int len = Send((BYTE*)(LPCSTR)str, str.GetLength());
  481. m_nBytesRead = 0;
  482. m_metaint = metaint = 0;
  483. m_bitrate = 0;
  484. str.Empty();
  485. BYTE cur = 0, prev = 0;
  486. while(Receive(&cur, 1) == 1 && cur && !(cur == 'n' && prev == 'n'))
  487. {
  488. if(cur == 'r')
  489. continue;
  490. if(cur == 'n')
  491. {
  492. str.MakeLower();
  493. if(str.Find("icy 200 ok") >= 0) fOK = true;
  494. else if(1 == sscanf(str, "icy-br:%d", &m_bitrate)) m_bitrate *= 1000;
  495. else if(1 == sscanf(str, "icy-metaint:%d", &metaint)) metaint = metaint;
  496. str.Empty();
  497. }
  498. else
  499. {
  500. str += cur;
  501. }
  502. prev = cur;
  503. cur = 0;
  504. }
  505. if(!fOK && GetLastError() == WSAECONNRESET && !fTryAgain)
  506. {
  507. str.Format(
  508. "GET %s HTTP/1.0rn"
  509. "Icy-MetaData:1rn"
  510. "Host: %srn"
  511. "Accept: */*rn"
  512. "Connection: Keep-Alivern"
  513. "rn", CStringA(url.GetUrlPath()), CStringA(url.GetHostName()));
  514. fTryAgain = true;
  515. }
  516. else
  517. {
  518. fTryAgain = false;
  519. }
  520. }
  521. while(fTryAgain);
  522. if(!fOK || m_bitrate == 0) {Close(); return(false);}
  523. m_metaint = metaint;
  524. m_nBytesRead = 0;
  525. return(FindSync());
  526. }
  527. bool CShoutcastStream::CShoutcastSocket::FindSync()
  528. {
  529. m_freq = -1;
  530. m_channels = -1;
  531. BYTE b;
  532. for(int i = MAXFRAMESIZE; i > 0; i--, Receive(&b, 1))
  533. {
  534. mp3hdr h;
  535. if(h.ExtractHeader(*this) && m_bitrate == h.bitrate)
  536. {
  537. if(h.bitrate > 1) m_bitrate = h.bitrate;
  538. m_freq = h.freq;
  539. m_channels = h.channels;
  540. return(true);
  541. }
  542. }
  543. return(false);
  544. }