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

多媒体编程

开发平台:

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 <winioctl.h>
  23. #include "TextFile.h"
  24. #include "....includeunrarunrar.h"
  25. #include "VobSubFile.h"
  26. //
  27. struct lang_type {unsigned short id; TCHAR lang_long[64];} lang_tbl[] =
  28. {
  29. {'--', _T("(Not detected)")},
  30. {'cc', _T("Closed Caption")},
  31. {'aa', _T("Afar")},
  32. {'ab', _T("Abkhazian")},
  33. {'af', _T("Afrikaans")},
  34. {'am', _T("Amharic")},
  35. {'ar', _T("Arabic")},
  36. {'as', _T("Assamese")},
  37. {'ay', _T("Aymara")},
  38. {'az', _T("Azerbaijani")},
  39. {'ba', _T("Bashkir")},
  40. {'be', _T("Byelorussian")},
  41. {'bg', _T("Bulgarian")},
  42. {'bh', _T("Bihari")},
  43. {'bi', _T("Bislama")},
  44. {'bn', _T("Bengali; Bangla")},
  45. {'bo', _T("Tibetan")},
  46. {'br', _T("Breton")},
  47. {'ca', _T("Catalan")},
  48. {'co', _T("Corsican")},
  49. {'cs', _T("Czech")},
  50. {'cy', _T("Welsh")},
  51. {'da', _T("Dansk")},
  52. {'de', _T("Deutsch")},
  53. {'dz', _T("Bhutani")},
  54. {'el', _T("Greek")},
  55. {'en', _T("English")},
  56. {'eo', _T("Esperanto")},
  57. {'es', _T("Espanol")},
  58. {'et', _T("Estonian")},
  59. {'eu', _T("Basque")},
  60. {'fa', _T("Persian")},
  61. {'fi', _T("Finnish")},
  62. {'fj', _T("Fiji")},
  63. {'fo', _T("Faroese")},
  64. {'fr', _T("Francais")},
  65. {'fy', _T("Frisian")},
  66. {'ga', _T("Irish")},
  67. {'gd', _T("Scots Gaelic")},
  68. {'gl', _T("Galician")},
  69. {'gn', _T("Guarani")},
  70. {'gu', _T("Gujarati")},
  71. {'ha', _T("Hausa")},
  72. {'he', _T("Hebrew")},
  73. {'hi', _T("Hindi")},
  74. {'hr', _T("Hrvatski")},
  75. {'hu', _T("Hungarian")},
  76. {'hy', _T("Armenian")},
  77. {'ia', _T("Interlingua")},
  78. {'id', _T("Indonesian")},
  79. {'ie', _T("Interlingue")},
  80. {'ik', _T("Inupiak")},
  81. {'in', _T("Indonesian")},
  82. {'is', _T("Islenska")},
  83. {'it', _T("Italiano")},
  84. {'iu', _T("Inuktitut")},
  85. {'iw', _T("Hebrew")},
  86. {'ja', _T("Japanese")},
  87. {'ji', _T("Yiddish")},
  88. {'jw', _T("Javanese")},
  89. {'ka', _T("Georgian")},
  90. {'kk', _T("Kazakh")},
  91. {'kl', _T("Greenlandic")},
  92. {'km', _T("Cambodian")},
  93. {'kn', _T("Kannada")},
  94. {'ko', _T("Korean")},
  95. {'ks', _T("Kashmiri")},
  96. {'ku', _T("Kurdish")},
  97. {'ky', _T("Kirghiz")},
  98. {'la', _T("Latin")},
  99. {'ln', _T("Lingala")},
  100. {'lo', _T("Laothian")},
  101. {'lt', _T("Lithuanian")},
  102. {'lv', _T("Latvian, Lettish")},
  103. {'mg', _T("Malagasy")},
  104. {'mi', _T("Maori")},
  105. {'mk', _T("Macedonian")},
  106. {'ml', _T("Malayalam")},
  107. {'mn', _T("Mongolian")},
  108. {'mo', _T("Moldavian")},
  109. {'mr', _T("Marathi")},
  110. {'ms', _T("Malay")},
  111. {'mt', _T("Maltese")},
  112. {'my', _T("Burmese")},
  113. {'na', _T("Nauru")},
  114. {'ne', _T("Nepali")},
  115. {'nl', _T("Nederlands")},
  116. {'no', _T("Norsk")},
  117. {'oc', _T("Occitan")},
  118. {'om', _T("(Afan) Oromo")},
  119. {'or', _T("Oriya")},
  120. {'pa', _T("Punjabi")},
  121. {'pl', _T("Polish")},
  122. {'ps', _T("Pashto, Pushto")},
  123. {'pt', _T("Portugues")},
  124. {'qu', _T("Quechua")},
  125. {'rm', _T("Rhaeto-Romance")},
  126. {'rn', _T("Kirundi")},
  127. {'ro', _T("Romanian")},
  128. {'ru', _T("Russian")},
  129. {'rw', _T("Kinyarwanda")},
  130. {'sa', _T("Sanskrit")},
  131. {'sd', _T("Sindhi")},
  132. {'sg', _T("Sangho")},
  133. {'sh', _T("Serbo-Croatian")},
  134. {'si', _T("Sinhalese")},
  135. {'sk', _T("Slovak")},
  136. {'sl', _T("Slovenian")},
  137. {'sm', _T("Samoan")},
  138. {'sn', _T("Shona")},
  139. {'so', _T("Somali")},
  140. {'sq', _T("Albanian")},
  141. {'sr', _T("Serbian")},
  142. {'ss', _T("Siswati")},
  143. {'st', _T("Sesotho")},
  144. {'su', _T("Sundanese")},
  145. {'sv', _T("Svenska")},
  146. {'sw', _T("Swahili")},
  147. {'ta', _T("Tamil")},
  148. {'te', _T("Telugu")},
  149. {'tg', _T("Tajik")},
  150. {'th', _T("Thai")},
  151. {'ti', _T("Tigrinya")},
  152. {'tk', _T("Turkmen")},
  153. {'tl', _T("Tagalog")},
  154. {'tn', _T("Setswana")},
  155. {'to', _T("Tonga")},
  156. {'tr', _T("Turkish")},
  157. {'ts', _T("Tsonga")},
  158. {'tt', _T("Tatar")},
  159. {'tw', _T("Twi")},
  160. {'ug', _T("Uighur")},
  161. {'uk', _T("Ukrainian")},
  162. {'ur', _T("Urdu")},
  163. {'uz', _T("Uzbek")},
  164. {'vi', _T("Vietnamese")},
  165. {'vo', _T("Volapuk")},
  166. {'wo', _T("Wolof")},
  167. {'xh', _T("Xhosa")},
  168. {'yi', _T("Yiddish")}, // formerly ji
  169. {'yo', _T("Yoruba")},
  170. {'za', _T("Zhuang")},
  171. {'zh', _T("Chinese")},
  172. {'zu', _T("Zulu")},
  173. };
  174. int find_lang(unsigned short id)
  175. {
  176. int mid, lo = 0, hi = countof(lang_tbl) - 1;
  177. while(lo < hi)
  178. {
  179. mid = (lo + hi) >> 1;
  180. if(id < lang_tbl[mid].id) hi = mid;
  181. else if(id > lang_tbl[mid].id) lo = mid + 1;
  182. else return(mid);
  183. }
  184. return(id == lang_tbl[lo].id ? lo : 0);
  185. }
  186. CString FindLangFromId(WORD id)
  187. {
  188. return(lang_tbl[find_lang(id)].lang_long);
  189. }
  190. //
  191. // CVobSubFile
  192. //
  193. CVobSubFile::CVobSubFile(CCritSec* pLock)
  194. : ISubPicProviderImpl(pLock)
  195. , m_sub(1024*1024)
  196. {
  197. }
  198. CVobSubFile::~CVobSubFile()
  199. {
  200. }
  201. //
  202. bool CVobSubFile::Copy(CVobSubFile& vsf)
  203. {
  204. Close();
  205. *(CVobSubSettings*)this = *(CVobSubSettings*)&vsf;
  206. m_title = vsf.m_title;
  207. m_iLang = vsf.m_iLang;
  208. m_sub.SetLength(vsf.m_sub.GetLength());
  209. m_sub.SeekToBegin();
  210. for(int i = 0; i < 32; i++)
  211. {
  212. SubLang& src = vsf.m_langs[i];
  213. SubLang& dst = m_langs[i];
  214. dst.id = src.id;
  215. dst.name = src.name;
  216. dst.alt = src.alt;
  217. for(int j = 0; j < src.subpos.GetCount(); j++)
  218. {
  219. SubPos& sp = src.subpos[j];
  220. if(!sp.fValid) continue;
  221. if(sp.filepos != vsf.m_sub.Seek(sp.filepos, CFile::begin))
  222. continue;
  223. sp.filepos = m_sub.GetPosition();
  224. BYTE buff[2048];
  225. vsf.m_sub.Read(buff, 2048);
  226. m_sub.Write(buff, 2048);
  227. WORD packetsize = (buff[buff[0x16]+0x18]<<8) | buff[buff[0x16]+0x19];
  228. for(int k = 0, size, sizeleft = packetsize - 4; 
  229. k < packetsize - 4; 
  230. k += size, sizeleft -= size)
  231. {
  232. int hsize = buff[0x16]+0x18 + ((buff[0x15]&0x80) ? 4 : 0);
  233. size = min(sizeleft, 2048 - hsize);
  234. if(size != sizeleft) 
  235. {
  236. while(vsf.m_sub.Read(buff, 2048))
  237. {
  238. if(!(buff[0x15]&0x80) && buff[buff[0x16]+0x17] == (i|0x20)) break;
  239. }
  240. m_sub.Write(buff, 2048);
  241. }
  242. }
  243. dst.subpos.Add(sp);
  244. }
  245. }
  246. m_sub.SetLength(m_sub.GetPosition());
  247. return(true);
  248. }
  249. //
  250. void CVobSubFile::TrimExtension(CString& fn)
  251. {
  252. int i = fn.ReverseFind('.');
  253. if(i > 0)
  254. {
  255. CString ext = fn.Mid(i).MakeLower();
  256. if(ext == _T(".ifo") || ext == _T(".idx") || ext == _T(".sub")
  257. || ext == _T(".sst") || ext == _T(".son") || ext == _T(".rar"))
  258. fn = fn.Left(i);
  259. }
  260. }
  261. bool CVobSubFile::Open(CString fn)
  262. {
  263. TrimExtension(fn);
  264. do
  265. {
  266. Close();
  267. int ver;
  268. if(!ReadIdx(fn + _T(".idx"), ver))
  269. break;
  270. if(ver < 6 && !ReadIfo(fn + _T(".ifo")))
  271. break;
  272. if(!ReadSub(fn + _T(".sub")) && !ReadRar(fn + _T(".rar")))
  273. break;
  274. m_title = fn;
  275. for(int i = 0; i < 32; i++)
  276. {
  277. CArray<SubPos>& sp = m_langs[i].subpos;
  278. for(int j = 0; j < sp.GetCount(); j++)
  279. {
  280. sp[j].stop = sp[j].start;
  281. sp[j].fForced = false;
  282. int packetsize = 0, datasize = 0;
  283. BYTE* buff = GetPacket(j, packetsize, datasize, i);
  284. if(!buff) continue;
  285. m_img.delay = j < (sp.GetSize()-1) ? sp[j+1].start - sp[j].start : 3000;
  286. m_img.GetPacketInfo(buff, packetsize, datasize);
  287. if(j < (sp.GetSize()-1)) m_img.delay = min(m_img.delay, sp[j+1].start - sp[j].start);
  288. sp[j].stop = sp[j].start + m_img.delay;
  289. sp[j].fForced = m_img.fForced;
  290. if(j > 0 && sp[j-1].stop > sp[j].start)
  291. sp[j-1].stop = sp[j].start;
  292. delete [] buff;
  293. }
  294. }
  295. return(true);
  296. }
  297. while(false);
  298. Close();
  299. return(false);
  300. }
  301. bool CVobSubFile::Save(CString fn, SubFormat sf)
  302. {
  303. TrimExtension(fn);
  304. CVobSubFile vsf(NULL);
  305. if(!vsf.Copy(*this))
  306. return(false);
  307. switch(sf)
  308. {
  309. case VobSub: return vsf.SaveVobSub(fn); break;
  310. case WinSubMux: return vsf.SaveWinSubMux(fn); break;
  311. case Scenarist: return vsf.SaveScenarist(fn); break;
  312. case Maestro: return vsf.SaveMaestro(fn); break;
  313. default: break;
  314. }
  315. return(false);
  316. }
  317. void CVobSubFile::Close()
  318. {
  319. InitSettings();
  320. m_title.Empty();
  321. m_sub.SetLength(0);
  322. m_img.Invalidate();
  323. m_iLang = -1;
  324. for(int i = 0; i < 32; i++)
  325. {
  326. m_langs[i].id = 0;
  327. m_langs[i].name.Empty();
  328. m_langs[i].alt.Empty();
  329. m_langs[i].subpos.RemoveAll();
  330. }
  331. }
  332. //
  333. bool CVobSubFile::ReadIdx(CString fn, int& ver)
  334. {
  335. CWebTextFile f;
  336. if(!f.Open(fn))
  337. return(false);
  338. bool fError = false;
  339. int id = -1, delay = 0, vobid = -1, cellid = -1;
  340. __int64 celltimestamp = 0;
  341. CString str;
  342. for(int line = 0; !fError && f.ReadString(str); line++)
  343. {
  344. str.Trim();
  345. if(line == 0)
  346. {
  347. TCHAR buff[] = _T("VobSub index file, v");
  348. const TCHAR* s = str;
  349. int i = str.Find(buff);
  350. if(i < 0 || _stscanf(&s[i+_tcslen(buff)], _T("%d"), &ver) != 1
  351. || ver > VOBSUBIDXVER)
  352. {
  353. AfxMessageBox(_T("Wrong file version!"));
  354. fError = true;
  355. continue;
  356. }
  357. }
  358. else if(!str.GetLength())
  359. {
  360. continue;
  361. }
  362. else if(str[0] == _T('#'))
  363. {
  364. TCHAR buff[] = _T("Vob/Cell ID:");
  365.             const TCHAR* s = str;
  366. int i = str.Find(buff);
  367. if(i >= 0)
  368. {
  369. _stscanf(&s[i+_tcslen(buff)], _T("%d, %d (PTS: %d)"), &vobid, &cellid, &celltimestamp);
  370. }
  371. continue;
  372. }
  373. int i = str.Find(':');
  374. if(i <= 0) continue;
  375. CString entry = str.Left(i).MakeLower();
  376. str = str.Mid(i+1);
  377. str.Trim();
  378. if(str.IsEmpty()) continue;
  379. if(entry == _T("size"))
  380. {
  381. int x, y;
  382. if(_stscanf(str, _T("%dx%d"), &x, &y) != 2) fError = true;
  383. m_size.cx = x;
  384. m_size.cy = y;
  385. }
  386. else if(entry == _T("org"))
  387. {
  388. if(_stscanf(str, _T("%d,%d"), &m_x, &m_y) != 2) fError = true;
  389. else m_org = CPoint(m_x, m_y);
  390. }
  391. else if(entry == _T("scale"))
  392. {
  393. if(ver < 5) 
  394. {
  395. int scale = 100;
  396. if(_stscanf(str, _T("%d%%"), &scale) != 1) fError = true;
  397. m_scale_x = m_scale_y = scale;
  398. }
  399. else 
  400. {
  401. if(_stscanf(str, _T("%d%%,%d%%"), &m_scale_x, &m_scale_y) != 2) fError = true;
  402. }
  403. }
  404. else if(entry == _T("alpha"))
  405. {
  406. if(_stscanf(str, _T("%d"), &m_alpha) != 1) fError = true;
  407. }
  408. else if(entry == _T("smooth"))
  409. {
  410. str.MakeLower();
  411. if(str.Find(_T("old")) >= 0 || str.Find(_T("2")) >= 0) m_fSmooth = 2;
  412. else if(str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) m_fSmooth = 1;
  413. else if(str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) m_fSmooth = 0;
  414. else fError = true;
  415. }
  416. else if(entry == _T("fadein/out"))
  417. {
  418. if(_stscanf(str, _T("%d,%d"), &m_fadein, &m_fadeout) != 2) fError = true;
  419. }
  420. else if(entry == _T("align"))
  421. {
  422. str.MakeLower();
  423. int i = 0, j = 0;
  424. for(CString token = str.Tokenize(_T(" "), i); 
  425. j < 3 && !fError && !token.IsEmpty(); 
  426. token = str.Tokenize(_T(" "), i), j++)
  427. {
  428. if(j == 0)
  429. {
  430. if(token == _T("on") || token == _T("1")) m_fAlign = true;
  431. else if(token == _T("off") || token == _T("0")) m_fAlign = false;
  432. else fError = true;
  433. }
  434. else if(j == 1)
  435. {
  436. if(token == _T("at")) {j--; continue;}
  437. if(token == _T("left")) m_alignhor = 0;
  438. else if(token == _T("center")) m_alignhor = 1;
  439. else if(token == _T("right")) m_alignhor = 2;
  440. else fError = true;
  441. }
  442. else if(j == 2)
  443. {
  444. if(token == _T("top")) m_alignver = 0;
  445. else if(token == _T("center")) m_alignver = 1;
  446. else if(token == _T("bottom")) m_alignver = 2;
  447. else fError = true;
  448. }
  449. }
  450. }
  451. else if(entry == _T("time offset"))
  452. {
  453. bool fNegative = false;
  454. if(str[0] == '-') fNegative = true;
  455. str.TrimLeft(_T("+-"));
  456. TCHAR c;
  457. int hh, mm, ss, ms;
  458. int n = _stscanf(str, _T("%d%c%d%c%d%c%d"), &hh, &c, &mm, &c, &ss, &c, &ms);
  459. m_toff = n == 1 
  460. ? hh * (fNegative ? -1 : 1)
  461. : n == 4+3
  462. ? (hh*60*60*1000 + mm*60*1000 + ss*1000 + ms) * (fNegative ? -1 : 1)
  463. : fError = true, 0;
  464. }
  465. else if(entry == _T("forced subs"))
  466. {
  467. str.MakeLower();
  468. if(str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) m_fOnlyShowForcedSubs = true;
  469. else if(str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) m_fOnlyShowForcedSubs = false;
  470. else fError = true;
  471. }
  472. else if(entry == _T("langidx"))
  473. {
  474. if(_stscanf(str, _T("%d"), &m_iLang) != 1) fError = true;
  475. }
  476. else if(entry == _T("palette"))
  477. {
  478. if(_stscanf(str, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"), 
  479. &m_orgpal[0], &m_orgpal[1], &m_orgpal[2], &m_orgpal[3],
  480. &m_orgpal[4], &m_orgpal[5], &m_orgpal[6], &m_orgpal[7],
  481. &m_orgpal[8], &m_orgpal[9], &m_orgpal[10], &m_orgpal[11],
  482. &m_orgpal[12], &m_orgpal[13], &m_orgpal[14], &m_orgpal[15]
  483. ) != 16) fError = true;
  484. }
  485. else if(entry == _T("custom colors"))
  486. {
  487. str.MakeLower();
  488. if(str.Find(_T("on")) == 0 || str.Find(_T("1")) == 0) m_fCustomPal = true;
  489. else if(str.Find(_T("off")) == 0 || str.Find(_T("0")) == 0) m_fCustomPal = false;
  490. else fError = true;
  491. i = str.Find(_T("tridx:"));
  492. if(i < 0) {fError = true; continue;}
  493. str = str.Mid(i + (int)_tcslen(_T("tridx:")));
  494. int tridx;
  495. if(_stscanf(str, _T("%x"), &tridx) != 1) {fError = true; continue;}
  496. tridx = ((tridx&0x1000)>>12) | ((tridx&0x100)>>7) | ((tridx&0x10)>>2) | ((tridx&1)<<3);
  497. i = str.Find(_T("colors:"));
  498. if(i < 0) {fError = true; continue;}
  499. str = str.Mid(i + (int)_tcslen(_T("colors:")));
  500. RGBQUAD pal[4];
  501. if(_stscanf(str, _T("%x,%x,%x,%x"), &pal[0], &pal[1], &pal[2], &pal[3]) != 4) {fError = true; continue;}
  502. SetCustomPal(pal, tridx);
  503. }
  504. else if(entry == _T("id"))
  505. {
  506. str.MakeLower();
  507. int langid = ((str[0]&0xff)<<8)|(str[1]&0xff);
  508. i = str.Find(_T("index:"));
  509. if(i < 0) {fError = true; continue;}
  510. str = str.Mid(i + (int)_tcslen(_T("index:")));
  511. if(_stscanf(str, _T("%d"), &id) != 1 || id < 0 || id >= 32) {fError = true; continue;}
  512. m_langs[id].id = langid;
  513. m_langs[id].name = lang_tbl[find_lang(langid)].lang_long;
  514. m_langs[id].alt = lang_tbl[find_lang(langid)].lang_long;
  515. delay = 0;
  516. }
  517. else if(id >= 0 && entry == _T("alt"))
  518. {
  519. m_langs[id].alt = str;
  520. }
  521. else if(id >= 0 && entry == _T("delay"))
  522. {
  523. bool fNegative = false;
  524. if(str[0] == '-') fNegative = true;
  525. str.TrimLeft(_T("+-"));
  526. TCHAR c;
  527. int hh, mm, ss, ms;
  528. if(_stscanf(str, _T("%d%c%d%c%d%c%d"), &hh, &c, &mm, &c, &ss, &c, &ms) != 4+3)  {fError = true; continue;}
  529. delay += (hh*60*60*1000 + mm*60*1000 + ss*1000 + ms) * (fNegative ? -1 : 1);
  530. }
  531. else if(id >= 0 && entry == _T("timestamp"))
  532. {
  533. SubPos sb;
  534. sb.vobid = vobid;
  535. sb.cellid = cellid;
  536. sb.celltimestamp = celltimestamp;
  537. sb.fValid = true;
  538. bool fNegative = false;
  539. if(str[0] == '-') fNegative = true;
  540. str.TrimLeft(_T("+-"));
  541. TCHAR c;
  542. int hh, mm, ss, ms;
  543. if(_stscanf(str, _T("%d%c%d%c%d%c%d"), &hh, &c, &mm, &c, &ss, &c, &ms) != 4+3)  {fError = true; continue;}
  544. sb.start = (hh*60*60*1000 + mm*60*1000 + ss*1000 + ms) * (fNegative ? -1 : 1) + delay;
  545. i = str.Find(_T("filepos:"));
  546. if(i < 0) {fError = true; continue;}
  547. str = str.Mid(i + (int)_tcslen(_T("filepos:")));
  548. if(_stscanf(str, _T("%I64x"), &sb.filepos) != 1) {fError = true; continue;}
  549. if(delay < 0 && m_langs[id].subpos.GetSize() > 0)
  550. {
  551. __int64 ts = m_langs[id].subpos[m_langs[id].subpos.GetSize()-1].start;
  552. if(sb.start < ts)
  553. {
  554. delay += (int)(ts - sb.start);
  555. sb.start = ts;
  556. }
  557. }
  558. m_langs[id].subpos.Add(sb);
  559. }
  560. else fError = true;
  561. }
  562. return(!fError);
  563. }
  564. bool CVobSubFile::ReadSub(CString fn)
  565. {
  566. CFile f;
  567. if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
  568. return(false);
  569. m_sub.SetLength(f.GetLength());
  570. m_sub.SeekToBegin();
  571. int len;
  572. BYTE buff[2048];
  573. while((len = f.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000)
  574. m_sub.Write(buff, len);
  575. return(true);
  576. }
  577. static unsigned char* RARbuff = NULL;
  578. static unsigned int RARpos = 0;
  579. static int PASCAL MyProcessDataProc(unsigned char* Addr, int Size)
  580. {
  581. ASSERT(RARbuff);
  582. memcpy(&RARbuff[RARpos], Addr, Size);
  583. RARpos += Size;
  584. return(1);
  585. }
  586. bool CVobSubFile::ReadRar(CString fn)
  587. {
  588. HMODULE h = LoadLibrary(_T("unrar.dll"));
  589. if(!h) return(false);
  590. RAROpenArchiveEx OpenArchiveEx = (RAROpenArchiveEx)GetProcAddress(h, "RAROpenArchiveEx");
  591. RARCloseArchive CloseArchive = (RARCloseArchive)GetProcAddress(h, "RARCloseArchive");
  592. RARReadHeaderEx ReadHeaderEx = (RARReadHeaderEx)GetProcAddress(h, "RARReadHeaderEx");
  593. RARProcessFile ProcessFile = (RARProcessFile)GetProcAddress(h, "RARProcessFile");
  594. RARSetChangeVolProc SetChangeVolProc = (RARSetChangeVolProc)GetProcAddress(h, "RARSetChangeVolProc");
  595. RARSetProcessDataProc SetProcessDataProc = (RARSetProcessDataProc)GetProcAddress(h, "RARSetProcessDataProc");
  596. RARSetPassword SetPassword = (RARSetPassword)GetProcAddress(h, "RARSetPassword");
  597. if(!(OpenArchiveEx && CloseArchive && ReadHeaderEx && ProcessFile 
  598. && SetChangeVolProc && SetProcessDataProc && SetPassword))
  599. {
  600. FreeLibrary(h);
  601. return(false);
  602. }
  603. struct RAROpenArchiveDataEx ArchiveDataEx;
  604. memset(&ArchiveDataEx, 0, sizeof(ArchiveDataEx));
  605. #ifdef UNICODE
  606. ArchiveDataEx.ArcNameW = (LPTSTR)(LPCTSTR)fn;
  607. char fnA[MAX_PATH];
  608. if(wcstombs(fnA, fn, fn.GetLength()+1) == -1) fnA[0] = 0;
  609. ArchiveDataEx.ArcName = fnA;
  610. #else
  611. ArchiveDataEx.ArcName = (LPTSTR)(LPCTSTR)fn;
  612. #endif
  613. ArchiveDataEx.OpenMode = RAR_OM_EXTRACT;
  614. ArchiveDataEx.CmtBuf = 0;
  615. HANDLE hrar = OpenArchiveEx(&ArchiveDataEx);
  616. if(!hrar) 
  617. {
  618. FreeLibrary(h);
  619. return(false);
  620. }
  621. SetProcessDataProc(hrar, MyProcessDataProc);
  622. struct RARHeaderDataEx HeaderDataEx;
  623. HeaderDataEx.CmtBuf = NULL;
  624. while(ReadHeaderEx(hrar, &HeaderDataEx) == 0)
  625. {
  626. #ifdef UNICODE
  627. CString subfn(HeaderDataEx.FileNameW);
  628. #else
  629. CString subfn(HeaderDataEx.FileName);
  630. #endif
  631. if(!subfn.Right(4).CompareNoCase(_T(".sub")))
  632. {
  633. CAutoVectorPtr<BYTE> buff;
  634. if(!buff.Allocate(HeaderDataEx.UnpSize))
  635. {
  636. CloseArchive(hrar);
  637. FreeLibrary(h);
  638. return(false);
  639. }
  640. RARbuff = buff;
  641. RARpos = 0;
  642. if(ProcessFile(hrar, RAR_TEST, NULL, NULL))
  643. {
  644. CloseArchive(hrar);
  645. FreeLibrary(h);
  646. return(false);
  647. }
  648. m_sub.SetLength(HeaderDataEx.UnpSize);
  649. m_sub.SeekToBegin();
  650. m_sub.Write(buff, HeaderDataEx.UnpSize);
  651. m_sub.SeekToBegin();
  652. RARbuff = NULL;
  653. RARpos = 0;
  654. break;
  655. }
  656. ProcessFile(hrar, RAR_SKIP, NULL, NULL);
  657. }
  658. CloseArchive(hrar);
  659. FreeLibrary(h);
  660. return(true);
  661. }
  662. #define ReadBEdw(var) 
  663.     f.Read(&((BYTE*)&var)[3], 1); 
  664. f.Read(&((BYTE*)&var)[2], 1); 
  665. f.Read(&((BYTE*)&var)[1], 1); 
  666. f.Read(&((BYTE*)&var)[0], 1); 
  667. bool CVobSubFile::ReadIfo(CString fn)
  668. {
  669. CFile f;
  670. if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
  671. return(false);
  672. /* PGC1 */
  673. f.Seek(0xc0+0x0c, SEEK_SET);
  674. DWORD pos;
  675. ReadBEdw(pos);
  676. f.Seek(pos*0x800 + 0x0c, CFile::begin);
  677. DWORD offset;
  678. ReadBEdw(offset);
  679. /* Subpic palette */
  680. f.Seek(pos*0x800 + offset + 0xa4, CFile::begin);
  681. for(int i = 0; i < 16; i++) 
  682. {
  683. BYTE y, u, v, tmp;
  684. f.Read(&tmp, 1);
  685. f.Read(&y, 1);
  686. f.Read(&u, 1);
  687. f.Read(&v, 1);
  688. y = (y-16)*255/219;
  689. m_orgpal[i].rgbRed = (BYTE)min(max(1.0*y + 1.4022*(u-128), 0), 255);
  690. m_orgpal[i].rgbGreen = (BYTE)min(max(1.0*y - 0.3456*(u-128) - 0.7145*(v-128), 0), 255);
  691. m_orgpal[i].rgbBlue = (BYTE)min(max(1.0*y + 1.7710*(v-128), 0) , 255);
  692. }
  693. return(true);
  694. }
  695. bool CVobSubFile::WriteIdx(CString fn)
  696. {
  697. CTextFile f;
  698. if(!f.Save(fn, CTextFile::ASCII))
  699. return(false);
  700. CString str;
  701. str.Format(_T("# VobSub index file, v%d (do not modify this line!)n"), VOBSUBIDXVER);
  702. f.WriteString(str);
  703. f.WriteString(_T("# n"));
  704. f.WriteString(_T("# To repair desyncronization, you can insert gaps this way:n"));
  705. f.WriteString(_T("# (it usually happens after vob id changes)n"));
  706. f.WriteString(_T("# n"));
  707. f.WriteString(_T("#t delay: [sign]hh:mm:ss:msn"));
  708. f.WriteString(_T("# n"));
  709. f.WriteString(_T("# Where:n"));
  710. f.WriteString(_T("#t [sign]: +, - (optional)n"));
  711. f.WriteString(_T("#t hh: hours (0 <= hh)n"));
  712. f.WriteString(_T("#t mm/ss: minutes/seconds (0 <= mm/ss <= 59)n"));
  713. f.WriteString(_T("#t ms: milliseconds (0 <= ms <= 999)n"));
  714. f.WriteString(_T("# n"));
  715. f.WriteString(_T("#t Note: You can't position a sub before the previous with a negative value.n"));
  716. f.WriteString(_T("# n"));
  717. f.WriteString(_T("# You can also modify timestamps or delete a few subs you don't like.n"));
  718. f.WriteString(_T("# Just make sure they stay in increasing order.n"));
  719. f.WriteString(_T("n"));
  720. f.WriteString(_T("n"));
  721. // Settings
  722. f.WriteString(_T("# Settingsnn"));
  723. f.WriteString(_T("# Original frame sizen"));
  724. str.Format(_T("size: %dx%dnn"), m_size.cx, m_size.cy);
  725. f.WriteString(str);
  726. f.WriteString(_T("# Origin, relative to the upper-left corner, can be overloaded by aligmentn"));
  727. str.Format(_T("org: %d, %dnn"), m_x, m_y);
  728. f.WriteString(str);
  729. f.WriteString(_T("# Image scaling (hor,ver), origin is at the upper-left corner or at the alignment coord (x, y)n"));
  730. str.Format(_T("scale: %d%%, %d%%nn"), m_scale_x, m_scale_y);
  731. f.WriteString(str);
  732. f.WriteString(_T("# Alpha blendingn"));
  733. str.Format(_T("alpha: %d%%nn"), m_alpha);
  734. f.WriteString(str);
  735. f.WriteString(_T("# Smoothing for very blocky images (use OLD for no filtering)n"));
  736. str.Format(_T("smooth: %snn"), m_fSmooth == 0 ? _T("OFF") : m_fSmooth == 1 ? _T("ON") : _T("OLD"));
  737. f.WriteString(str);
  738. f.WriteString(_T("# In millisecsn"));
  739. str.Format(_T("fadein/out: %d, %dnn"), m_fadein, m_fadeout);
  740. f.WriteString(str);
  741. f.WriteString(_T("# Force subtitle placement relative to (org.x, org.y)n"));
  742. str.Format(_T("align: %s %s %snn"), 
  743. m_fAlign ? _T("ON at") : _T("OFF at"), 
  744. m_alignhor == 0 ? _T("LEFT") : m_alignhor == 1 ? _T("CENTER") : m_alignhor == 2 ? _T("RIGHT") : _T(""), 
  745. m_alignver == 0 ? _T("TOP") : m_alignver == 1 ? _T("CENTER") : m_alignver == 2 ? _T("BOTTOM") : _T(""));
  746. f.WriteString(str);
  747. f.WriteString(_T("# For correcting non-progressive desync. (in millisecs or hh:mm:ss:ms)n"));
  748. f.WriteString(_T("# Note: Not effective in DirectVobSub, use "delay: ... " instead.n"));
  749. str.Format(_T("time offset: %dnn"), m_toff);
  750. f.WriteString(str);
  751. f.WriteString(_T("# ON: displays only forced subtitles, OFF: shows everythingn"));
  752. str.Format(_T("forced subs: %snn"), m_fOnlyShowForcedSubs ? _T("ON") : _T("OFF"));
  753. f.WriteString(str);
  754. f.WriteString(_T("# The original palette of the DVDn"));
  755. str.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06xnn"), 
  756. *((unsigned int*)&m_orgpal[0])&0xffffff,
  757. *((unsigned int*)&m_orgpal[1])&0xffffff,
  758. *((unsigned int*)&m_orgpal[2])&0xffffff,
  759. *((unsigned int*)&m_orgpal[3])&0xffffff,
  760. *((unsigned int*)&m_orgpal[4])&0xffffff,
  761. *((unsigned int*)&m_orgpal[5])&0xffffff,
  762. *((unsigned int*)&m_orgpal[6])&0xffffff,
  763. *((unsigned int*)&m_orgpal[7])&0xffffff,
  764. *((unsigned int*)&m_orgpal[8])&0xffffff,
  765. *((unsigned int*)&m_orgpal[9])&0xffffff,
  766. *((unsigned int*)&m_orgpal[10])&0xffffff,
  767. *((unsigned int*)&m_orgpal[11])&0xffffff,
  768. *((unsigned int*)&m_orgpal[12])&0xffffff,
  769. *((unsigned int*)&m_orgpal[13])&0xffffff,
  770. *((unsigned int*)&m_orgpal[14])&0xffffff,
  771. *((unsigned int*)&m_orgpal[15])&0xffffff);
  772. f.WriteString(str);
  773. int tridx = (!!(m_tridx&1))*0x1000 + (!!(m_tridx&2))*0x100 + (!!(m_tridx&4))*0x10 + (!!(m_tridx&8));
  774. f.WriteString(_T("# Custom colors (transp idxs and the four colors)n"));
  775. str.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06xnn"), 
  776. m_fCustomPal ? _T("ON") : _T("OFF"),
  777. tridx, 
  778. *((unsigned int*)&m_cuspal[0])&0xffffff,
  779. *((unsigned int*)&m_cuspal[1])&0xffffff,
  780. *((unsigned int*)&m_cuspal[2])&0xffffff,
  781. *((unsigned int*)&m_cuspal[3])&0xffffff);
  782. f.WriteString(str);
  783. f.WriteString(_T("# Language index in usen"));
  784. str.Format(_T("langidx: %dnn"), m_iLang);
  785. f.WriteString(str);
  786. // Subs
  787. for(int i = 0; i < 32; i++)
  788. {
  789. SubLang& sl = m_langs[i];
  790. CArray<SubPos>& sp = sl.subpos;
  791. if(sp.IsEmpty() && !sl.id) continue;
  792. str.Format(_T("# %sn"), sl.name);
  793. f.WriteString(str);
  794. ASSERT(sl.id);
  795. if(!sl.id) sl.id = '--';
  796. str.Format(_T("id: %c%c, index: %dn"), sl.id>>8, sl.id&0xff, i);
  797. f.WriteString(str);
  798. str.Format(_T("# Decomment next line to activate alternative name in DirectVobSub / Windows Media Player 6.xn"));
  799. f.WriteString(str);
  800. str.Format(_T("alt: %sn"), sl.alt);
  801. if(sl.name == sl.alt) str = _T("# ") + str;
  802. f.WriteString(str);
  803. char vobid = -1, cellid = -1;
  804. for(int j = 0; j < sp.GetCount(); j++) 
  805. {
  806. if(!sp[j].fValid) continue;
  807. if(sp[j].vobid != vobid || sp[j].cellid != cellid)
  808. {
  809. str.Format(_T("# Vob/Cell ID: %d, %d (PTS: %d)n"), sp[j].vobid, sp[j].cellid, sp[j].celltimestamp);
  810. f.WriteString(str);
  811. vobid = sp[j].vobid;
  812. cellid = sp[j].cellid;
  813. }
  814. str.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64xn"), 
  815. sp[j].start < 0 ? _T("-") : _T(""),
  816. abs(int((sp[j].start/1000/60/60)%60)), 
  817. abs(int((sp[j].start/1000/60)%60)), 
  818. abs(int((sp[j].start/1000)%60)), 
  819. abs(int((sp[j].start)%1000)), 
  820. sp[j].filepos);
  821. f.WriteString(str);
  822. }
  823. f.WriteString(_T("n"));
  824. }
  825. return(true);
  826. }
  827. bool CVobSubFile::WriteSub(CString fn)
  828. {
  829. CFile f;
  830. if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite))
  831. return(false);
  832. if(m_sub.GetLength() == 0)
  833. return(true); // nothing to do...
  834. m_sub.SeekToBegin();
  835. int len;
  836. BYTE buff[2048];
  837. while((len = m_sub.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000)
  838. f.Write(buff, len);
  839. return(true);
  840. }
  841. //
  842. BYTE* CVobSubFile::GetPacket(int idx, int& packetsize, int& datasize, int iLang)
  843. {
  844. BYTE* ret = NULL;
  845. if(iLang < 0 || iLang >= 32) iLang = m_iLang;
  846. CArray<SubPos>& sp = m_langs[iLang].subpos;
  847. do
  848. {
  849. if(idx < 0 || idx >= sp.GetSize())
  850. break;
  851. if(m_sub.Seek(sp[idx].filepos, CFile::begin) != sp[idx].filepos) 
  852. break;
  853. BYTE buff[0x800];
  854. if(sizeof(buff) != m_sub.Read(buff, sizeof(buff)))
  855. break;
  856. BYTE offset = buff[0x16];
  857. // let's check a few things to make sure...
  858. if(*(DWORD*)&buff[0x00] != 0xba010000
  859. || *(DWORD*)&buff[0x0e] != 0xbd010000
  860. || !(buff[0x15] & 0x80)
  861. || (buff[0x17] & 0xf0) != 0x20
  862. || (buff[buff[0x16] + 0x17] & 0xe0) != 0x20
  863. || (buff[buff[0x16] + 0x17] & 0x1f) != iLang)
  864. break;
  865.         packetsize = (buff[buff[0x16] + 0x18] << 8) + buff[buff[0x16] + 0x19];
  866. datasize = (buff[buff[0x16] + 0x1a] << 8) + buff[buff[0x16] + 0x1b];
  867. ret = new BYTE[packetsize];
  868. if(!ret) break;
  869. int i = 0, sizeleft = packetsize;
  870.         for(int size; 
  871. i < packetsize; 
  872. i += size, sizeleft -= size)
  873. {
  874. int hsize = 0x18 + buff[0x16];
  875. size = min(sizeleft, 0x800 - hsize);
  876. memcpy(&ret[i], &buff[hsize], size);
  877.             if(size != sizeleft) 
  878. {
  879. while(m_sub.Read(buff, sizeof(buff)))
  880. {
  881. if(/*!(buff[0x15] & 0x80) &&*/ buff[buff[0x16] + 0x17] == (iLang|0x20)) 
  882. break;
  883. }
  884. }
  885. }
  886. if(i != packetsize || sizeleft > 0)
  887. delete [] ret, ret = NULL;
  888. }
  889. while(false);
  890. return(ret);
  891. }
  892. bool CVobSubFile::GetFrame(int idx, int iLang)
  893. {
  894. if(iLang < 0 || iLang >= 32) iLang = m_iLang;
  895. CArray<SubPos>& sp = m_langs[iLang].subpos;
  896. if(idx < 0 || idx >= sp.GetCount())
  897. return(false);
  898. if(m_img.iLang != iLang || m_img.iIdx != idx) 
  899. {
  900. int packetsize = 0, datasize = 0;
  901. CAutoVectorPtr<BYTE> buff;
  902. buff.Attach(GetPacket(idx, packetsize, datasize, iLang));
  903. if(!buff || packetsize <= 0 || datasize <= 0) return(false);
  904. m_img.start = sp[idx].start;
  905. m_img.delay = idx < (sp.GetSize()-1)
  906. ? sp[idx+1].start - sp[idx].start
  907. : 3000;
  908. bool ret = m_img.Decode(buff, packetsize, datasize, m_fCustomPal, m_tridx, m_orgpal, m_cuspal, true);
  909. if(idx < (sp.GetSize()-1))
  910. m_img.delay = min(m_img.delay, sp[idx+1].start - m_img.start);
  911. if(!ret) return(false);
  912. m_img.iIdx = idx;
  913. m_img.iLang = iLang;
  914. }
  915. return(m_fOnlyShowForcedSubs ? m_img.fForced : true);
  916. }
  917. bool CVobSubFile::GetFrameByTimeStamp(__int64 time)
  918. {
  919. return(GetFrame(GetFrameIdxByTimeStamp(time)));
  920. }
  921. int CVobSubFile::GetFrameIdxByTimeStamp(__int64 time)
  922. {
  923. if(m_iLang < 0 || m_iLang >= 32)
  924. return(-1);
  925. CArray<SubPos>& sp = m_langs[m_iLang].subpos;
  926. int i = 0, j = (int)sp.GetCount() - 1, ret = -1;
  927. if(j >= 0 && time >= sp[j].start)
  928. return(j);
  929. while(i < j)
  930. {
  931. int mid = (i + j) >> 1;
  932. int midstart = (int)sp[mid].start;
  933. if(time == midstart) {ret = mid; break;}
  934. else if(time < midstart) {ret = -1; if(j == mid) mid--; j = mid;}
  935. else if(time > midstart) {ret = mid; if(i == mid) mid++; i = mid;}
  936. }
  937. return(ret);
  938. }
  939. //
  940. STDMETHODIMP CVobSubFile::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  941. {
  942.     CheckPointer(ppv, E_POINTER);
  943.     *ppv = NULL;
  944.     return 
  945. QI(IPersist)
  946. QI(ISubStream)
  947. QI(ISubPicProvider)
  948. __super::NonDelegatingQueryInterface(riid, ppv);
  949. }
  950. // ISubPicProvider
  951. // TODO: return segments for the fade-in/out time (with animated set to "true" of course)
  952. STDMETHODIMP_(POSITION) CVobSubFile::GetStartPosition(REFERENCE_TIME rt, double fps)
  953. {
  954. rt /= 10000;
  955. int i = GetFrameIdxByTimeStamp(rt);
  956. if(!GetFrame(i))
  957. return(NULL);
  958. if(rt >= (m_img.start + m_img.delay))
  959. {
  960. if(!GetFrame(++i))
  961. return(NULL);
  962. }
  963. return((POSITION)(i+1));
  964. }
  965. STDMETHODIMP_(POSITION) CVobSubFile::GetNext(POSITION pos)
  966. {
  967. int i = (int)pos;
  968. return(GetFrame(i) ? (POSITION)(i+1) : NULL);
  969. }
  970. STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStart(POSITION pos, double fps)
  971. {
  972. int i = (int)pos-1;
  973. return(GetFrame(i) ? 10000i64*m_img.start : 0);
  974. }
  975. STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStop(POSITION pos, double fps)
  976. {
  977. int i = (int)pos-1;
  978. return(GetFrame(i) ? 10000i64*(m_img.start + m_img.delay) : 0);
  979. }
  980. STDMETHODIMP_(bool) CVobSubFile::IsAnimated(POSITION pos)
  981. {
  982. return(false);
  983. }
  984. STDMETHODIMP CVobSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox)
  985. {
  986. if(spd.bpp != 32) return E_INVALIDARG;
  987. rt /= 10000;
  988. if(!GetFrame(GetFrameIdxByTimeStamp(rt)))
  989. return E_FAIL;
  990. if(rt >= (m_img.start + m_img.delay))
  991. return E_FAIL;
  992. return __super::Render(spd, bbox);
  993. }
  994. // IPersist
  995. STDMETHODIMP CVobSubFile::GetClassID(CLSID* pClassID)
  996. {
  997. return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER;
  998. }
  999. // ISubStream
  1000. STDMETHODIMP_(int) CVobSubFile::GetStreamCount()
  1001. {
  1002. int iStreamCount = 0;
  1003. for(int i = 0; i < 32; i++)
  1004. if(m_langs[i].subpos.GetCount()) iStreamCount++;
  1005. return(iStreamCount);
  1006. }
  1007. STDMETHODIMP CVobSubFile::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID)
  1008. {
  1009. for(int i = 0; i < 32; i++)
  1010. {
  1011. SubLang& sl = m_langs[i];
  1012. if(sl.subpos.IsEmpty() || iStream-- > 0)
  1013. continue;
  1014. if(ppName)
  1015. {
  1016. if(!(*ppName = (WCHAR*)CoTaskMemAlloc((sl.alt.GetLength()+1)*sizeof(WCHAR))))
  1017. return E_OUTOFMEMORY;
  1018. wcscpy(*ppName, CStringW(sl.alt));
  1019. }
  1020. if(pLCID)
  1021. {
  1022. *pLCID = 0; // TODO: make lcid out of "sl.id"
  1023. }
  1024. return S_OK;
  1025. }
  1026. return E_FAIL;
  1027. }
  1028. STDMETHODIMP_(int) CVobSubFile::GetStream()
  1029. {
  1030. int iStream = 0;
  1031. for(int i = 0; i < m_iLang; i++)
  1032. if(!m_langs[i].subpos.IsEmpty()) iStream++;
  1033. return(iStream);
  1034. }
  1035. STDMETHODIMP CVobSubFile::SetStream(int iStream)
  1036. {
  1037. for(int i = 0; i < 32; i++)
  1038. {
  1039. CArray<SubPos>& sp = m_langs[i].subpos;
  1040. if(sp.IsEmpty() || iStream-- > 0)
  1041. continue;
  1042. m_iLang = i;
  1043. m_img.Invalidate();
  1044. break;
  1045. }
  1046. return iStream < 0 ? S_OK : E_FAIL;
  1047. }
  1048. STDMETHODIMP CVobSubFile::Reload()
  1049. {
  1050. CFileStatus s;
  1051. if(!CFile::GetStatus(m_title + _T(".idx"), s)) return E_FAIL;
  1052. return !m_title.IsEmpty() && Open(m_title) ? S_OK : E_FAIL;
  1053. }
  1054. // StretchBlt
  1055. static void PixelAtBiLinear(RGBQUAD& c, int x, int y, CVobSubImage& src)
  1056. {
  1057. int w = src.rect.Width(),
  1058. h = src.rect.Height();
  1059. int x1 = (x >> 16), y1 = (y >> 16) * w,
  1060. x2 = min(x1 + 1, w-1), y2 = min(y1 + w, (h-1)*w);
  1061. RGBQUAD* ptr = src.lpPixels;
  1062. RGBQUAD c11 = ptr[y1 + x1], c12 = ptr[y1 + x2],
  1063. c21 = ptr[y2 + x1], c22 = ptr[y2 + x2];
  1064. __int64 u2 = x & 0xffff,
  1065. v2 = y & 0xffff,
  1066. u1 = 0x10000 - u2,
  1067. v1 = 0x10000 - v2;
  1068. int v1u1 = int(v1*u1 >> 16) * c11.rgbReserved, 
  1069. v1u2 = int(v1*u2 >> 16) * c12.rgbReserved,
  1070. v2u1 = int(v2*u1 >> 16) * c21.rgbReserved, 
  1071. v2u2 = int(v2*u2 >> 16) * c22.rgbReserved;
  1072. c.rgbRed = (c11.rgbRed * v1u1 + c12.rgbRed * v1u2
  1073.   + c21.rgbRed * v2u1 + c22.rgbRed * v2u2) >> 24;
  1074. c.rgbGreen = (c11.rgbGreen * v1u1 + c12.rgbGreen * v1u2
  1075. + c21.rgbGreen * v2u1 + c22.rgbGreen * v2u2) >> 24;
  1076. c.rgbBlue = (c11.rgbBlue * v1u1 + c12.rgbBlue * v1u2
  1077. + c21.rgbBlue * v2u1 + c22.rgbBlue * v2u2) >> 24;
  1078. c.rgbReserved = (v1u1 + v1u2 
  1079. + v2u1 + v2u2) >> 16;
  1080. }
  1081. static void StretchBlt(SubPicDesc& spd, CRect dstrect, CVobSubImage& src)
  1082. {
  1083. if(dstrect.IsRectEmpty()) return;
  1084. if((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) return;
  1085. int sw = src.rect.Width(),
  1086. sh = src.rect.Height(),
  1087. dw = dstrect.Width(),
  1088. dh = dstrect.Height();
  1089. int srcx = 0, 
  1090. srcy = 0,
  1091. srcdx = (sw << 16) / dw >> 1, 
  1092. srcdy = (sh << 16) / dh >> 1;
  1093. if(dstrect.left < 0) {srcx = -dstrect.left * (srcdx<<1); dstrect.left = 0;}
  1094. if(dstrect.top < 0) {srcy = -dstrect.top * (srcdy<<1); dstrect.top = 0;}
  1095. if(dstrect.right > spd.w) {dstrect.right = spd.w;}
  1096. if(dstrect.bottom > spd.h) {dstrect.bottom = spd.h;}
  1097. if((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) return;
  1098. dw = dstrect.Width();
  1099. dh = dstrect.Height();
  1100. for(int y = dstrect.top; y < dstrect.bottom; y++, srcy += (srcdy<<1))
  1101. {
  1102. RGBQUAD* ptr = (RGBQUAD*)&((BYTE*)spd.bits)[y*spd.pitch] + dstrect.left;
  1103. RGBQUAD* endptr = ptr + dw;
  1104. for(int sx = srcx; ptr < endptr; sx += (srcdx<<1), ptr++)
  1105. {
  1106. // PixelAtBiLinear(*ptr, sx, srcy, src);
  1107. ////
  1108. RGBQUAD cc[4];
  1109. PixelAtBiLinear(cc[0], sx, srcy, src);
  1110. PixelAtBiLinear(cc[1], sx+srcdx, srcy, src);
  1111. PixelAtBiLinear(cc[2], sx, srcy+srcdy, src);
  1112. PixelAtBiLinear(cc[3], sx+srcdx, srcy+srcdy, src);
  1113. ptr->rgbRed = (cc[0].rgbRed + cc[1].rgbRed + cc[2].rgbRed + cc[3].rgbRed) >> 2;
  1114. ptr->rgbGreen = (cc[0].rgbGreen + cc[1].rgbGreen + cc[2].rgbGreen + cc[3].rgbGreen) >> 2;
  1115. ptr->rgbBlue = (cc[0].rgbBlue + cc[1].rgbBlue + cc[2].rgbBlue + cc[3].rgbBlue) >> 2;
  1116. ptr->rgbReserved = (cc[0].rgbReserved + cc[1].rgbReserved + cc[2].rgbReserved + cc[3].rgbReserved) >> 2;
  1117. ////
  1118. ptr->rgbRed = ptr->rgbRed * ptr->rgbReserved >> 8;
  1119. ptr->rgbGreen = ptr->rgbGreen * ptr->rgbReserved >> 8;
  1120. ptr->rgbBlue = ptr->rgbBlue * ptr->rgbReserved >> 8;
  1121. ptr->rgbReserved = ~ptr->rgbReserved;
  1122. }
  1123. }
  1124. }
  1125. //
  1126. // CVobSubSettings
  1127. //
  1128. void CVobSubSettings::InitSettings()
  1129. {
  1130. m_size.SetSize(720, 480);
  1131. m_toff = m_x = m_y = 0;
  1132. m_org.SetPoint(0, 0);
  1133. m_scale_x = m_scale_y = m_alpha = 100;
  1134. m_fadein = m_fadeout = 50;
  1135. m_fSmooth = 0;
  1136. m_fAlign = false;
  1137. m_alignhor = m_alignver = 0;
  1138. m_fOnlyShowForcedSubs = false;
  1139. m_fCustomPal = false;
  1140. m_tridx = 0;
  1141. memset(m_orgpal, 0, sizeof(m_orgpal));
  1142. memset(m_cuspal, 0, sizeof(m_cuspal));
  1143. }
  1144. bool CVobSubSettings::GetCustomPal(RGBQUAD* cuspal, int& tridx)
  1145. {
  1146. memcpy(cuspal, m_cuspal, sizeof(RGBQUAD)*4); 
  1147. tridx = m_tridx;
  1148. return(m_fCustomPal);
  1149. }
  1150. void CVobSubSettings::SetCustomPal(RGBQUAD* cuspal, int tridx) 
  1151. {
  1152. memcpy(m_cuspal, cuspal, sizeof(RGBQUAD)*4);
  1153. m_tridx = tridx & 0xf;
  1154. for(int i = 0; i < 4; i++) m_cuspal[i].rgbReserved = (tridx&(1<<i)) ? 0 : 0xff;
  1155. m_img.Invalidate();
  1156. }
  1157. void CVobSubSettings::GetDestrect(CRect& r)
  1158. {
  1159. int w = MulDiv(m_img.rect.Width(), m_scale_x, 100);
  1160. int h = MulDiv(m_img.rect.Height(), m_scale_y, 100);
  1161. if(!m_fAlign)
  1162. {
  1163. r.left = MulDiv(m_img.rect.left, m_scale_x, 100);
  1164. r.right = MulDiv(m_img.rect.right, m_scale_x, 100);
  1165. r.top = MulDiv(m_img.rect.top, m_scale_y, 100);
  1166. r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100);
  1167. }
  1168. else
  1169. {
  1170. switch(m_alignhor)
  1171. {
  1172. case 0: r.left = 0; r.right = w; break; // left
  1173. case 1: r.left = -(w>>1); r.right = -(w>>1) + w; break; // center
  1174. case 2: r.left = -w; r.right = 0; break; // right
  1175. default:
  1176. r.left = MulDiv(m_img.rect.left, m_scale_x, 100);
  1177. r.right = MulDiv(m_img.rect.right, m_scale_x, 100);
  1178. break;
  1179. }
  1180. switch(m_alignver)
  1181. {
  1182. case 0: r.top = 0; r.bottom = h; break; // top
  1183. case 1: r.top = -(h>>1); r.bottom = -(h>>1) + h; break; // center
  1184. case 2: r.top = -h; r.bottom = 0; break; // bottom
  1185. default:
  1186. r.top = MulDiv(m_img.rect.top, m_scale_y, 100);
  1187. r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100);
  1188. break;
  1189. }
  1190. }
  1191. r += m_org;
  1192. }
  1193. void CVobSubSettings::GetDestrect(CRect& r, int w, int h)
  1194. {
  1195. GetDestrect(r);
  1196. r.left = MulDiv(r.left, w, m_size.cx);
  1197. r.right = MulDiv(r.right, w, m_size.cx);
  1198. r.top = MulDiv(r.top, h, m_size.cy);
  1199. r.bottom = MulDiv(r.bottom, h, m_size.cy);
  1200. }
  1201. void CVobSubSettings::SetAlignment(bool fAlign, int x, int y, int hor, int ver)
  1202. {
  1203. if(m_fAlign = fAlign)
  1204. {
  1205. m_org.x = MulDiv(m_size.cx, x, 100);
  1206. m_org.y = MulDiv(m_size.cy, y, 100);
  1207. m_alignhor = min(max(hor, 0), 2);
  1208. m_alignver = min(max(ver, 0), 2);
  1209. }
  1210. else
  1211. {
  1212. m_org.x = m_x;
  1213. m_org.y = m_y;
  1214. }
  1215. }
  1216. #include "RTS.h"
  1217. HRESULT CVobSubSettings::Render(SubPicDesc& spd, RECT& bbox)
  1218. {
  1219. CRect r;
  1220. GetDestrect(r, spd.w, spd.h);
  1221. StretchBlt(spd, r, m_img);
  1222. /*
  1223. CRenderedTextSubtitle rts(NULL);
  1224. rts.CreateDefaultStyle(DEFAULT_CHARSET);
  1225. rts.m_dstScreenSize.SetSize(m_size.cx, m_size.cy);
  1226. CStringW assstr;
  1227. m_img.Polygonize(assstr, false);
  1228. REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay);
  1229. rts.Add(assstr, true, rtStart, rtStop);
  1230. rts.Render(spd, (rtStart+rtStop)/2, 25, r);
  1231. */
  1232. r &= CRect(CPoint(0, 0), CSize(spd.w, spd.h));
  1233. bbox = r;
  1234. return !r.IsRectEmpty() ? S_OK : S_FALSE;
  1235. }
  1236. /////////////////////////////////////////////////////////
  1237. static bool CompressFile(CString fn)
  1238. {
  1239. if(GetVersion() < 0)
  1240. return(false);
  1241. BOOL b = FALSE;
  1242. HANDLE h = CreateFile(fn, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
  1243. if(h != INVALID_HANDLE_VALUE)
  1244. {
  1245. USHORT us = COMPRESSION_FORMAT_DEFAULT;
  1246. DWORD nBytesReturned;
  1247. b = DeviceIoControl(h, FSCTL_SET_COMPRESSION, (LPVOID)&us, 2, NULL, 0, (LPDWORD)&nBytesReturned, NULL);
  1248. CloseHandle(h);
  1249. }
  1250. return(!!b);
  1251. }
  1252. bool CVobSubFile::SaveVobSub(CString fn)
  1253. {
  1254. return WriteIdx(fn + _T(".idx")) && WriteSub(fn + _T(".sub"));
  1255. }
  1256. bool CVobSubFile::SaveWinSubMux(CString fn)
  1257. {
  1258. TrimExtension(fn);
  1259. CStdioFile f;
  1260. if(!f.Open(fn + _T(".sub"), CFile::modeCreate|CFile::modeWrite|CFile::typeText|CFile::shareDenyWrite)) 
  1261. return(false);
  1262. m_img.Invalidate();
  1263. CAutoVectorPtr<BYTE> p4bpp;
  1264. if(!p4bpp.Allocate(720*576/2))
  1265. return(false);
  1266. CArray<SubPos>& sp = m_langs[m_iLang].subpos;
  1267. for(int i = 0; i < sp.GetCount(); i++)
  1268. {
  1269. if(!GetFrame(i)) continue;
  1270. int pal[4] = {0, 1, 2, 3};
  1271. for(int j = 0; j < 5; j++)
  1272. {
  1273. if(j == 4 || !m_img.pal[j].tr)
  1274. {
  1275. j &= 3;
  1276. memset(p4bpp, (j<<4)|j, 720*576/2);
  1277. pal[j] ^= pal[0], pal[0] ^= pal[j], pal[j] ^= pal[0];
  1278. break;
  1279. }
  1280. }
  1281. int tr[4] = {m_img.pal[pal[0]].tr, m_img.pal[pal[1]].tr, m_img.pal[pal[2]].tr, m_img.pal[pal[3]].tr};
  1282. DWORD uipal[4+12];
  1283. if(!m_fCustomPal)
  1284. {
  1285. uipal[0] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[0]].pal]);
  1286. uipal[1] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[1]].pal]);
  1287. uipal[2] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[2]].pal]);
  1288. uipal[3] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[3]].pal]);
  1289. }
  1290. else
  1291. {
  1292. uipal[0] = *((DWORD*)&m_img.cuspal[pal[0]]) & 0xffffff;
  1293. uipal[1] = *((DWORD*)&m_img.cuspal[pal[1]]) & 0xffffff;
  1294. uipal[2] = *((DWORD*)&m_img.cuspal[pal[2]]) & 0xffffff;
  1295. uipal[3] = *((DWORD*)&m_img.cuspal[pal[3]]) & 0xffffff;
  1296. }
  1297. CMap<DWORD,DWORD&,BYTE,BYTE&> palmap;
  1298. palmap[uipal[0]] = 0;
  1299. palmap[uipal[1]] = 1;
  1300. palmap[uipal[2]] = 2;
  1301. palmap[uipal[3]] = 3;
  1302. uipal[0] = 0xff; // blue background
  1303. int w = m_img.rect.Width()-2;
  1304. int h = m_img.rect.Height()-2;
  1305. int pitch = (((w+1)>>1) + 3) & ~3;
  1306. for(int y = 0; y < h; y++)
  1307. {
  1308. DWORD* p = (DWORD*)&m_img.lpPixels[(y+1)*(w+2)+1];
  1309. for(int x = 0; x < w; x++, p++)
  1310. {
  1311. BYTE c = 0;
  1312. if(*p & 0xff000000)
  1313. {
  1314. DWORD uic = *p & 0xffffff;
  1315. palmap.Lookup(uic, c);
  1316. }
  1317. BYTE& c4bpp = p4bpp[(h-y-1)*pitch+(x>>1)];
  1318. c4bpp = (x&1) ? ((c4bpp&0xf0)|c) : ((c4bpp&0x0f)|(c<<4));
  1319. }
  1320. }
  1321. int t1 = m_img.start, t2 = t1 + m_img.delay /*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/;
  1322. ASSERT(t2>t1);
  1323. if(t2 <= 0) continue;
  1324. if(t1 < 0) t1 = 0;
  1325. CString bmpfn;
  1326. bmpfn.Format(_T("%s_%06d.bmp"), fn, i+1);
  1327. CString str;
  1328. str.Format(_T("%st%02d:%02d:%02d:%02d %02d:%02d:%02d:%02dt%03d %03d %03d %03d %d %d %d %dn"), 
  1329. bmpfn,
  1330. t1/1000/60/60, (t1/1000/60)%60, (t1/1000)%60, (t1%1000)/10,
  1331. t2/1000/60/60, (t2/1000/60)%60, (t2/1000)%60, (t2%1000)/10,
  1332. m_img.rect.Width(), m_img.rect.Height(), m_img.rect.left, m_img.rect.top,
  1333. (tr[0]<<4)|tr[0], (tr[1]<<4)|tr[1], (tr[2]<<4)|tr[2], (tr[3]<<4)|tr[3]);
  1334. f.WriteString(str);
  1335. BITMAPFILEHEADER fhdr = 
  1336. {
  1337. 0x4d42,
  1338. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + pitch*h,
  1339. 0, 0,
  1340. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD)
  1341. };
  1342. BITMAPINFOHEADER ihdr = 
  1343. {
  1344. sizeof(BITMAPINFOHEADER),
  1345. w, h, 1, 4, 0,
  1346. 0,
  1347. pitch*h, 0,
  1348. 16, 4
  1349. };
  1350. CFile bmp;
  1351. if(bmp.Open(bmpfn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite))
  1352. {
  1353. bmp.Write(&fhdr, sizeof(fhdr));
  1354. bmp.Write(&ihdr, sizeof(ihdr));
  1355. bmp.Write(uipal, sizeof(RGBQUAD)*16);
  1356. bmp.Write(p4bpp, pitch*h);
  1357. bmp.Close();
  1358. CompressFile(bmpfn);
  1359. }
  1360. }
  1361. return(true);
  1362. }
  1363. bool CVobSubFile::SaveScenarist(CString fn)
  1364. {
  1365. TrimExtension(fn);
  1366. CStdioFile f;
  1367. if(!f.Open(fn + _T(".sst"), CFile::modeCreate|CFile::modeWrite|CFile::typeText|CFile::shareDenyWrite)) 
  1368. return(false);
  1369. m_img.Invalidate();
  1370. fn.Replace('\', '/');
  1371. CString title = fn.Mid(fn.ReverseFind('/')+1);
  1372. TCHAR buff[MAX_PATH], * pFilePart = buff;
  1373. if(GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0)
  1374. return(false);
  1375. CString fullpath = CString(buff).Left(pFilePart - buff);
  1376. fullpath.TrimRight(_T("\/"));
  1377. if(fullpath.IsEmpty())
  1378. return(false);
  1379. CString str, str2;
  1380. str += _T("st_formatt2n");
  1381. str += _T("Display_Startt%sn");
  1382. str += _T("TV_Typett%sn");
  1383. str += _T("Tape_TypetNON_DROPn");
  1384. str += _T("Pixel_Areat(0 %d)n");
  1385. str += _T("Directoryt%sn");
  1386. str += _T("Subtitlet%sn");
  1387. str += _T("Display_Areat(0 2 719 %d)n");
  1388. str += _T("Contrastt(15 15 15 0)n");
  1389. str += _T("n");
  1390. str += _T("PAt(0 0 255 - - - )n");
  1391. str += _T("E1t(255 0 0 - - - )n");
  1392. str += _T("E2t(0 0 0 - - - )n");
  1393. str += _T("BGt(255 255 255 - - - )n");
  1394. str += _T("n");
  1395. str += _T("SP_NUMBERtSTARTtENDtFILE_NAMEn");
  1396. str2.Format(str, 
  1397. !m_fOnlyShowForcedSubs ? _T("non_forced") : _T("forced"),
  1398. m_size.cy == 480 ? _T("NTSC") : _T("PAL"), 
  1399. m_size.cy-3,
  1400. fullpath,
  1401. title, 
  1402. m_size.cy == 480 ? 479 : 574);
  1403. f.WriteString(str2);
  1404. f.Flush();
  1405. RGBQUAD pal[16] = 
  1406. {
  1407. {255, 0, 0, 0},
  1408. {0, 0, 255, 0},
  1409. {0, 0, 0, 0},
  1410. {255, 255, 255, 0},
  1411. {0, 255, 0, 0},
  1412. {255, 0, 255, 0},
  1413. {0, 255, 255, 0},
  1414. {125, 125, 0, 0},
  1415. {125, 125, 125, 0},
  1416. {225, 225, 225, 0},
  1417. {0, 0, 125, 0},
  1418. {0, 125, 0, 0},
  1419. {125, 0, 0, 0},
  1420. {255, 0, 222, 0},
  1421. {0, 125, 222, 0},
  1422. {125, 0, 125, 0},
  1423. };
  1424. BITMAPFILEHEADER fhdr = 
  1425. {
  1426. 0x4d42,
  1427. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + 360*(m_size.cy-2),
  1428. 0, 0,
  1429. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD)
  1430. };
  1431. BITMAPINFOHEADER ihdr = 
  1432. {
  1433.         sizeof(BITMAPINFOHEADER),
  1434. 720, m_size.cy-2, 1, 4, 0,
  1435. 360*(m_size.cy-2),
  1436. 0, 0,
  1437. 16, 4
  1438. };
  1439. bool fCustomPal = m_fCustomPal;
  1440. m_fCustomPal = true;
  1441. RGBQUAD tempCusPal[4], newCusPal[4+12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}};
  1442. memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal));
  1443. memcpy(m_cuspal, newCusPal, sizeof(m_cuspal));
  1444. CAutoVectorPtr<BYTE> p4bpp;
  1445. if(!p4bpp.Allocate((m_size.cy-2)*360))
  1446. return(false);
  1447. BYTE colormap[16];
  1448. for(int i = 0; i < 16; i++) 
  1449. {
  1450. int idx = 0, maxdif = 255*255*3+1;
  1451. for(int j = 0; j < 16 && maxdif; j++)
  1452. {
  1453. int rdif = pal[j].rgbRed - m_orgpal[i].rgbRed;
  1454. int gdif = pal[j].rgbGreen - m_orgpal[i].rgbGreen;
  1455. int bdif = pal[j].rgbBlue - m_orgpal[i].rgbBlue;
  1456. int dif = rdif*rdif + gdif*gdif + bdif*bdif;
  1457. if(dif < maxdif) {maxdif = dif; idx = j;}
  1458. }
  1459. colormap[i] = idx+1;
  1460. }
  1461. int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0};
  1462. CArray<SubPos>& sp = m_langs[m_iLang].subpos;
  1463. for(int i = 0, k = 0; i < sp.GetCount(); i++)
  1464. {
  1465. if(!GetFrame(i)) continue;
  1466. for(int j = 0; j < 5; j++)
  1467. {
  1468. if(j == 4 || !m_img.pal[j].tr)
  1469. {
  1470. j &= 3;
  1471. memset(p4bpp, (j<<4)|j, (m_size.cy-2)*360);
  1472. break;
  1473. }
  1474. }
  1475. for(int y = max(m_img.rect.top+1, 2); y < m_img.rect.bottom-1; y++)
  1476. {
  1477. ASSERT(m_size.cy-y-1 >= 0);
  1478. if(m_size.cy-y-1 < 0) break;
  1479. DWORD* p = (DWORD*)&m_img.lpPixels[(y-m_img.rect.top)*m_img.rect.Width()+1];
  1480. for(int x = m_img.rect.left+1; x < m_img.rect.right-1; x++, p++)
  1481. {
  1482. DWORD rgb = *p&0xffffff;
  1483. BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3;
  1484. BYTE& c4bpp = p4bpp[(m_size.cy-y-1)*360+(x>>1)];
  1485. c4bpp = (x&1) ? ((c4bpp&0xf0)|c) : ((c4bpp&0x0f)|(c<<4));
  1486. }
  1487. }
  1488. CString bmpfn;
  1489. bmpfn.Format(_T("%s_%04d.bmp"), fn, i+1);
  1490. title = bmpfn.Mid(bmpfn.ReverseFind('/')+1);
  1491. // E1, E2, P, Bg
  1492. int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]};
  1493. c[0]^=c[1], c[1]^=c[0], c[0]^=c[1];
  1494. if(memcmp(pc, c, sizeof(c)))
  1495. {
  1496. memcpy(pc, c, sizeof(c));
  1497. str.Format(_T("Colort (%d %d %d %d)n"), c[0], c[1], c[2], c[3]);
  1498. f.WriteString(str);
  1499. }
  1500. // E1, E2, P, Bg
  1501. int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr};
  1502. a[0]^=a[1], a[1]^=a[0], a[0]^=a[1];
  1503. if(memcmp(pa, a, sizeof(a)))
  1504. {
  1505. memcpy(pa, a, sizeof(a));
  1506. str.Format(_T("Contrast (%d %d %d %d)n"), a[0], a[1], a[2], a[3]);
  1507. f.WriteString(str);
  1508. }
  1509. int t1 = sp[i].start;
  1510. int h1 = t1/1000/60/60, m1 = (t1/1000/60)%60, s1 = (t1/1000)%60;
  1511. int f1 = (int)((m_size.cy==480?29.97:25)*(t1%1000)/1000);
  1512. int t2 = sp[i].stop;
  1513. int h2 = t2/1000/60/60, m2 = (t2/1000/60)%60, s2 = (t2/1000)%60;
  1514. int f2 = (int)((m_size.cy==480?29.97:25)*(t2%1000)/1000);
  1515. if(t2 <= 0) continue;
  1516. if(t1 < 0) t1 = 0;
  1517. if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2)
  1518. {
  1519. f2++;
  1520. if(f2 == (m_size.cy==480?30:25)) {f2 = 0; s2++; if(s2 == 60) {s2 = 0; m2++; if(m2 == 60) {m2 = 0; h2++;}}}
  1521. }
  1522. if(i < sp.GetCount()-1)
  1523. {
  1524. int t3 = sp[i+1].start;
  1525. int h3 = t3/1000/60/60, m3 = (t3/1000/60)%60, s3 = (t3/1000)%60;
  1526. int f3 = (int)((m_size.cy==480?29.97:25)*(t3%1000)/1000);
  1527. if(h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) 
  1528. {
  1529. f2--;
  1530. if(f2 == -1) {f2 = (m_size.cy==480?29:24); s2--; if(s2 == -1) {s2 = 59; m2--; if(m2 == -1) {m2 = 59; if(h2 > 0) h2--;}}}
  1531. }
  1532. }
  1533. if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2)
  1534. continue;
  1535. str.Format(_T("%04dt%02d:%02d:%02d:%02dt%02d:%02d:%02d:%02dt%sn"),
  1536. ++k,
  1537. h1, m1, s1, f1,
  1538. h2, m2, s2, f2,
  1539. title);
  1540. f.WriteString(str);
  1541. CFile bmp;
  1542. if(bmp.Open(bmpfn, CFile::modeCreate|CFile::modeWrite|CFile::modeRead|CFile::typeBinary))
  1543. {
  1544. bmp.Write(&fhdr, sizeof(fhdr));
  1545. bmp.Write(&ihdr, sizeof(ihdr));
  1546. bmp.Write(newCusPal, sizeof(RGBQUAD)*16);
  1547. bmp.Write(p4bpp, 360*(m_size.cy-2));
  1548. bmp.Close();
  1549. CompressFile(bmpfn);
  1550. }
  1551. }
  1552. m_fCustomPal = fCustomPal;
  1553. memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal));
  1554. return(true);
  1555. }
  1556. bool CVobSubFile::SaveMaestro(CString fn)
  1557. {
  1558. TrimExtension(fn);
  1559. CStdioFile f;
  1560. if(!f.Open(fn + _T(".son"), CFile::modeCreate|CFile::modeWrite|CFile::typeText|CFile::shareDenyWrite)) 
  1561. return(false);
  1562. m_img.Invalidate();
  1563. fn.Replace('\', '/');
  1564. CString title = fn.Mid(fn.ReverseFind('/')+1);
  1565. TCHAR buff[MAX_PATH], * pFilePart = buff;
  1566. if(GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0)
  1567. return(false);
  1568. CString fullpath = CString(buff).Left(pFilePart - buff);
  1569. fullpath.TrimRight(_T("\/"));
  1570. if(fullpath.IsEmpty())
  1571. return(false);
  1572. CString str, str2;
  1573. str += _T("st_formatt2n");
  1574. str += _T("Display_Startt%sn");
  1575. str += _T("TV_Typett%sn");
  1576. str += _T("Tape_TypetNON_DROPn");
  1577. str += _T("Pixel_Areat(0 %d)n");
  1578. str += _T("Directoryt%sn");
  1579. str += _T("Subtitlet%sn");
  1580. str += _T("Display_Areat(0 2 719 %d)n");
  1581. str += _T("Contrastt(15 15 15 0)n");
  1582. str += _T("n");
  1583. str += _T("SP_NUMBERtSTARTtENDtFILE_NAMEn");
  1584. str2.Format(str, 
  1585. !m_fOnlyShowForcedSubs ? _T("non_forced") : _T("forced"),
  1586. m_size.cy == 480 ? _T("NTSC") : _T("PAL"), 
  1587. m_size.cy-3, 
  1588. fullpath,
  1589. title, 
  1590. m_size.cy == 480 ? 479 : 574);
  1591. f.WriteString(str2);
  1592. f.Flush();
  1593. RGBQUAD pal[16] = 
  1594. {
  1595. {255, 0, 0, 0},
  1596. {0, 0, 255, 0},
  1597. {0, 0, 0, 0},
  1598. {255, 255, 255, 0},
  1599. {0, 255, 0, 0},
  1600. {255, 0, 255, 0},
  1601. {0, 255, 255, 0},
  1602. {125, 125, 0, 0},
  1603. {125, 125, 125, 0},
  1604. {225, 225, 225, 0},
  1605. {0, 0, 125, 0},
  1606. {0, 125, 0, 0},
  1607. {125, 0, 0, 0},
  1608. {255, 0, 222, 0},
  1609. {0, 125, 222, 0},
  1610. {125, 0, 125, 0},
  1611. };
  1612. BITMAPFILEHEADER fhdr = 
  1613. {
  1614. 0x4d42,
  1615. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + 360*(m_size.cy-2),
  1616. 0, 0,
  1617. sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD)
  1618. };
  1619. BITMAPINFOHEADER ihdr = 
  1620. {
  1621.         sizeof(BITMAPINFOHEADER),
  1622. 720, m_size.cy-2, 1, 4, 0,
  1623. 360*(m_size.cy-2),
  1624. 0, 0,
  1625. 16, 4
  1626. };
  1627. bool fCustomPal = m_fCustomPal;
  1628. m_fCustomPal = true;
  1629. RGBQUAD tempCusPal[4], newCusPal[4+12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}};
  1630. memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal));
  1631. memcpy(m_cuspal, newCusPal, sizeof(m_cuspal));
  1632. CAutoVectorPtr<BYTE> p4bpp;
  1633. if(!p4bpp.Allocate((m_size.cy-2)*360))
  1634. return(false);
  1635. BYTE colormap[16];
  1636. for(int i = 0; i < 16; i++)
  1637. colormap[i] = i;
  1638. CFile spf;
  1639. if(spf.Open(fn + _T(".spf"), CFile::modeCreate|CFile::modeWrite|CFile::typeBinary))
  1640. {
  1641. for(int i = 0; i < 16; i++) 
  1642. {
  1643. COLORREF c = (m_orgpal[i].rgbBlue<<16) | (m_orgpal[i].rgbGreen<<8) | m_orgpal[i].rgbRed;
  1644. spf.Write(&c, sizeof(COLORREF));
  1645. }
  1646. spf.Close();
  1647. }
  1648. int pc[4] = {1,1,1,1}, pa[4] = {15,15,15,0};
  1649. CArray<SubPos>& sp = m_langs[m_iLang].subpos;
  1650. for(int i = 0, k = 0; i < sp.GetCount(); i++)
  1651. {
  1652. if(!GetFrame(i)) continue;
  1653. for(int j = 0; j < 5; j++)
  1654. {
  1655. if(j == 4 || !m_img.pal[j].tr)
  1656. {
  1657. j &= 3;
  1658. memset(p4bpp, (j<<4)|j, (m_size.cy-2)*360);
  1659. break;
  1660. }
  1661. }
  1662. for(int y = max(m_img.rect.top+1, 2); y < m_img.rect.bottom-1; y++)
  1663. {
  1664. ASSERT(m_size.cy-y-1 >= 0);
  1665. if(m_size.cy-y-1 < 0) break;
  1666. DWORD* p = (DWORD*)&m_img.lpPixels[(y-m_img.rect.top)*m_img.rect.Width()+1];
  1667. for(int x = m_img.rect.left+1; x < m_img.rect.right-1; x++, p++)
  1668. {
  1669. DWORD rgb = *p&0xffffff;
  1670. BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3;
  1671. BYTE& c4bpp = p4bpp[(m_size.cy-y-1)*360+(x>>1)];
  1672. c4bpp = (x&1) ? ((c4bpp&0xf0)|c) : ((c4bpp&0x0f)|(c<<4));
  1673. }
  1674. }
  1675. CString bmpfn;
  1676. bmpfn.Format(_T("%s_%04d.bmp"), fn, i+1);
  1677. title = bmpfn.Mid(bmpfn.ReverseFind('/')+1);
  1678. // E1, E2, P, Bg
  1679. int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]};
  1680. if(memcmp(pc, c, sizeof(c)))
  1681. {
  1682. memcpy(pc, c, sizeof(c));
  1683. str.Format(_T("Colort (%d %d %d %d)n"), c[0], c[1], c[2], c[3]);
  1684. f.WriteString(str);
  1685. }
  1686. // E1, E2, P, Bg
  1687. int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr};
  1688. if(memcmp(pa, a, sizeof(a)))
  1689. {
  1690. memcpy(pa, a, sizeof(a));
  1691. str.Format(_T("Contrast (%d %d %d %d)n"), a[0], a[1], a[2], a[3]);
  1692. f.WriteString(str);
  1693. }
  1694. int t1 = sp[i].start;
  1695. int h1 = t1/1000/60/60, m1 = (t1/1000/60)%60, s1 = (t1/1000)%60;
  1696. int f1 = (int)((m_size.cy==480?29.97:25)*(t1%1000)/1000);
  1697. int t2 = sp[i].stop;
  1698. int h2 = t2/1000/60/60, m2 = (t2/1000/60)%60, s2 = (t2/1000)%60;
  1699. int f2 = (int)((m_size.cy==480?29.97:25)*(t2%1000)/1000);
  1700. if(t2 <= 0) continue;
  1701. if(t1 < 0) t1 = 0;
  1702. if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2)
  1703. {
  1704. f2++;
  1705. if(f2 == (m_size.cy==480?30:25)) {f2 = 0; s2++; if(s2 == 60) {s2 = 0; m2++; if(m2 == 60) {m2 = 0; h2++;}}}
  1706. }
  1707. if(i < sp.GetCount()-1)
  1708. {
  1709. int t3 = sp[i+1].start;
  1710. int h3 = t3/1000/60/60, m3 = (t3/1000/60)%60, s3 = (t3/1000)%60;
  1711. int f3 = (int)((m_size.cy==480?29.97:25)*(t3%1000)/1000);
  1712. if(h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2)
  1713. {
  1714. f2--;
  1715. if(f2 == -1) {f2 = (m_size.cy==480?29:24); s2--; if(s2 == -1) {s2 = 59; m2--; if(m2 == -1) {m2 = 59; if(h2 > 0) h2--;}}}
  1716. }
  1717. }
  1718. if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2)
  1719. continue;
  1720. str.Format(_T("%04dt%02d:%02d:%02d:%02dt%02d:%02d:%02d:%02dt%sn"),
  1721. ++k,
  1722. h1, m1, s1, f1,
  1723. h2, m2, s2, f2,
  1724. title);
  1725. f.WriteString(str);
  1726. CFile bmp;
  1727. if(bmp.Open(bmpfn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary))
  1728. {
  1729. bmp.Write(&fhdr, sizeof(fhdr));
  1730. bmp.Write(&ihdr, sizeof(ihdr));
  1731. bmp.Write(newCusPal, sizeof(RGBQUAD)*16);
  1732. bmp.Write(p4bpp, 360*(m_size.cy-2));
  1733. bmp.Close();
  1734. CompressFile(bmpfn);
  1735. }
  1736. }
  1737. m_fCustomPal = fCustomPal;
  1738. memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal));
  1739. return(true);
  1740. }
  1741. //
  1742. // CVobSubStream
  1743. //
  1744. CVobSubStream::CVobSubStream(CCritSec* pLock)
  1745. : ISubPicProviderImpl(pLock)
  1746. {
  1747. }
  1748. CVobSubStream::~CVobSubStream()
  1749. {
  1750. }
  1751. void CVobSubStream::Open(CString name, BYTE* pData, int len)
  1752. {
  1753. CAutoLock cAutoLock(&m_csSubPics);
  1754. m_name = name;
  1755. CList<CString> lines;
  1756. Explode(CString(CStringA((CHAR*)pData, len)), lines, 'n');
  1757. while(lines.GetCount())
  1758. {
  1759. CList<CString> sl;
  1760. Explode(lines.RemoveHead(), sl, ':', 2);
  1761. if(sl.GetCount() != 2) continue;
  1762. CString key = sl.GetHead();
  1763. CString value = sl.GetTail();
  1764. if(key == _T("size"))
  1765. _stscanf(value, _T("%dx %d"), &m_size.cx, &m_size.cy);
  1766. else if(key == _T("org"))
  1767. _stscanf(value, _T("%d, %d"), &m_org.x, &m_org.y);
  1768. else if(key == _T("scale"))
  1769. _stscanf(value, _T("%d%%, %d%%"), &m_scale_x, &m_scale_y);
  1770. else if(key == _T("alpha"))
  1771. _stscanf(value, _T("%d%%"), &m_alpha);
  1772. else if(key == _T("smooth"))
  1773. m_fSmooth = 
  1774. value == _T("0") || value == _T("OFF") ? 0 : 
  1775. value == _T("1") || value == _T("ON") ? 1 : 
  1776. value == _T("2") || value == _T("OLD") ? 2 : 
  1777. 0;
  1778. else if(key == _T("align"))
  1779. {
  1780. Explode(value, sl, ' ');
  1781. if(sl.GetCount() == 4) sl.RemoveAt(sl.FindIndex(1));
  1782. if(sl.GetCount() == 3)
  1783. {
  1784. m_fAlign = sl.RemoveHead() == _T("ON");
  1785. CString hor = sl.GetHead(), ver = sl.GetTail();
  1786. m_alignhor = hor == _T("LEFT") ? 0 : hor == _T("CENTER") ? 1 : hor == _T("RIGHT") ? 2 : 1;
  1787. m_alignver = ver == _T("TOP") ? 0 : ver == _T("CENTER") ? 1 : ver == _T("BOTTOM") ? 2 : 2;
  1788. }
  1789. }
  1790. else if(key == _T("fade in/out"))
  1791. _stscanf(value, _T("%d%, %d%"), &m_fadein, &m_fadeout);
  1792. else if(key == _T("time offset"))
  1793. m_toff = _tcstol(value, NULL, 10);
  1794. else if(key == _T("forced subs"))
  1795. m_fOnlyShowForcedSubs = value == _T("1") || value == _T("ON");
  1796. else if(key == _T("palette"))
  1797. {
  1798. Explode(value, sl, ',', 16);
  1799. for(int i = 0; i < 16 && sl.GetCount(); i++)
  1800. *(DWORD*)&m_orgpal[i] = _tcstol(sl.RemoveHead(), NULL, 16);
  1801. }
  1802. else if(key == _T("custom colors"))
  1803. {
  1804. m_fCustomPal = Explode(value, sl, ',', 3) == _T("ON");
  1805. if(sl.GetCount() == 3)
  1806. {
  1807. sl.RemoveHead();
  1808. CList<CString> tridx, colors;
  1809. Explode(sl.RemoveHead(), tridx, ':', 2);
  1810. if(tridx.RemoveHead() == _T("tridx"))
  1811. {
  1812. TCHAR tr[4];
  1813. _stscanf(tridx.RemoveHead(), _T("%c%c%c%c"), &tr[0], &tr[1], &tr[2], &tr[3]);
  1814. for(int i = 0; i < 4; i++)
  1815. m_tridx |= ((tr[i]=='1')?1:0)<<i;
  1816. }
  1817. Explode(sl.RemoveHead(), colors, ':', 2);
  1818. if(colors.RemoveHead() == _T("colors"))
  1819. {
  1820. Explode(colors.RemoveHead(), colors, ',', 4);
  1821. for(int i = 0; i < 4 && colors.GetCount(); i++)
  1822. *(DWORD*)&m_cuspal[i] = _tcstol(colors.RemoveHead(), NULL, 16);
  1823. }
  1824. }
  1825. }
  1826. }
  1827. }
  1828. void CVobSubStream::Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len)
  1829. {
  1830. if(len <= 4 || ((pData[0]<<8)|pData[1]) != len) return;
  1831. CVobSubImage vsi;
  1832. vsi.GetPacketInfo(pData, (pData[0]<<8)|pData[1], (pData[2]<<8)|pData[3]);
  1833. CAutoPtr<SubPic> p(new SubPic());
  1834. p->tStart = tStart;
  1835. p->tStop = vsi.delay > 0 ? (tStart + 10000i64*vsi.delay) : tStop;
  1836. p->pData.SetSize(len);
  1837. memcpy(p->pData.GetData(), pData, p->pData.GetSize());
  1838. CAutoLock cAutoLock(&m_csSubPics);
  1839. while(m_subpics.GetCount() && m_subpics.GetTail()->tStart >= tStart)
  1840. m_subpics.RemoveTail();
  1841. m_subpics.AddTail(p);
  1842. }
  1843. void CVobSubStream::RemoveAll()
  1844. {
  1845. CAutoLock cAutoLock(&m_csSubPics);
  1846. m_subpics.RemoveAll();
  1847. }
  1848. STDMETHODIMP CVobSubStream::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  1849. {
  1850.     CheckPointer(ppv, E_POINTER);
  1851.     *ppv = NULL;
  1852.     return 
  1853. QI(IPersist)
  1854. QI(ISubStream)
  1855. QI(ISubPicProvider)
  1856. __super::NonDelegatingQueryInterface(riid, ppv);
  1857. }
  1858. // ISubPicProvider
  1859. STDMETHODIMP_(POSITION) CVobSubStream::GetStartPosition(REFERENCE_TIME rt, double fps)
  1860. {
  1861. CAutoLock cAutoLock(&m_csSubPics);
  1862. POSITION pos = m_subpics.GetTailPosition();
  1863. for(; pos; m_subpics.GetPrev(pos))
  1864. {
  1865. SubPic* sp = m_subpics.GetAt(pos);
  1866. if(sp->tStart <= rt)
  1867. {
  1868. if(sp->tStop <= rt) m_subpics.GetNext(pos);
  1869. break;
  1870. }
  1871. }
  1872. return(pos);
  1873. }
  1874. STDMETHODIMP_(POSITION) CVobSubStream::GetNext(POSITION pos)
  1875. {
  1876. CAutoLock cAutoLock(&m_csSubPics);
  1877. m_subpics.GetNext(pos);
  1878.     return pos;
  1879. }
  1880. STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStart(POSITION pos, double fps)
  1881. {
  1882. CAutoLock cAutoLock(&m_csSubPics);
  1883. return m_subpics.GetAt(pos)->tStart;
  1884. }
  1885. STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStop(POSITION pos, double fps)
  1886. {
  1887. CAutoLock cAutoLock(&m_csSubPics);
  1888. return m_subpics.GetAt(pos)->tStop;
  1889. }
  1890. STDMETHODIMP_(bool) CVobSubStream::IsAnimated(POSITION pos)
  1891. {
  1892. return(false);
  1893. }
  1894. STDMETHODIMP CVobSubStream::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox)
  1895. {
  1896. if(spd.bpp != 32) return E_INVALIDARG;
  1897. POSITION pos = m_subpics.GetTailPosition();
  1898. for(; pos; m_subpics.GetPrev(pos))
  1899. {
  1900. SubPic* sp = m_subpics.GetAt(pos);
  1901. if(sp->tStart <= rt && rt < sp->tStop)
  1902. {
  1903. if(m_img.iIdx != (int)pos)
  1904. {
  1905. BYTE* pData = sp->pData.GetData();
  1906. m_img.Decode(
  1907. pData, (pData[0]<<8)|pData[1], (pData[2]<<8)|pData[3],
  1908. m_fCustomPal, m_tridx, m_orgpal, m_cuspal, true);
  1909. m_img.iIdx = (int)pos;
  1910. }
  1911. return __super::Render(spd, bbox);
  1912. }
  1913. }
  1914. return E_FAIL;
  1915. }
  1916. // IPersist
  1917. STDMETHODIMP CVobSubStream::GetClassID(CLSID* pClassID)
  1918. {
  1919. return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER;
  1920. }
  1921. // ISubStream
  1922. STDMETHODIMP_(int) CVobSubStream::GetStreamCount()
  1923. {
  1924. return 1;
  1925. }
  1926. STDMETHODIMP CVobSubStream::GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID)
  1927. {
  1928. CAutoLock cAutoLock(&m_csSubPics);
  1929. if(ppName)
  1930. {
  1931. if(!(*ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength()+1)*sizeof(WCHAR))))
  1932. return E_OUTOFMEMORY;
  1933. wcscpy(*ppName, CStringW(m_name));
  1934. }
  1935. if(pLCID)
  1936. {
  1937. *pLCID = 0; // TODO
  1938. }
  1939. return S_OK;
  1940. }
  1941. STDMETHODIMP_(int) CVobSubStream::GetStream()
  1942. {
  1943. return 0;
  1944. }
  1945. STDMETHODIMP CVobSubStream::SetStream(int iStream)
  1946. {
  1947. return iStream == 0 ? S_OK : E_FAIL;
  1948. }