MpegSplitterFile.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 <mmreg.h>
  23. #include "MpegSplitterFile.h"
  24. #include <initguid.h>
  25. #include "........includemoreuuids.h"
  26. #define MEGABYTE 1024*1024
  27. #define ISVALIDPID(pid) (pid >= 0x10 && pid < 0x1fff)
  28. CMpegSplitterFile::CMpegSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr)
  29. : CBaseSplitterFileEx(pAsyncReader, hr)
  30. , m_type(us)
  31. , m_rate(0)
  32. {
  33. if(SUCCEEDED(hr)) hr = Init();
  34. }
  35. HRESULT CMpegSplitterFile::Init()
  36. {
  37. HRESULT hr;
  38. // get the type first
  39. m_type = us;
  40. Seek(0);
  41. if(m_type == us)
  42. {
  43. int cnt = 0, limit = 4;
  44. for(trhdr h; cnt < limit && Read(h); cnt++) Seek(h.next);
  45. if(cnt >= limit) m_type = ts;
  46. }
  47. Seek(0);
  48. if(m_type == us)
  49. {
  50. int cnt = 0, limit = 4;
  51. for(pvahdr h; cnt < limit && Read(h); cnt++) Seek(GetPos() + h.length);
  52. if(cnt >= limit) m_type = pva;
  53. }
  54. Seek(0);
  55. if(m_type == us)
  56. {
  57. BYTE b;
  58. for(int i = 0; (i < 4 || GetPos() < 65536) && m_type == us && NextMpegStartCode(b); i++)
  59. {
  60. if(b == 0xba)
  61. {
  62. pshdr h;
  63. if(Read(h)) 
  64. {
  65. m_type = ps;
  66. m_rate = h.bitrate/8;
  67. break;
  68. }
  69. }
  70. else if((b&0xe0) == 0xc0 // audio, 110xxxxx, mpeg1/2/3
  71. || (b&0xf0) == 0xe0 // video, 1110xxxx, mpeg1/2
  72. // || (b&0xbd) == 0xbd) // private stream 1, 0xbd, ac3/dts/lpcm/subpic
  73. || b == 0xbd) // private stream 1, 0xbd, ac3/dts/lpcm/subpic
  74. {
  75. peshdr h;
  76. if(Read(h, b))
  77. {
  78. m_type = es;
  79. }
  80. }
  81. }
  82. }
  83. Seek(0);
  84. if(m_type == us)
  85. {
  86. return E_FAIL;
  87. }
  88. //
  89. if(IsStreaming())
  90. {
  91. for(int i = 0; i < 50 && GetLength() < 1024*100 || i < 20; i++)
  92. Sleep(100);
  93. }
  94. // min/max pts & bitrate
  95. m_rtMin = m_posMin = _I64_MAX;
  96. m_rtMax = m_posMax = 0;
  97. CList<__int64> fps;
  98. for(int i = 0, j = 5; i <= j; i++)
  99. fps.AddTail(i*GetLength()/j);
  100. for(__int64 pfp = 0; fps.GetCount(); )
  101. {
  102. __int64 fp = fps.RemoveHead();
  103. fp = min(GetLength() - MEGABYTE/8, fp);
  104. fp = max(pfp, fp);
  105. __int64 nfp = fp + (pfp == 0 ? 5*MEGABYTE : MEGABYTE/8);
  106. if(FAILED(hr = SearchStreams(fp, nfp)))
  107. return hr;
  108. pfp = nfp;
  109. }
  110. if(m_posMax - m_posMin <= 0 || m_rtMax - m_rtMin <= 0)
  111. return E_FAIL;
  112. int indicated_rate = m_rate;
  113. int detected_rate = 10000000i64 * (m_posMax - m_posMin) / (m_rtMax - m_rtMin);
  114. // normally "detected" should always be less than "indicated", but sometimes it can be a few percent higher (+10% is allowed here)
  115. // (update: also allowing +/-50k/s)
  116. if(indicated_rate == 0 || ((float)detected_rate / indicated_rate) < 1.1
  117. || abs(detected_rate - indicated_rate) < 50*1024)
  118. m_rate = detected_rate;
  119. else ; // TODO: in this case disable seeking, or try doing something less drastical...
  120. #ifndef DEBUG
  121. if(m_streams[video].GetCount() || m_streams[subpic].GetCount())
  122. {
  123. stream s;
  124. s.mt.majortype = MEDIATYPE_Video;
  125. s.mt.subtype = MEDIASUBTYPE_DVD_SUBPICTURE;
  126. s.mt.formattype = FORMAT_None;
  127. m_streams[subpic].Insert(s);
  128. }
  129. #endif
  130. Seek(0);
  131. return S_OK;
  132. }
  133. REFERENCE_TIME CMpegSplitterFile::NextPTS(DWORD TrackNum)
  134. {
  135. REFERENCE_TIME rt = -1;
  136. __int64 rtpos = -1;
  137. BYTE b;
  138. while(GetPos() < GetLength())
  139. {
  140. if(m_type == ps || m_type == es)
  141. {
  142. if(!NextMpegStartCode(b)) // continue;
  143. {ASSERT(0); break;}
  144. rtpos = GetPos()-4;
  145. if(b >= 0xbd && b < 0xf0)
  146. {
  147. peshdr h;
  148. if(!Read(h, b) || !h.len) continue;
  149. __int64 pos = GetPos();
  150. if(h.fpts && AddStream(0, b, h.len) == TrackNum)
  151. {
  152. ASSERT(h.pts >= m_rtMin && h.pts <= m_rtMax);
  153. rt = h.pts;
  154. break;
  155. }
  156. Seek(pos + h.len);
  157. }
  158. }
  159. else if(m_type == ts)
  160. {
  161. trhdr h;
  162. if(!Read(h)) continue;
  163. rtpos = GetPos()-4;
  164. if(h.payload && h.payloadstart && ISVALIDPID(h.pid))
  165. {
  166. peshdr h2;
  167. if(NextMpegStartCode(b, 4) && Read(h2, b)) // pes packet
  168. {
  169. if(h2.fpts && AddStream(h.pid, b, h.bytes - (GetPos() - rtpos)) == TrackNum)
  170. {
  171. ASSERT(h2.pts >= m_rtMin && h2.pts <= m_rtMax);
  172. rt = h2.pts;
  173. break;
  174. }
  175. }
  176. }
  177. Seek(h.next);
  178. }
  179. else if(m_type == pva)
  180. {
  181. pvahdr h;
  182. if(!Read(h)) continue;
  183. if(h.fpts)
  184. {
  185. rt = h.pts;
  186. break;
  187. }
  188. }
  189. }
  190. if(rtpos >= 0) Seek(rtpos);
  191. if(rt >= 0) rt -= m_rtMin;
  192. return rt;
  193. }
  194. HRESULT CMpegSplitterFile::SearchStreams(__int64 start, __int64 stop)
  195. {
  196. Seek(start);
  197. stop = min(stop, GetLength());
  198. while(GetPos() < stop)
  199. {
  200. BYTE b;
  201. if(m_type == ps || m_type == es)
  202. {
  203. if(!NextMpegStartCode(b)) continue;
  204. if(b == 0xba) // program stream header
  205. {
  206. pshdr h;
  207. if(!Read(h)) continue;
  208. }
  209. else if(b == 0xbb) // program stream system header
  210. {
  211. pssyshdr h;
  212. if(!Read(h)) continue;
  213. }
  214. else if(b >= 0xbd && b < 0xf0) // pes packet
  215. {
  216. peshdr h;
  217. if(!Read(h, b)) continue;
  218. if(h.type == mpeg2 && h.scrambling) {ASSERT(0); return E_FAIL;}
  219. if(h.fpts)
  220. {
  221. if(m_rtMin == _I64_MAX) {m_rtMin = h.pts; m_posMin = GetPos();}
  222. if(m_rtMin < h.pts && m_rtMax < h.pts) {m_rtMax = h.pts; m_posMax = GetPos();}
  223. /*
  224. int rate = 10000000i64 * (m_posMax - m_posMin) / (m_rtMax - m_rtMin); 
  225. if(m_rate == 0) m_rate = rate;
  226. TRACE(_T("rate = %d (%d), (h.pts = %I64d)n"), rate, rate - m_rate, h.pts);
  227. m_rate = rate;
  228. */
  229. }
  230. __int64 pos = GetPos();
  231. AddStream(0, b, h.len);
  232. if(h.len) Seek(pos + h.len);
  233. }
  234. }
  235. else if(m_type == ts)
  236. {
  237. trhdr h;
  238. if(!Read(h)) continue;
  239. // if(h.scrambling) {ASSERT(0); return E_FAIL;}
  240. __int64 pos = GetPos();
  241. if(h.payload && ISVALIDPID(h.pid))
  242. {
  243. peshdr h2;
  244. if(h.payloadstart && NextMpegStartCode(b, 4) && Read(h2, b)) // pes packet
  245. {
  246. if(h2.type == mpeg2 && h2.scrambling) {ASSERT(0); return E_FAIL;}
  247. if(h2.fpts)
  248. {
  249. if(m_rtMin == _I64_MAX) {m_rtMin = h2.pts; m_posMin = GetPos();}
  250. if(m_rtMin < h2.pts && m_rtMax < h2.pts) {m_rtMax = h2.pts; m_posMax = GetPos();}
  251. }
  252. }
  253. else
  254. {
  255. b = 0;
  256. }
  257. AddStream(h.pid, b, h.bytes - (GetPos() - pos));
  258. }
  259. Seek(h.next);
  260. }
  261. else if(m_type == pva)
  262. {
  263. pvahdr h;
  264. if(!Read(h)) continue;
  265. if(h.fpts)
  266. {
  267. if(m_rtMin == _I64_MAX) {m_rtMin = h.pts; m_posMin = GetPos();}
  268. if(m_rtMin < h.pts && m_rtMax < h.pts) {m_rtMax = h.pts; m_posMax = GetPos();}
  269. }
  270. __int64 pos = GetPos();
  271. if(h.streamid == 1) AddStream(h.streamid, 0xe0, h.length);
  272. else if(h.streamid == 2) AddStream(h.streamid, 0xc0, h.length);
  273. if(h.length) Seek(pos + h.length);
  274. }
  275. }
  276. return S_OK;
  277. }
  278. DWORD CMpegSplitterFile::AddStream(WORD pid, BYTE pesid, DWORD len)
  279. {
  280. if(pid)
  281. {
  282. if(pesid) m_pid2pes[pid] = pesid;
  283. else m_pid2pes.Lookup(pid, pesid);
  284. }
  285. stream s;
  286. s.pid = pid;
  287. s.pesid = pesid;
  288. int type = unknown;
  289. if(pesid >= 0xe0 && pesid < 0xf0) // mpeg video
  290. {
  291. __int64 pos = GetPos();
  292. if(type == unknown)
  293. {
  294. CMpegSplitterFile::seqhdr h;
  295. if(!m_streams[video].Find(s) && Read(h, len, &s.mt))
  296. type = video;
  297. }
  298. Seek(pos);
  299. if(type == unknown)
  300. {
  301. CMpegSplitterFile::avchdr h;
  302. if(!m_streams[video].Find(s) && Read(h, len, &s.mt))
  303. type = video;
  304. }
  305. }
  306. else if(pesid >= 0xc0 && pesid < 0xe0) // mpeg audio
  307. {
  308. __int64 pos = GetPos();
  309. if(type == unknown)
  310. {
  311. CMpegSplitterFile::mpahdr h;
  312. if(!m_streams[audio].Find(s) && Read(h, len, false, &s.mt))
  313. type = audio;
  314. }
  315. Seek(pos);
  316. if(type == unknown)
  317. {
  318. CMpegSplitterFile::aachdr h;
  319. if(!m_streams[audio].Find(s) && Read(h, len, &s.mt))
  320. type = audio;
  321. }
  322. }
  323. else if(pesid == 0xbd) // private stream 1
  324. {
  325. if(s.pid)
  326. {
  327. if(!m_streams[audio].Find(s))
  328. {
  329. __int64 pos = GetPos();
  330. if(type == unknown)
  331. {
  332. CMpegSplitterFile::ac3hdr h;
  333. if(Read(h, len, &s.mt))
  334. type = audio;
  335. }
  336. Seek(pos);
  337. if(type == unknown)
  338. {
  339. CMpegSplitterFile::dtshdr h;
  340. if(Read(h, len, &s.mt))
  341. type = audio;
  342. }
  343. }
  344. }
  345. else
  346. {
  347. BYTE b = (BYTE)BitRead(8, true);
  348. WORD w = (WORD)BitRead(16, true);
  349. DWORD dw = (DWORD)BitRead(32, true);
  350. if(b >= 0x80 && b < 0x88 || w == 0x0b77) // ac3
  351. {
  352. s.ps1id = (b >= 0x80 && b < 0x88) ? (BYTE)(BitRead(32) >> 24) : 0x80;
  353. CMpegSplitterFile::ac3hdr h;
  354. if(!m_streams[audio].Find(s) && Read(h, len, &s.mt))
  355. type = audio;
  356. }
  357. else if(b >= 0x88 && b < 0x90 || dw == 0x7ffe8001) // dts
  358. {
  359. s.ps1id = (b >= 0x88 && b < 0x90) ? (BYTE)(BitRead(32) >> 24) : 0x88;
  360. CMpegSplitterFile::dtshdr h;
  361. if(!m_streams[audio].Find(s) && Read(h, len, &s.mt))
  362. type = audio;
  363. }
  364. else if(b >= 0xa0 && b < 0xa8) // lpcm
  365. {
  366. s.ps1id = (b >= 0xa0 && b < 0xa8) ? (BYTE)(BitRead(32) >> 24) : 0xa0;
  367. CMpegSplitterFile::lpcmhdr h;
  368. if(Read(h, &s.mt) && !m_streams[audio].Find(s)) // note the reversed order, the header should be stripped always even if it's not a new stream
  369. type = audio;
  370. }
  371. else if(b >= 0x20 && b < 0x40) // DVD subpic
  372. {
  373. s.ps1id = (BYTE)BitRead(8);
  374. CMpegSplitterFile::dvdspuhdr h;
  375. if(!m_streams[subpic].Find(s) && Read(h, &s.mt))
  376. type = subpic;
  377. }
  378. else if(b >= 0x70 && b < 0x80) // SVCD subpic
  379. {
  380. s.ps1id = (BYTE)BitRead(8);
  381. CMpegSplitterFile::svcdspuhdr h;
  382. if(!m_streams[subpic].Find(s) && Read(h, &s.mt))
  383. type = subpic;
  384. }
  385. else if(b >= 0x00 && b < 0x10) // CVD subpic
  386. {
  387. s.ps1id = (BYTE)BitRead(8);
  388. CMpegSplitterFile::cvdspuhdr h;
  389. if(!m_streams[subpic].Find(s) && Read(h, &s.mt))
  390. type = subpic;
  391. }
  392. else if(w == 0xffa0 || w == 0xffa1) // ps2-mpg audio
  393. {
  394. s.ps1id = (BYTE)BitRead(8);
  395. s.pid = (WORD)((BitRead(8) << 8) | BitRead(16)); // pid = 0xa000 | track id
  396. CMpegSplitterFile::ps2audhdr h;
  397. if(!m_streams[audio].Find(s) && Read(h, &s.mt))
  398. type = audio;
  399. }
  400. else if(w == 0xff90) // ps2-mpg ac3 or subtitles
  401. {
  402. s.ps1id = (BYTE)BitRead(8);
  403. s.pid = (WORD)((BitRead(8) << 8) | BitRead(16)); // pid = 0x9000 | track id
  404. w = BitRead(16, true);
  405. if(w == 0x0b77)
  406. {
  407. CMpegSplitterFile::ac3hdr h;
  408. if(!m_streams[audio].Find(s) && Read(h, len, &s.mt))
  409. type = audio;
  410. }
  411. else if(w == 0x0000) // usually zero...
  412. {
  413. CMpegSplitterFile::ps2subhdr h;
  414. if(!m_streams[subpic].Find(s) && Read(h, &s.mt))
  415. type = subpic;
  416. }
  417. }
  418. }
  419. }
  420. else if(pesid == 0xbe) // padding
  421. {
  422. }
  423. else if(pesid == 0xbf) // private stream 2
  424. {
  425. }
  426. if(type != unknown && !m_streams[type].Find(s))
  427. {
  428. if(s.pid)
  429. {
  430. for(int i = 0; i < unknown; i++)
  431. {
  432. if(m_streams[i].Find(s)) {/*ASSERT(0);*/ return s;}
  433. }
  434. }
  435. m_streams[type].Insert(s);
  436. }
  437. return s;
  438. }