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

多媒体编程

开发平台:

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 "DSMMuxer.h"
  23. #include "......DSUtilDSUtil.h"
  24. #include <initguid.h>
  25. #include <qnetwork.h>
  26. #include "........includemoreuuids.h"
  27. #ifdef REGISTER_FILTER
  28. const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
  29. {
  30. {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia}
  31. };
  32. const AMOVIESETUP_PIN sudpPins[] =
  33. {
  34.     {L"Input", FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, NULL, 0, NULL},
  35.     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
  36. };
  37. const AMOVIESETUP_FILTER sudFilter[] =
  38. {
  39. {&__uuidof(CDSMMuxerFilter), L"DSM Muxer", MERIT_DO_NOT_USE, countof(sudpPins), sudpPins}
  40. };
  41. CFactoryTemplate g_Templates[] =
  42. {
  43. {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CDSMMuxerFilter>, NULL, &sudFilter[0]}
  44. };
  45. int g_cTemplates = countof(g_Templates);
  46. STDAPI DllRegisterServer()
  47. {
  48. return AMovieDllRegisterServer2(TRUE);
  49. }
  50. STDAPI DllUnregisterServer()
  51. {
  52. return AMovieDllRegisterServer2(FALSE);
  53. }
  54. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  55. BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
  56. {
  57.     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
  58. }
  59. #endif
  60. template<typename T> static T myabs(T n) {return n >= 0 ? n : -n;}
  61. static int GetByteLength(UINT64 data, int min = 0)
  62. {
  63. int i = 7;
  64. while(i >= min && ((BYTE*)&data)[i] == 0) i--;
  65. return ++i;
  66. }
  67. //
  68. // CDSMMuxerFilter
  69. //
  70. CDSMMuxerFilter::CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap, bool fAutoRes)
  71. : CBaseMuxerFilter(pUnk, phr, __uuidof(this))
  72. , m_fAutoChap(fAutoChap)
  73. , m_fAutoRes(fAutoRes)
  74. {
  75. if(phr) *phr = S_OK;
  76. }
  77. CDSMMuxerFilter::~CDSMMuxerFilter()
  78. {
  79. }
  80. void CDSMMuxerFilter::MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len)
  81. {
  82. ASSERT(type < 32);
  83. int i = GetByteLength(len, 1);
  84. pBS->BitWrite(DSMSW, DSMSW_SIZE<<3);
  85. pBS->BitWrite(type, 5);
  86. pBS->BitWrite(i-1, 3);
  87. pBS->BitWrite(len, i<<3);
  88. }
  89. void CDSMMuxerFilter::MuxFileInfo(IBitStream* pBS)
  90. {
  91. int len = 1;
  92. CSimpleMap<CStringA, CStringA> si;
  93. for(int i = 0; i < GetSize(); i++)
  94. {
  95. CStringA key = CStringA(CString(GetKeyAt(i))), value = UTF16To8(GetValueAt(i));
  96. if(key.GetLength() != 4) continue;
  97. si.Add(key, value);
  98. len += 4 + value.GetLength() + 1;
  99. }
  100. MuxPacketHeader(pBS, DSMP_FILEINFO, len);
  101. pBS->BitWrite(DSMF_VERSION, 8);
  102. for(int i = 0; i < si.GetSize(); i++)
  103. {
  104. CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i);
  105. pBS->ByteWrite((LPCSTR)key, 4);
  106. pBS->ByteWrite((LPCSTR)value, value.GetLength()+1);
  107. }
  108. }
  109. void CDSMMuxerFilter::MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin)
  110. {
  111. int len = 1;
  112. CSimpleMap<CStringA, CStringA> si;
  113. for(int i = 0; i < pPin->GetSize(); i++)
  114. {
  115. CStringA key = CStringA(CString(pPin->GetKeyAt(i))), value = UTF16To8(pPin->GetValueAt(i));
  116. if(key.GetLength() != 4) continue;
  117. si.Add(key, value);
  118. len += 4 + value.GetLength() + 1;
  119. }
  120. if(len > 1)
  121. {
  122. MuxPacketHeader(pBS, DSMP_STREAMINFO, len);
  123. pBS->BitWrite(pPin->GetID(), 8);
  124. for(int i = 0; i < si.GetSize(); i++)
  125. {
  126. CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i);
  127. pBS->ByteWrite((LPCSTR)key, 4);
  128. pBS->ByteWrite((LPCSTR)value, value.GetLength()+1);
  129. }
  130. }
  131. }
  132. void CDSMMuxerFilter::MuxInit()
  133. {
  134. m_sps.RemoveAll();
  135. m_isps.RemoveAll();
  136. m_rtPrevSyncPoint = _I64_MIN;
  137. }
  138. void CDSMMuxerFilter::MuxHeader(IBitStream* pBS)
  139. {
  140. CString muxer;
  141. muxer.Format(_T("DSM Muxer (%s)"), CString(__TIMESTAMP__));
  142. SetProperty(L"MUXR", CStringW(muxer));
  143. SetProperty(L"DATE", CStringW(CTime::GetCurrentTime().FormatGmt(_T("%Y-%m-%d %H:%M:%S"))));
  144. MuxFileInfo(pBS);
  145. POSITION pos = m_pPins.GetHeadPosition();
  146. while(pos)
  147. {
  148. CBaseMuxerInputPin* pPin = m_pPins.GetNext(pos);
  149. const CMediaType& mt = pPin->CurrentMediaType();
  150. ASSERT((mt.lSampleSize >> 30) == 0); // you don't need >1GB samples, do you?
  151. MuxPacketHeader(pBS, DSMP_MEDIATYPE, 5 + sizeof(GUID)*3 + mt.FormatLength());
  152. pBS->BitWrite(pPin->GetID(), 8);
  153. pBS->ByteWrite(&mt.majortype, sizeof(mt.majortype));
  154. pBS->ByteWrite(&mt.subtype, sizeof(mt.subtype));
  155. pBS->BitWrite(mt.bFixedSizeSamples, 1);
  156. pBS->BitWrite(mt.bTemporalCompression, 1);
  157. pBS->BitWrite(mt.lSampleSize, 30);
  158. pBS->ByteWrite(&mt.formattype, sizeof(mt.formattype));
  159. pBS->ByteWrite(mt.Format(), mt.FormatLength());
  160. MuxStreamInfo(pBS, pPin);
  161. }
  162. // resources & chapters
  163. CInterfaceList<IDSMResourceBag> pRBs;
  164. pRBs.AddTail(this);
  165. CComQIPtr<IDSMChapterBag> pCB = (IUnknown*)(INonDelegatingUnknown*)this;
  166. pos = m_pPins.GetHeadPosition();
  167. while(pos)
  168. {
  169. for(CComPtr<IPin> pPin = m_pPins.GetNext(pos)->GetConnected(); pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin)))
  170. {
  171. if(m_fAutoRes)
  172. {
  173. CComQIPtr<IDSMResourceBag> pPB = GetFilterFromPin(pPin);
  174. if(pPB && !pRBs.Find(pPB)) pRBs.AddTail(pPB);
  175. }
  176. if(m_fAutoChap)
  177. {
  178. if(!pCB || pCB->ChapGetCount() == 0) pCB = GetFilterFromPin(pPin);
  179. }
  180. }
  181. }
  182. // resources
  183. pos = pRBs.GetHeadPosition();
  184. while(pos)
  185. {
  186. IDSMResourceBag* pRB = pRBs.GetNext(pos);
  187. for(DWORD i = 0, j = pRB->ResGetCount(); i < j; i++)
  188. {
  189. CComBSTR name, desc, mime;
  190. BYTE* pData = NULL;
  191. DWORD len = 0;
  192. if(SUCCEEDED(pRB->ResGet(i, &name, &desc, &mime, &pData, &len, NULL)))
  193. {
  194. CStringA utf8_name = UTF16To8(name);
  195. CStringA utf8_desc = UTF16To8(desc);
  196. CStringA utf8_mime = UTF16To8(mime);
  197. MuxPacketHeader(pBS, DSMP_RESOURCE, 
  198. 1 + 
  199. utf8_name.GetLength()+1 + 
  200. utf8_desc.GetLength()+1 + 
  201. utf8_mime.GetLength()+1 + 
  202. len);
  203. pBS->BitWrite(0, 2);
  204. pBS->BitWrite(0, 6); // reserved
  205. pBS->ByteWrite(utf8_name, utf8_name.GetLength()+1);
  206. pBS->ByteWrite(utf8_desc, utf8_desc.GetLength()+1);
  207. pBS->ByteWrite(utf8_mime, utf8_mime.GetLength()+1);
  208. pBS->ByteWrite(pData, len);
  209. CoTaskMemFree(pData);
  210. }
  211. }
  212. }
  213. // chapters
  214. if(pCB)
  215. {
  216. CList<CDSMChapter> chapters;
  217. REFERENCE_TIME rtPrev = 0;
  218. int len = 0;
  219. pCB->ChapSort();
  220. for(DWORD i = 0; i < pCB->ChapGetCount(); i++)
  221. {
  222. CDSMChapter c;
  223. CComBSTR name;
  224. if(SUCCEEDED(pCB->ChapGet(i, &c.rt, &name)))
  225. {
  226. REFERENCE_TIME rtDiff = c.rt - rtPrev; rtPrev = c.rt; c.rt = rtDiff;
  227. c.name = name;
  228. len += 1 + GetByteLength(myabs(c.rt)) + UTF16To8(c.name).GetLength()+1;
  229. chapters.AddTail(c);
  230. }
  231. }
  232. if(chapters.GetCount())
  233. {
  234. MuxPacketHeader(pBS, DSMP_CHAPTERS, len);
  235. pos = chapters.GetHeadPosition();
  236. while(pos)
  237. {
  238. CDSMChapter& c = chapters.GetNext(pos);
  239. CStringA name = UTF16To8(c.name);
  240. int irt = GetByteLength(myabs(c.rt));
  241. pBS->BitWrite(c.rt < 0, 1);
  242. pBS->BitWrite(irt, 3);
  243. pBS->BitWrite(0, 4);
  244. pBS->BitWrite(myabs(c.rt), irt<<3);
  245. pBS->ByteWrite((LPCSTR)name, name.GetLength()+1);
  246. }
  247. }
  248. }
  249. }
  250. void CDSMMuxerFilter::MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket)
  251. {
  252. if(pPacket->IsEOS())
  253. return;
  254. if(pPacket->pPin->CurrentMediaType().majortype == MEDIATYPE_Text)
  255. {
  256. CStringA str((char*)pPacket->pData.GetData(), pPacket->pData.GetCount());
  257. str.Replace("xff", " ");
  258. str.Replace("&nbsp;", " ");
  259. str.Replace("&nbsp", " ");
  260. str.Trim();
  261. if(str.IsEmpty())
  262. return;
  263. }
  264. ASSERT(!pPacket->IsSyncPoint() || pPacket->IsTimeValid());
  265. REFERENCE_TIME rtTimeStamp = _I64_MIN, rtDuration = 0;
  266. int iTimeStamp = 0, iDuration = 0;
  267. if(pPacket->IsTimeValid())
  268. {
  269. rtTimeStamp = pPacket->rtStart;
  270. rtDuration = max(pPacket->rtStop - pPacket->rtStart, 0);
  271. iTimeStamp = GetByteLength(myabs(rtTimeStamp));
  272. ASSERT(iTimeStamp <= 7);
  273. iDuration = GetByteLength(rtDuration);
  274. ASSERT(iDuration <= 7);
  275. IndexSyncPoint(pPacket, pBS->GetPos());
  276. }
  277. int len = 2 + iTimeStamp + iDuration + pPacket->pData.GetCount(); // id + flags + data 
  278. MuxPacketHeader(pBS, DSMP_SAMPLE, len);
  279. pBS->BitWrite(pPacket->pPin->GetID(), 8);
  280. pBS->BitWrite(pPacket->IsSyncPoint(), 1);
  281. pBS->BitWrite(rtTimeStamp < 0, 1);
  282. pBS->BitWrite(iTimeStamp, 3);
  283. pBS->BitWrite(iDuration, 3);
  284. pBS->BitWrite(myabs(rtTimeStamp), iTimeStamp<<3);
  285. pBS->BitWrite(rtDuration, iDuration<<3);
  286. pBS->ByteWrite(pPacket->pData.GetData(), pPacket->pData.GetCount());
  287. }
  288. void CDSMMuxerFilter::MuxFooter(IBitStream* pBS)
  289. {
  290. // syncpoints
  291. int len = 0;
  292. CList<IndexedSyncPoint> isps;
  293. REFERENCE_TIME rtPrev = 0, rt;
  294. UINT64 fpPrev = 0, fp;
  295. POSITION pos = m_isps.GetHeadPosition();
  296. while(pos)
  297. {
  298. IndexedSyncPoint& isp = m_isps.GetNext(pos);
  299. TRACE(_T("sp[%d]: %I64d %I64xn"), isp.id, isp.rt, isp.fp);
  300. rt = isp.rt - rtPrev; rtPrev = isp.rt;
  301. fp = isp.fp - fpPrev; fpPrev = isp.fp;
  302. IndexedSyncPoint isp2;
  303. isp2.fp = fp;
  304. isp2.rt = rt;
  305. isps.AddTail(isp2);
  306. len += 1 + GetByteLength(myabs(rt)) + GetByteLength(fp); // flags + rt + fp
  307. }
  308. MuxPacketHeader(pBS, DSMP_SYNCPOINTS, len);
  309. pos = isps.GetHeadPosition();
  310. while(pos)
  311. {
  312. IndexedSyncPoint& isp = isps.GetNext(pos);
  313. int irt = GetByteLength(myabs(isp.rt));
  314. int ifp = GetByteLength(isp.fp);
  315. pBS->BitWrite(isp.rt < 0, 1);
  316. pBS->BitWrite(irt, 3);
  317. pBS->BitWrite(ifp, 3);
  318. pBS->BitWrite(0, 1); // reserved
  319. pBS->BitWrite(myabs(isp.rt), irt<<3);
  320. pBS->BitWrite(isp.fp, ifp<<3);
  321. }
  322. }
  323. void CDSMMuxerFilter::IndexSyncPoint(const MuxerPacket* p, __int64 fp)
  324. {
  325. // Yes, this is as complicated as it looks.
  326. // Rule #1: don't write this packet if you can't do it reliably. 
  327. // (think about overlapped subtitles, line1: 0->10, line2: 1->9)
  328. // FIXME: the very last syncpoints won't get moved to m_isps because there are no more syncpoints to trigger it!
  329. if(fp < 0 || !p || !p->IsTimeValid() || !p->IsSyncPoint()) 
  330. return;
  331. ASSERT(p->rtStart >= m_rtPrevSyncPoint);
  332. m_rtPrevSyncPoint = p->rtStart;
  333. SyncPoint sp;
  334. sp.id = p->pPin->GetID();
  335. sp.rtStart = p->rtStart;
  336. sp.rtStop = p->pPin->IsSubtitleStream() ? p->rtStop : _I64_MAX;
  337. sp.fp = fp;
  338. {
  339. SyncPoint& head = !m_sps.IsEmpty() ? m_sps.GetHead() : sp;
  340. SyncPoint& tail = !m_sps.IsEmpty() ? m_sps.GetTail() : sp;
  341. REFERENCE_TIME rtfp = !m_isps.IsEmpty() ? m_isps.GetTail().rtfp : _I64_MIN;
  342. if(head.rtStart > rtfp + 1000000) // 100ms limit, just in case every stream had only keyframes, then sycnpoints would be too frequent
  343. {
  344. IndexedSyncPoint isp;
  345. isp.id = head.id;
  346. isp.rt = tail.rtStart;
  347. isp.rtfp = head.rtStart;
  348. isp.fp = head.fp;
  349. m_isps.AddTail(isp);
  350. }
  351. }
  352. POSITION pos = m_sps.GetHeadPosition();
  353. while(pos)
  354. {
  355. POSITION cur = pos;
  356. SyncPoint& sp2 = m_sps.GetNext(pos);
  357. if(sp2.id == sp.id && sp2.rtStop <= sp.rtStop || sp2.rtStop <= sp.rtStart)
  358. m_sps.RemoveAt(cur);
  359. }
  360. m_sps.AddTail(sp);
  361. }