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

多媒体编程

开发平台:

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 "vobsubfileripper.h"
  23. #include "..decssVobDec.h"
  24. #include "..subtitlesCCDecoder.h"
  25. //
  26. // CVobSubFileRipper
  27. //
  28. CVobSubFileRipper::CVobSubFileRipper()
  29. : CVobSubFile(NULL)
  30. , m_fThreadActive(false)
  31. , m_fBreakThread(false)
  32. , m_fIndexing(false)
  33. {
  34. m_rd.Reset();
  35. CAMThread::Create();
  36. }
  37. CVobSubFileRipper::~CVobSubFileRipper()
  38. {
  39. CAMThread::CallWorker(CMD_EXIT);
  40. CAMThread::Close();
  41. }
  42. STDMETHODIMP CVobSubFileRipper::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  43. {
  44. return 
  45. QI(IVSFRipper)
  46. __super::NonDelegatingQueryInterface(riid, ppv);
  47. }
  48. void CVobSubFileRipper::Log(log_t type, LPCTSTR lpszFormat, ...)
  49. {
  50. CAutoLock cAutoLock(&m_csCallback);
  51. if(!m_pCallback) return;
  52. TCHAR buff[1024];
  53. va_list args;
  54. va_start(args, lpszFormat);
  55. _vstprintf(buff, lpszFormat, args);
  56. va_end(args);
  57. CString msg;
  58. switch(type)
  59. {
  60. default:
  61. case LOG_INFO: msg = _T(""); break;
  62. case LOG_WARNING: msg = _T("WARNING: "); break;
  63. case LOG_ERROR: msg = _T("ERROR: "); break;
  64. }
  65. msg += buff;
  66. m_pCallback->OnMessage(msg);
  67. }
  68. void CVobSubFileRipper::Progress(double progress)
  69. {
  70. CAutoLock cAutoLock(&m_csCallback);
  71. if(!m_pCallback) return;
  72. m_pCallback->OnProgress(progress);
  73. }
  74. void CVobSubFileRipper::Finished(bool fSucceeded)
  75. {
  76. CAutoLock cAutoLock(&m_csCallback);
  77. if(!m_pCallback) return;
  78. m_pCallback->OnFinished(fSucceeded);
  79. }
  80. #define ReadBEb(var) 
  81. f.Read(&((BYTE*)&var)[0], 1); 
  82. #define ReadBEw(var) 
  83. f.Read(&((BYTE*)&var)[1], 1); 
  84. f.Read(&((BYTE*)&var)[0], 1); 
  85. #define ReadBEdw(var) 
  86.     f.Read(&((BYTE*)&var)[3], 1); 
  87. f.Read(&((BYTE*)&var)[2], 1); 
  88. f.Read(&((BYTE*)&var)[1], 1); 
  89. f.Read(&((BYTE*)&var)[0], 1); 
  90. bool CVobSubFileRipper::LoadIfo(CString fn)
  91. {
  92. CString str;
  93. CFileStatus status;
  94. if(!CFileGetStatus(fn, status) || !status.m_size)
  95. {
  96. Log(LOG_ERROR, _T("Invalid ifo"));
  97. return(false);
  98. }
  99. CFile f;
  100. if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
  101. {
  102. Log(LOG_ERROR, _T("Cannot open ifo"));
  103. return(false);
  104. }
  105. Log(LOG_INFO, _T("Opening ifo OK"));
  106. char hdr[13];
  107. f.Read(hdr, 12);
  108. hdr[12] = 0;
  109. if(strcmp(hdr, "DVDVIDEO-VTS"))
  110. {
  111. Log(LOG_ERROR, _T("Not a Video Title Set IFO file!"));
  112. return(false);
  113. }
  114. // lang ids
  115. f.Seek(0x254, CFile::begin);
  116. WORD ids[32];
  117. memset(ids, 0, sizeof(ids));
  118. int len = 0;
  119. ReadBEw(len);
  120. for(int i = 0; i < len; i++)
  121. {
  122. f.Seek(2, CFile::current); // 01 00 ?
  123. ReadBEw(ids[i]);
  124. if(ids[i] == 0) ids[i] = '--';
  125. f.Seek(2, CFile::current); // 00 00 ?
  126. }
  127. /* Video info */
  128. f.Seek(0x200, CFile::begin);
  129. f.Read(&m_rd.vidinfo, 2);
  130. SIZE res[4][2] =
  131. {
  132. {{720,480},{720,576}},
  133. {{704,480},{704,576}},
  134. {{352,480},{352,576}},
  135. {{352,240},{352,288}}
  136. };
  137. m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system&1];
  138. double rate = (m_rd.vidinfo.system == 0) ? 30.0/29.97 : 1.0;
  139. /* PGCs */
  140. {
  141. DWORD offset;
  142. DWORD pgcpos;
  143. f.Seek(0xc0+0x0c, CFile::begin);
  144. ReadBEdw(pgcpos);
  145. pgcpos *= 0x800;
  146. WORD nPGC;
  147. f.Seek(pgcpos, CFile::begin);
  148. ReadBEw(nPGC);
  149. m_rd.pgcs.RemoveAll();
  150. m_rd.pgcs.SetSize(nPGC);
  151. for(int i = 0; i < nPGC; i++)
  152. {
  153. PGC& pgc = m_rd.pgcs[i];
  154. f.Seek(pgcpos + 8 + i*8 + 4, CFile::begin);
  155. ReadBEdw(offset);
  156. offset += pgcpos;
  157. BYTE nProgs, nCells;
  158. f.Seek(offset + 2, CFile::begin);
  159. ReadBEb(nProgs);
  160. ReadBEb(nCells);
  161. //
  162. memcpy(pgc.ids, ids, sizeof(ids));
  163. struct splanginfo {BYTE res1, id1, id2, res2;};
  164. splanginfo splinfo[32];
  165. f.Seek(offset + 0x1c, CFile::begin);
  166. f.Read(splinfo, 32*4);
  167. for(int j = 0; j < 32; j++) 
  168. {
  169. if(splinfo[j].id1 || splinfo[i].id2) 
  170. {
  171. WORD tmpids[32];
  172. memset(tmpids, 0, sizeof(tmpids));
  173. for(j = 0; j < 32; j++) 
  174. {
  175. if(!(splinfo[j].res1 & 0x80)) break;
  176. pgc.ids[splinfo[j].id1] = ids[j];
  177. pgc.ids[splinfo[j].id2] = ids[j];
  178. }
  179. break;
  180. }
  181. }
  182. //
  183. f.Seek(offset + 0xa4, CFile::begin);
  184. for(int j = 0; j < 16; j++) 
  185. {
  186. BYTE y, u, v, tmp;
  187. f.Read(&tmp, 1);
  188. f.Read(&y, 1);
  189. f.Read(&u, 1);
  190. f.Read(&v, 1);
  191. y = (y-16)*255/219;
  192. pgc.pal[j].rgbRed = (BYTE)min(max(1.0*y + 1.4022*(u-128), 0), 255);
  193. pgc.pal[j].rgbGreen = (BYTE)min(max(1.0*y - 0.3456*(u-128) - 0.7145*(v-128), 0), 255);
  194. pgc.pal[j].rgbBlue = (BYTE)min(max(1.0*y + 1.7710*(v-128), 0) , 255);
  195. }
  196. //
  197. WORD progoff, celladdroff, vobcelloff;
  198. f.Seek(offset + 0xe6, CFile::begin);
  199. ReadBEw(progoff);
  200. f.Seek(offset + 0xe8, CFile::begin);
  201. ReadBEw(celladdroff);
  202. f.Seek(offset + 0xea, CFile::begin);
  203. ReadBEw(vobcelloff);
  204. //
  205.             CByteArray progs;
  206. progs.SetSize(nProgs);
  207. f.Seek(offset + progoff, CFile::begin);
  208. f.Read(progs.GetData(), nProgs);
  209. //
  210. pgc.angles[0].SetSize(nCells);
  211. pgc.iSelAngle = 0;
  212. //
  213. f.Seek(offset + vobcelloff, CFile::begin);
  214. for(int j = 0; j < nCells; j++)
  215. {
  216. ReadBEw(pgc.angles[0][j].vob);
  217. ReadBEw(pgc.angles[0][j].cell);
  218. }
  219. //
  220. DWORD tOffset = 0, tTotal = 0;
  221. int iAngle = 0;
  222. pgc.nAngles = 0;
  223. f.Seek(offset + celladdroff, CFile::begin);
  224. for(int j = 0; j < nCells; j++)
  225. {
  226. BYTE b;
  227. ReadBEb(b);
  228. switch(b>>6)
  229. {
  230. case 0: iAngle = 0; break; // normal
  231. case 1: iAngle = 1; break; // first angle block
  232. case 2: iAngle++; break; // middle angle block
  233. case 3: iAngle++; break; // last angle block (no more should follow)
  234. }
  235. pgc.angles[0][j].iAngle = iAngle;
  236. pgc.nAngles = max(pgc.nAngles, iAngle);
  237. f.Seek(3, CFile::current);
  238. ReadBEdw(pgc.angles[0][j].tTime);
  239. ReadBEdw(pgc.angles[0][j].start);
  240. f.Seek(8, CFile::current);
  241. ReadBEdw(pgc.angles[0][j].end);
  242. float fps;
  243. switch((pgc.angles[0][j].tTime>>6)&0x3)
  244. {
  245. default:
  246. case 3: fps = 30; break;
  247. case 1: fps = 25; break;
  248. }
  249. int t = pgc.angles[0][j].tTime;
  250. int hh = ((t>>28)&0xf)*10+((t>>24)&0xf);
  251. int mm = ((t>>20)&0xf)*10+((t>>16)&0xf);
  252. int ss = ((t>>12)&0xf)*10+((t>>8)&0xf);
  253. int ms = (int)(1000.0 * (((t>>4)&0x3)*10+((t>>0)&0xf)) / fps);
  254. pgc.angles[0][j].tTime = (DWORD)((((hh*60+mm)*60+ss)*1000+ms)*rate);
  255. // time discontinuity
  256. if(b&0x02) tOffset = tTotal;
  257. pgc.angles[0][j].fDiscontinuity = !!(b&0x02);
  258. pgc.angles[0][j].tTotal = tTotal;
  259. pgc.angles[0][j].tOffset = tOffset;
  260. tTotal += pgc.angles[0][j].tTime;
  261. }
  262. for(iAngle = 1; iAngle <= 9; iAngle++)
  263. {
  264. tOffset = tTotal = 0;
  265. for(int j = 0, k = 0; j < nCells; j++)
  266. {
  267. if(pgc.angles[0][j].iAngle != 0
  268. && pgc.angles[0][j].iAngle != iAngle)
  269. continue;
  270. pgc.angles[iAngle].Add(pgc.angles[0][j]);
  271. if(pgc.angles[iAngle][k].fDiscontinuity) tOffset = tTotal;
  272. pgc.angles[iAngle][k].tTotal = tTotal;
  273. pgc.angles[iAngle][k].tOffset = tOffset;
  274. tTotal += pgc.angles[iAngle][k].tTime;
  275. k++;
  276. }
  277. }
  278. }
  279. }
  280.     Log(LOG_INFO, _T("Parsing ifo OK"));
  281. return(true);
  282. }
  283. bool CVobSubFileRipper::LoadVob(CString fn)
  284. {
  285. Log(LOG_INFO, _T("Searching vobs..."));
  286. /*
  287. CList<CString> m_vobs;
  288. fn = fn.Left(fn.ReverseFind('.')+1);
  289. fn.TrimRight(_T(".0123456789"));
  290. for(int i = 0; i < 100; i++)
  291. {
  292. CString vob;
  293. vob.Format(_T("%s%d.vob"), fn, i);
  294. CFileStatus status;
  295. if(!(CFileGetStatus(vob, status) && status.m_size))
  296. {
  297. if(i > 0) break;
  298. else continue;
  299. }
  300. if(status.m_size&0x7ff)
  301. {
  302. Log(LOG_ERROR, _T("Length of %s is not n*2048!"), vob);
  303. m_vobs.RemoveAll();
  304. break;
  305. }
  306. CString str = _T("Found ") + vob;
  307. if(i == 0) 
  308. {
  309. str += _T(" (skipping, if not a menu vob rename it)");
  310. }
  311. else
  312. {
  313. m_vobs.AddTail(vob);
  314. }
  315. Log(LOG_INFO, str);
  316. }
  317. if(m_vobs.GetCount() <= 0)
  318. {
  319. Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn);
  320. return(false);
  321. }
  322. */
  323. CList<CString> vobs;
  324. if(!m_vob.Open(fn, vobs/*m_vobs*/))
  325. {
  326. Log(LOG_ERROR, _T("Cannot open vob sequence"));
  327. return(false);
  328. }
  329. if(vobs.GetCount() <= 0)
  330. {
  331. Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn);
  332. return(false);
  333. }
  334. POSITION pos = vobs.GetHeadPosition();
  335. while(pos) Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos));
  336. if(m_vob.IsDVD())
  337. {
  338. Log(LOG_INFO, _T("DVD detected..."));
  339. BYTE key[5];
  340. if(m_vob.HasDiscKey(key))
  341. Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]);
  342. else
  343. Log(LOG_WARNING, _T("Couldn't get the disc key"));
  344. if(m_vob.HasTitleKey(key))
  345. Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]);
  346. else
  347. Log(LOG_WARNING, _T("Couldn't get the title key"));
  348. BYTE buff[2048];
  349. m_vob.Seek(0);
  350. if(!m_vob.Read(buff))
  351. {
  352. Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!"));
  353. return(false);
  354. }
  355. m_vob.Seek(0);
  356. }
  357. return(true);
  358. }
  359. DWORD CVobSubFileRipper::ThreadProc()
  360. {
  361. SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL);
  362.     while(1)
  363. {
  364. DWORD cmd = GetRequest();
  365. m_fThreadActive = true;
  366. switch(cmd)
  367. {
  368. case CMD_EXIT:
  369.     Reply(S_OK);
  370. return 0;
  371. case CMD_INDEX:
  372. Reply(S_OK);
  373. {
  374. m_fIndexing = true;
  375. bool fSucceeded = Create();
  376. m_fIndexing = false;
  377. Finished(fSucceeded);
  378. }
  379. break;
  380. default:
  381.     Reply(E_FAIL);
  382. return -1;
  383. }
  384. m_fBreakThread = false;
  385. m_fThreadActive = false;
  386. }
  387. return 1;
  388. }
  389. static int SubPosSortProc(const void* e1, const void* e2)
  390. {
  391. return((int)(((CVobSubFile::SubPos*)e1)->start - ((CVobSubFile::SubPos*)e2)->start));
  392. }
  393. bool CVobSubFileRipper::Create()
  394. {
  395. CAutoLock cAutoLock(&m_csAccessLock);
  396. if(m_rd.iSelPGC < 0 || m_rd.iSelPGC >= m_rd.pgcs.GetCount())
  397. {
  398. Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC);
  399. return(false);
  400. }
  401. PGC& pgc = m_rd.pgcs[m_rd.iSelPGC];
  402. if(pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].GetCount() == 0)
  403. {
  404. Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle);
  405. return(false);
  406. }
  407. CArray<vc_t>& angle = pgc.angles[pgc.iSelAngle];
  408. if(m_rd.selids.GetCount() == 0 && !m_rd.fClosedCaption)
  409. {
  410. Log(LOG_ERROR, _T("No valid stream set to be extacted!"));
  411. return(false);
  412. }
  413. if(m_rd.selvcs.GetCount() == 0)
  414. {
  415. Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!"));
  416. return(false);
  417. }
  418. Log(LOG_INFO, _T("Indexing..."));
  419. // initalize CVobSubFile
  420. CVobSubFile::Close();
  421. InitSettings();
  422. m_title = m_outfn;
  423. m_size = m_rd.vidsize;
  424. TrimExtension(m_title);
  425. memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal));
  426. m_sub.SetLength(0);
  427. CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw"));
  428. CVobDec vd;
  429. __int64 SCR, PTS, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0;
  430. int vob = 0, cell = 0;
  431. bool fDiscontinuity = false, fDiscontinuityFixApplied = false, fNavpackFound = false;
  432. int PTSframeoffset = 0, minPTSframeoffset = 0;
  433. if(m_rd.fResetTime)
  434. {
  435. for(int i = 0; i < angle.GetCount() && ((angle[i].vob<<16)|angle[i].cell) != m_rd.selvcs[0]; i++)
  436. tStart += angle[i].tTime;
  437. Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), 
  438. tStart, m_rd.selvcs[0]>>16, m_rd.selvcs[0]&0xffff);
  439. }
  440. CMap<DWORD, DWORD, int, int> selvcmap;
  441. selvcmap.RemoveAll();
  442. for(int i = 0; i < m_rd.selvcs.GetCount(); i++)
  443. selvcmap[m_rd.selvcs[i]] = 90000;
  444. CArray<vcchunk> chunks, foundchunks, loadedchunks;
  445. if(m_vob.IsDVD())
  446. {
  447. Log(LOG_INFO, _T("Indexing mode: DVD"));
  448. for(int i = 0; i < angle.GetCount(); i++)
  449. {
  450. UINT vc = (angle[i].vob<<16)|angle[i].cell;
  451. if(selvcmap.PLookup(vc) == NULL)
  452. continue;
  453. vcchunk c = {2048i64*angle[i].start, 2048i64*angle[i].end+2048, vc};
  454. chunks.Add(c);
  455. Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), 
  456. angle[i].start, angle[i].end, angle[i].vob, angle[i].cell);
  457. }
  458. }
  459. else if(LoadChunks(loadedchunks))
  460. {
  461. Log(LOG_INFO, _T("Indexing mode: File"));
  462. for(int i = 0; i < loadedchunks.GetCount(); i++)
  463. {
  464. UINT vcid = loadedchunks[i].vc;
  465. if(selvcmap.PLookup(vcid) == NULL)
  466. continue;
  467. chunks.Add(loadedchunks[i]);
  468. }
  469. Log(LOG_INFO, _T(".chunk file loaded"));
  470. }
  471. else
  472. {
  473. Log(LOG_INFO, _T("Indexing mode: File"));
  474. chunks.RemoveAll();
  475. vcchunk c = {0, 2048i64*m_vob.GetLength(), 0};
  476. chunks.Add(c);
  477. }
  478. __int64 sizedone = 0, sizetotal = 0;
  479. for(int i = 0; i < chunks.GetCount(); i++)
  480. sizetotal += chunks[i].end - chunks[i].start;
  481. for(int i = 0; !m_fBreakThread && i < chunks.GetCount(); i++)
  482. {
  483. __int64 curpos = chunks[i].start, endpos = chunks[i].end;
  484. vcchunk curchunk = {curpos, curpos, chunks[i].vc};
  485. for(m_vob.Seek((int)(curpos/2048)); !m_fBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048)
  486. {
  487. if(!(curpos&0x7ffff))
  488. Progress(1.0 * sizedone / sizetotal);
  489. static BYTE buff[2048];
  490. if(!m_vob.Read(buff))
  491. {
  492. Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!"));
  493. return(false);
  494. }
  495. curchunk.end = curpos;
  496. if(buff[0x14] & 0x30)
  497. {
  498. if(!vd.m_fFoundKey)
  499. {
  500. Log(LOG_INFO, _T("Encrypted sector found, searching key..."));
  501. __int64 savepos = curpos;
  502. m_vob.Seek(0);
  503. for(__int64 pos = 0; !m_fBreakThread && pos < endpos; pos += 2048)
  504. {
  505. if(!m_vob.Read(buff))
  506. {
  507. Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!"));
  508. return(false);
  509. }
  510. if(vd.FindKey(buff))
  511. break;
  512. }
  513. if(m_fBreakThread)
  514. break;
  515. if(!vd.m_fFoundKey)
  516. {
  517. Log(LOG_ERROR, _T("Key not found, can't decrypt!"));
  518. return(false);
  519. }
  520. Log(LOG_INFO, _T("Key found, continuing extraction..."));
  521. m_vob.Seek((int)((curpos = savepos)/2048));
  522. m_vob.Read(buff);
  523. }
  524. vd.Decrypt(buff);
  525. }
  526. if(*((DWORD*)&buff[0]) != 0xba010000)
  527. {
  528. Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos/2048));
  529. if(AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO)
  530. {
  531. Log(LOG_ERROR, _T("Terminated!"));
  532. return(false);
  533. }
  534. }
  535. SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30
  536. | __int64(buff[0x04] & 0x03) << 28
  537. | __int64(buff[0x05]) << 20
  538. | (__int64(buff[0x06] & 0xf8) >> 3) << 15
  539. | __int64(buff[0x06] & 0x03) << 13
  540. | __int64(buff[0x07]) << 5
  541. | (__int64(buff[0x08] & 0xf8) >> 3) << 0;
  542. bool hasPTS = false;
  543. if((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000)
  544. && buff[0x15] & 0x80)
  545. {
  546. PTS = (__int64)(buff[0x17] & 0x0e) << 29 // 32-30 (+marker)
  547. | ((__int64)(buff[0x18]) << 22) // 29-22
  548. | ((__int64)(buff[0x19] & 0xfe) << 14) // 21-15 (+marker)
  549. | ((__int64)(buff[0x1a]) << 7) // 14-07
  550. | ((__int64)(buff[0x1b]) >> 1); // 06-00 (+marker)
  551. hasPTS = true;
  552. }
  553. if(*((DWORD*)&buff[0x0e]) == 0xbb010000)
  554. {
  555. fNavpackFound = true;
  556. if(vob == buff[0x420] && cell == buff[0x422])
  557. continue;
  558. vob = buff[0x420];
  559. cell = buff[0x422];
  560. tOffset = tTotal = 0;
  561. for(int i = 0; i < angle.GetSize(); i++)
  562. {
  563. if(angle[i].vob == vob && angle[i].cell == cell)
  564. {
  565. tPrevOffset = tOffset;
  566. tOffset = (__int64)angle[i].tOffset;
  567. tTotal = (__int64)angle[i].tTotal;
  568. fDiscontinuity = angle[i].fDiscontinuity;
  569. fDiscontinuityFixApplied = false;
  570. break;
  571. }
  572. }
  573. if(curchunk.vc != ((vob<<16)|cell))
  574. {
  575. if(curchunk.vc != 0) foundchunks.Add(curchunk);
  576. curchunk.start = curchunk.end = curpos;
  577. curchunk.vc = (vob<<16)|cell;
  578. }
  579. CString str, str2;
  580. str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos/2048));
  581. UINT vcid = (vob<<16)|cell;
  582. if(!selvcmap.Lookup(vcid, minPTSframeoffset)) str2 = _T(", skipping");
  583. else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), 
  584. tTotal, tOffset, -tStart, (int)fDiscontinuity);
  585. Log(LOG_INFO, str + str2);
  586. }
  587. UINT vcid = (vob<<16)|cell;
  588. if(!selvcmap.Lookup(vcid, minPTSframeoffset))
  589. continue;
  590. if(hasPTS && fDiscontinuity && !fDiscontinuityFixApplied)
  591. {
  592. __int64 tDiff = tOffset - tPrevOffset;
  593. if(tDiff > 0 && tDiff < (PTS/90+1000))
  594. {
  595. CString str;
  596. str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff);
  597. Log(LOG_INFO, str);
  598. tStart += tDiff;
  599. }
  600. fDiscontinuityFixApplied = true;
  601. }
  602. if(*(DWORD*)&buff[0x0e] == 0xe0010000)
  603. {
  604. if(fDiscontinuity)
  605. {
  606. if(PTS < minPTSframeoffset)
  607. {
  608. selvcmap[vcid] = PTSframeoffset = PTS;
  609. }
  610. fDiscontinuity = false;
  611. }
  612. if(m_rd.fClosedCaption)
  613. ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart);
  614. }
  615. else if(*(DWORD*)&buff[0x0e] == 0xbd010000)
  616. {
  617. BYTE id = buff[0x17 + buff[0x16]], iLang = id&0x1f;
  618. if((id & 0xe0) == 0x20 && m_rd.selids.PLookup(iLang))
  619. {
  620. if(hasPTS)
  621. {
  622. SubPos sb;
  623. sb.filepos = m_sub.GetPosition();
  624. sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart;
  625. sb.vobid = (char)vob;
  626. sb.cellid = (char)cell;
  627. sb.celltimestamp = tTotal;
  628. sb.fValid = true;
  629. m_langs[iLang].subpos.Add(sb);
  630. }
  631. m_sub.Write(buff, 2048);
  632. }
  633. }
  634. }
  635. if(curchunk.vc != ((vob<<16)|cell))
  636. {
  637. if(curchunk.vc != 0) foundchunks.Add(curchunk);
  638. curchunk.start = curchunk.end = curpos;
  639. curchunk.vc = (vob<<16)|cell;
  640. }
  641. }
  642. if(sizedone < sizetotal)
  643. {
  644. Log(LOG_ERROR, _T("Indexing terminated before reaching the end!"));
  645. Progress(0);
  646. return(false);
  647. }
  648. if(!fNavpackFound)
  649. {
  650. Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)"));
  651. if(!m_vob.IsDVD()) Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets."));
  652. Progress(0);
  653. return(false);
  654. }
  655. Log(LOG_INFO, _T("Indexing finished"));
  656. Progress(1);
  657. for(int i = 0; i < 32; i++)
  658. {
  659. if(m_iLang == -1 && m_langs[i].subpos.GetSize() > 0) m_iLang = i;
  660. m_langs[i].id = pgc.ids[i];
  661. m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id);
  662. CArray<SubPos>& sp = m_langs[i].subpos;
  663. qsort(sp.GetData(), sp.GetSize(), sizeof(SubPos), SubPosSortProc);
  664. if(m_rd.fForcedOnly)
  665. {
  666. Log(LOG_INFO, _T("Searching for forced subs..."));
  667. Progress(0);
  668. for(int j = 0, len = sp.GetCount(); j < len; j++)
  669. {
  670. Progress(1.0 * j / len);
  671. sp[j].fValid = false;
  672. int packetsize = 0, datasize = 0;
  673. if(BYTE* buff = GetPacket(j, packetsize, datasize, i))
  674. {
  675. m_img.GetPacketInfo(buff, packetsize, datasize);
  676. sp[j].fValid = m_img.fForced;
  677. delete [] buff;
  678. }
  679. }
  680. Progress(1);
  681. }
  682. }
  683. Log(LOG_INFO, _T("Saving files..."));
  684. if(m_iLang != -1)
  685. {
  686. if(!Save(m_title))
  687. {
  688. Log(LOG_ERROR, _T("Could not save output files!"));
  689. return(false);
  690. }
  691. }
  692. Log(LOG_INFO, _T("Subtitles saved"));
  693. if(!m_vob.IsDVD() && loadedchunks.GetCount() == 0)
  694. {
  695. if(SaveChunks(foundchunks))
  696. {
  697. Log(LOG_INFO, _T(".chunk file saved"));
  698. }
  699. }
  700. Log(LOG_INFO, _T("Done!"));
  701. return(true);
  702. }
  703. static const DWORD s_version = 1;
  704. bool CVobSubFileRipper::LoadChunks(CArray<vcchunk>& chunks)
  705. {
  706. CFile f;
  707. CString fn = m_infn;
  708. TrimExtension(fn);
  709. fn += _T(".chunks");
  710. DWORD chksum = 0, chunklen, version;
  711. __int64 voblen;
  712. if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
  713. return(false);
  714. f.Read(&version, sizeof(version));
  715. if(version == 1)
  716. {
  717. f.Read(&chksum, sizeof(chksum));
  718. f.Read(&voblen, sizeof(voblen));
  719. f.Read(&chunklen, sizeof(chunklen));
  720. chunks.SetSize(chunklen);
  721. f.Read(chunks.GetData(), sizeof(vcchunk)*chunks.GetCount());
  722. }
  723. f.Close();
  724. if(voblen != m_vob.GetLength())
  725. {
  726. chunks.RemoveAll();
  727. return(false);
  728. }
  729. if(!f.Open(m_infn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
  730. return(false);
  731. DWORD dw, chksum2 = 0;
  732. while(f.Read(&dw, sizeof(dw)) == sizeof(dw)) chksum2 += dw;
  733. f.Close();
  734. if(chksum != chksum2)
  735. {
  736. chunks.RemoveAll();
  737. return(false);
  738. }
  739. return(true);
  740. }
  741. bool CVobSubFileRipper::SaveChunks(CArray<vcchunk>& chunks)
  742. {
  743. CFile f;
  744. CString fn = m_infn;
  745. TrimExtension(fn);
  746. fn += _T(".chunks");
  747. DWORD chksum = 0, chunklen = chunks.GetCount();
  748. __int64 voblen = m_vob.GetLength();
  749. if(!f.Open(m_infn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
  750. return(false);
  751. DWORD dw;
  752. while(f.Read(&dw, sizeof(dw)) == sizeof(dw)) chksum += dw;
  753. f.Close();
  754. if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite))
  755. return(false);
  756. f.Write(&s_version, sizeof(s_version));
  757. f.Write(&chksum, sizeof(chksum));
  758. f.Write(&voblen, sizeof(voblen));
  759. f.Write(&chunklen, sizeof(chunklen));
  760. f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen);
  761. f.Close();
  762. return(true);
  763. }
  764. // IVSFRipper
  765. STDMETHODIMP CVobSubFileRipper::SetCallBack(IVSFRipperCallback* pCallback)
  766. {
  767. CAutoLock cAutoLock(&m_csCallback);
  768. m_pCallback = pCallback;
  769. return S_OK;
  770. }
  771. STDMETHODIMP CVobSubFileRipper::LoadParamFile(CString fn)
  772. {
  773. CAutoLock cAutoLock(&m_csAccessLock);
  774. m_rd.Reset();
  775. CStdioFile f;
  776. if(!f.Open(fn, CFile::modeRead|CFile::typeText))
  777. return E_FAIL;
  778. TCHAR langid[256];
  779. enum {P_INPUT, P_OUTPUT, P_PGC, P_ANGLE, P_LANGS, P_OPTIONS};
  780. int phase = P_INPUT;
  781. CString line;
  782. while(f.ReadString(line))
  783. {
  784. if(line.Trim().IsEmpty() || line[0] == '#') continue;
  785. if(phase == P_INPUT)
  786. {
  787. if(S_OK != SetInput(line)) break;
  788. phase = P_OUTPUT;
  789. }
  790. else if(phase == P_OUTPUT)
  791. {
  792. if(S_OK != SetOutput(line)) break;
  793. phase = P_PGC;
  794. }
  795. else if(phase == P_PGC)
  796. {
  797. m_rd.iSelPGC = _tcstol(line, NULL, 10)-1;
  798. if(m_rd.iSelPGC < 0 || m_rd.iSelPGC >= m_rd.pgcs.GetCount()) break;
  799. phase = P_ANGLE;
  800. }
  801. else if(phase == 3)
  802. {
  803. PGC& pgc = m_rd.pgcs[m_rd.iSelPGC];
  804. pgc.iSelAngle = _tcstol(line, NULL, 10);
  805. if(pgc.iSelAngle < 0 || pgc.iSelAngle > max(1, pgc.nAngles) || pgc.iSelAngle > 9) break;
  806. CArray<vc_t>& angle = pgc.angles[pgc.iSelAngle];
  807. if(line.Find('v') >= 0)
  808. {
  809. int vob = 0, cell = 0;
  810. line += ' ';
  811. TCHAR* s = (LPTSTR)(LPCTSTR)line;
  812. TCHAR* e = s + line.GetLength();
  813. while(s < e)
  814. {
  815. if(*s == 'v' || s == e-1)
  816. {
  817. s++;
  818. if(vob != 0 && cell == 0)
  819. {
  820. for(int i = 0; i < angle.GetCount(); i++)
  821. {
  822. if(angle[i].vob == vob)
  823. m_rd.selvcs.Add((angle[i].vob<<16)|angle[i].cell);
  824. }
  825. }
  826. vob = _tcstol(s, &s, 10);
  827. cell = 0;
  828. }
  829. else if(*s == 'c' && vob > 0)
  830. {
  831. s++;
  832. cell = _tcstol(s, &s, 10);
  833. for(int i = 0; i < angle.GetCount(); i++)
  834. {
  835. if(angle[i].vob == vob && angle[i].cell == cell)
  836. {
  837. m_rd.selvcs.Add((vob<<16)|cell);
  838. break;
  839. }
  840. }
  841. }
  842. else
  843. {
  844. s++;
  845. }
  846. }
  847. }
  848. else
  849. {
  850. for(int i = 0; i < angle.GetCount(); i++)
  851. m_rd.selvcs.Add((angle[i].vob<<16)|angle[i].cell);
  852. }
  853. phase = P_LANGS;
  854. }
  855. else if(phase == 4)
  856. {
  857. if(!line.CompareNoCase(_T("ALL")))
  858. {
  859. for(int i = 0; i < 32; i++) m_rd.selids[i] = true;
  860. m_rd.fClosedCaption = true;
  861. phase = P_OPTIONS;
  862. }
  863. else
  864. {
  865. line += ' ';
  866. while(line.GetLength() > 0)
  867. {
  868. int n = line.Find(_T(" "));
  869. CString lang = line.Left(n);
  870. line = line.Mid(n);
  871. line.TrimLeft();
  872. n = 0;
  873. int langnum;
  874. if(_istdigit(lang[0])) 
  875. {
  876. n = _stscanf(lang, _T("%d"), &langnum);
  877. if(n != 1) break;
  878. m_rd.selids[langnum] = true;
  879. }
  880. else if(_istalpha(lang[0])) 
  881. {
  882. n = _stscanf(lang, _T("%s"), langid);
  883. if(n != 1) break;
  884. int id = (langid[0] << 8) + langid[1];
  885. if(id == 'cc')
  886. {
  887. m_rd.fClosedCaption = true;
  888. }
  889. else
  890. {
  891. m_rd.selids[id] = true;
  892. }
  893. }
  894. else break;
  895. if(n != 1) break;
  896. }
  897. if((m_rd.selids.GetSize() > 0 || m_rd.fClosedCaption) && line.IsEmpty())
  898. phase = P_OPTIONS;
  899. }
  900. }
  901. else if(phase == 5 && !line.CompareNoCase(_T("CLOSE")))
  902. m_rd.fClose = true;
  903. else if(phase == 5 && !line.CompareNoCase(_T("BEEP")))
  904. m_rd.fBeep = true;
  905. else if(phase == 5 && !line.CompareNoCase(_T("RESETTIME")))
  906. m_rd.fResetTime = true;
  907. else if(phase == 5 && !line.CompareNoCase(_T("FORCEDONLY")))
  908. m_rd.fForcedOnly = true;
  909. else if(phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS")))
  910. m_rd.fCloseIgnoreError = true;
  911. }
  912. m_rd.fAuto = true;
  913. return phase == P_OPTIONS ? S_OK : E_FAIL;
  914. }
  915. STDMETHODIMP CVobSubFileRipper::SetInput(CString infn)
  916. {
  917. CAutoLock cAutoLock(&m_csAccessLock);
  918. m_rd.Reset();
  919. if(!LoadIfo(infn) || !LoadVob(infn))
  920. return E_INVALIDARG;
  921. m_infn = infn;
  922. return S_OK;
  923. }
  924. STDMETHODIMP CVobSubFileRipper::SetOutput(CString outfn)
  925. {
  926. CAutoLock cAutoLock(&m_csAccessLock);
  927. m_outfn = outfn;
  928. return S_OK;
  929. }
  930. STDMETHODIMP CVobSubFileRipper::GetRipperData(VSFRipperData& rd)
  931. {
  932. CAutoLock cAutoLock(&m_csAccessLock);
  933. rd.Copy(m_rd);
  934. return S_OK;
  935. }
  936. STDMETHODIMP CVobSubFileRipper::UpdateRipperData(VSFRipperData& rd)
  937. {
  938. CAutoLock cAutoLock(&m_csAccessLock);
  939. m_rd.Copy(rd);
  940. return S_OK;
  941. }
  942. STDMETHODIMP CVobSubFileRipper::Index()
  943. {
  944. if(m_fIndexing) return E_FAIL;
  945. CAMThread::CallWorker(CMD_INDEX);
  946. return S_OK;
  947. }
  948. STDMETHODIMP CVobSubFileRipper::IsIndexing()
  949. {
  950. return m_fIndexing ? S_OK : S_FALSE;
  951. }
  952. STDMETHODIMP CVobSubFileRipper::Abort(bool fSavePartial)
  953. {
  954. m_fBreakThread = true;
  955. return S_OK;
  956. }
  957. //
  958. void VSFRipperData::Reset()
  959. {
  960. vidsize.SetSize(0,0);
  961. memset(&vidinfo, 0, sizeof(vidinfo));
  962. pgcs.RemoveAll();
  963. iSelPGC = -1;
  964. fResetTime = fClosedCaption = true;
  965. fForcedOnly = false;
  966. fClose = fBeep = fAuto = false;
  967. fCloseIgnoreError = false;
  968. selvcs.RemoveAll();
  969. selids.RemoveAll();
  970. }
  971. void VSFRipperData::Copy(VSFRipperData& rd)
  972. {
  973. Reset();
  974. vidsize = rd.vidsize;
  975. vidinfo = rd.vidinfo;
  976. if(int len = rd.pgcs.GetCount())
  977. {
  978. pgcs.SetSize(len);
  979. for(int i = 0; i < len; i++)
  980. {
  981. PGC& src = rd.pgcs[i];
  982. PGC& dst = pgcs[i];
  983. dst.nAngles = src.nAngles;
  984. for(int i = 0; i < countof(dst.angles); i++)
  985. dst.angles[i].Copy(src.angles[i]);
  986. dst.iSelAngle = src.iSelAngle;
  987. memcpy(dst.pal, src.pal, sizeof(src.pal));
  988. memcpy(dst.ids, src.ids, sizeof(src.ids));
  989. }
  990. }
  991. iSelPGC = rd.iSelPGC;
  992. fResetTime = rd.fResetTime;
  993. fClosedCaption = rd.fClosedCaption;
  994. fForcedOnly = rd.fForcedOnly;
  995. fClose = rd.fClose;
  996. fBeep = rd.fBeep;
  997. fAuto = rd.fAuto;
  998. fCloseIgnoreError = rd.fCloseIgnoreError;
  999. selvcs.Copy(rd.selvcs);
  1000. POSITION pos = rd.selids.GetStartPosition();
  1001. while(pos)
  1002. {
  1003. BYTE key;
  1004. bool val;
  1005. rd.selids.GetNextAssoc(pos, key, val);
  1006. selids[key] = val;
  1007. }
  1008. }