From 3f1d6bcefa6890c86cc78456a6c675deed975264 Mon Sep 17 00:00:00 2001 From: Cyberbeing Date: Sun, 19 Apr 2015 00:14:17 -0700 Subject: [PATCH] Support Animated Vobsub --- src/subtitles/VobSubFile.cpp | 1959 ++++++++++++++----------- src/subtitles/VobSubFile.h | 296 ++-- src/subtitles/VobSubFileRipper.cpp | 2076 +++++++++++++------------- src/subtitles/VobSubFileRipper.h | 264 ++-- src/subtitles/VobSubImage.cpp | 2199 +++++++++++++++------------- src/subtitles/VobSubImage.h | 136 +- 6 files changed, 3619 insertions(+), 3311 deletions(-) diff --git a/src/subtitles/VobSubFile.cpp b/src/subtitles/VobSubFile.cpp index 144b30720..6eb598077 100644 --- a/src/subtitles/VobSubFile.cpp +++ b/src/subtitles/VobSubFile.cpp @@ -1,26 +1,27 @@ -/* -* Copyright (C) 2003-2006 Gabest -* http://www.gabest.org -* -* This Program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* This Program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with GNU Make; see the file COPYING. If not, write to -* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -* http://www.gnu.org/copyleft/gpl.html -* -*/ +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 see Authors.txt + * + * This file is part of MPC-HC. + * + * MPC-HC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * MPC-HC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #include "stdafx.h" #include +#include #include "TextFile.h" #include "VobSubFile.h" #ifndef USE_UNRAR_STATIC @@ -28,12 +29,14 @@ #else #include "unrar/dll.hpp" #endif - +#include "RTS.h" // -struct lang_type {unsigned short id; LPCSTR lang_long;} lang_tbl[] = -{ +struct lang_type { + unsigned short id; + LPCSTR lang_long; +} lang_tbl[] = { {'--', "(Not detected)"}, {'cc', "Closed Caption"}, {'aa', "Afar"}, @@ -173,7 +176,7 @@ struct lang_type {unsigned short id; LPCSTR lang_long;} lang_tbl[] = {'vo', "Volapuk"}, {'wo', "Wolof"}, {'xh', "Xhosa"}, - {'yi', "Yiddish"}, // formerly ji + {'yi', "Yiddish"}, // formerly ji {'yo', "Yoruba"}, {'za', "Zhuang"}, {'zh', "Chinese"}, @@ -182,17 +185,21 @@ struct lang_type {unsigned short id; LPCSTR lang_long;} lang_tbl[] = int find_lang(unsigned short id) { - int mid, lo = 0, hi = countof(lang_tbl) - 1; + int lo = 0, hi = _countof(lang_tbl) - 1; - while(lo < hi) - { - mid = (lo + hi) >> 1; - if(id < lang_tbl[mid].id) hi = mid; - else if(id > lang_tbl[mid].id) lo = mid + 1; - else return(mid); + while (lo < hi) { + int mid = (lo + hi) >> 1; + + if (id < lang_tbl[mid].id) { + hi = mid; + } else if (id > lang_tbl[mid].id) { + lo = mid + 1; + } else { + return mid; + } } - return(id == lang_tbl[lo].id ? lo : 0); + return (id == lang_tbl[lo].id ? lo : 0); } CString FindLangFromId(WORD id) @@ -206,7 +213,8 @@ CString FindLangFromId(WORD id) CVobSubFile::CVobSubFile(CCritSec* pLock) : CSubPicProviderImpl(pLock) - , m_sub(1024*1024) + , m_sub(1024 * 1024) + , m_iLang(0) { } @@ -227,8 +235,7 @@ bool CVobSubFile::Copy(CVobSubFile& vsf) m_sub.SetLength(vsf.m_sub.GetLength()); m_sub.SeekToBegin(); - for(int i = 0; i < 32; i++) - { + for (size_t i = 0; i < m_langs.size(); i++) { SubLang& src = vsf.m_langs[i]; SubLang& dst = m_langs[i]; @@ -236,37 +243,38 @@ bool CVobSubFile::Copy(CVobSubFile& vsf) dst.name = src.name; dst.alt = src.alt; - for(size_t j = 0; j < src.subpos.GetCount(); j++) - { + for (size_t j = 0; j < src.subpos.GetCount(); j++) { SubPos& sp = src.subpos[j]; - if(!sp.fValid) continue; + if (!sp.fValid) { + continue; + } - if(sp.filepos != vsf.m_sub.Seek(sp.filepos, CFile::begin)) + if (sp.filepos != (__int64)vsf.m_sub.Seek(sp.filepos, CFile::begin)) { continue; + } sp.filepos = m_sub.GetPosition(); BYTE buff[2048]; - vsf.m_sub.Read(buff, 2048); - m_sub.Write(buff, 2048); + UINT uRead = vsf.m_sub.Read(buff, 2048); + m_sub.Write(buff, uRead); - WORD packetsize = (buff[buff[0x16]+0x18]<<8) | buff[buff[0x16]+0x19]; + WORD packetsize = (buff[buff[0x16] + 0x18] << 8) | buff[buff[0x16] + 0x19]; - for(int k = 0, size, sizeleft = packetsize - 4; - k < packetsize - 4; - k += size, sizeleft -= size) - { - int hsize = buff[0x16]+0x18 + ((buff[0x15]&0x80) ? 4 : 0); + for (int k = 0, size, sizeleft = packetsize - 4; + k < packetsize - 4; + k += size, sizeleft -= size) { + int hsize = buff[0x16] + 0x18 + ((buff[0x15] & 0x80) ? 4 : 0); size = min(sizeleft, 2048 - hsize); - if(size != sizeleft) - { - while(vsf.m_sub.Read(buff, 2048)) - { - if(!(buff[0x15]&0x80) && buff[buff[0x16]+0x17] == (i|0x20)) break; + if (size != sizeleft) { + while ((uRead = vsf.m_sub.Read(buff, 2048)) > 0) { + if (!(buff[0x15] & 0x80) && buff[buff[0x16] + 0x17] == (i | 0x20)) { + break; + } } - m_sub.Write(buff, 2048); + m_sub.Write(buff, uRead); } } @@ -276,7 +284,7 @@ bool CVobSubFile::Copy(CVobSubFile& vsf) m_sub.SetLength(m_sub.GetPosition()); - return(true); + return true; } // @@ -284,12 +292,12 @@ bool CVobSubFile::Copy(CVobSubFile& vsf) void CVobSubFile::TrimExtension(CString& fn) { int i = fn.ReverseFind('.'); - if(i > 0) - { + if (i > 0) { CString ext = fn.Mid(i).MakeLower(); - if(ext == _T(".ifo") || ext == _T(".idx") || ext == _T(".sub") - || ext == _T(".sst") || ext == _T(".son") || ext == _T(".rar")) + if (ext == _T(".ifo") || ext == _T(".idx") || ext == _T(".sub") + || ext == _T(".sst") || ext == _T(".son") || ext == _T(".rar")) { fn = fn.Left(i); + } } } @@ -297,76 +305,87 @@ bool CVobSubFile::Open(CString fn) { TrimExtension(fn); - do - { + do { Close(); int ver; - if(!ReadIdx(fn + _T(".idx"), ver)) + if (!ReadIdx(fn + _T(".idx"), ver)) { break; + } - if(ver < 6 && !ReadIfo(fn + _T(".ifo"))) + if (ver < 6 && !ReadIfo(fn + _T(".ifo"))) { break; + } - if(!ReadSub(fn + _T(".sub")) && !ReadRar(fn + _T(".rar"))) + if (!ReadSub(fn + _T(".sub")) && !ReadRar(fn + _T(".rar"))) { break; + } m_title = fn; - for(int i = 0; i < 32; i++) - { + for (size_t i = 0; i < m_langs.size(); i++) { CAtlArray& sp = m_langs[i].subpos; - for(size_t j = 0; j < sp.GetCount(); j++) - { + for (size_t j = 0; j < sp.GetCount(); j++) { sp[j].stop = sp[j].start; sp[j].fForced = false; - int packetsize = 0, datasize = 0; - BYTE* buff = GetPacket(j, packetsize, datasize, i); - if(!buff) continue; + size_t packetSize = 0, dataSize = 0; + BYTE* buff = GetPacket(j, packetSize, dataSize, i); + if (!buff) { + sp[j].fValid = false; + continue; + } - m_img.delay = j < (sp.GetCount()-1) ? sp[j+1].start - sp[j].start : 3000; - m_img.GetPacketInfo(buff, packetsize, datasize); - if(j < (sp.GetCount()-1)) m_img.delay = min(m_img.delay, sp[j+1].start - sp[j].start); + m_img.delay = j + 1 < sp.GetCount() ? sp[j + 1].start - sp[j].start : 3000; + m_img.GetPacketInfo(buff, packetSize, dataSize); + if (j + 1 < sp.GetCount()) { + m_img.delay = min(m_img.delay, sp[j + 1].start - sp[j].start); + } sp[j].stop = sp[j].start + m_img.delay; sp[j].fForced = m_img.fForced; + sp[j].fAnimated = m_img.fAnimated; - if(j > 0 && sp[j-1].stop > sp[j].start) - sp[j-1].stop = sp[j].start; + if (j > 0 && sp[j - 1].stop > sp[j].start) { + sp[j - 1].stop = sp[j].start; + } delete [] buff; } } - return(true); - } - while(false); + return true; + } while (false); Close(); - return(false); + return false; } -bool CVobSubFile::Save(CString fn, SubFormat sf) +bool CVobSubFile::Save(CString fn, int delay, SubFormat sf) { TrimExtension(fn); - CVobSubFile vsf(NULL); - if(!vsf.Copy(*this)) - return(false); + CVobSubFile vsf(nullptr); + if (!vsf.Copy(*this)) { + return false; + } - switch(sf) - { - case VobSub: return vsf.SaveVobSub(fn); break; - case WinSubMux: return vsf.SaveWinSubMux(fn); break; - case Scenarist: return vsf.SaveScenarist(fn); break; - case Maestro: return vsf.SaveMaestro(fn); break; - default: break; + switch (sf) { + case VobSub: + return vsf.SaveVobSub(fn, delay); + case WinSubMux: + return vsf.SaveWinSubMux(fn, delay); + case Scenarist: + return vsf.SaveScenarist(fn, delay); + case Maestro: + return vsf.SaveMaestro(fn, delay); + default: + break; } - return(false); + return false; } void CVobSubFile::Close() @@ -390,8 +409,9 @@ void CVobSubFile::Close() bool CVobSubFile::ReadIdx(CString fn, int& ver) { CWebTextFile f; - if(!f.Open(fn)) - return(false); + if (!f.Open(fn)) { + return false; + } bool fError = false; @@ -399,303 +419,357 @@ bool CVobSubFile::ReadIdx(CString fn, int& ver) __int64 celltimestamp = 0; CString str; - for(int line = 0; !fError && f.ReadString(str); line++) - { + for (ptrdiff_t line = 0; !fError && f.ReadString(str); line++) { str.Trim(); - if(line == 0) - { + if (line == 0) { TCHAR buff[] = _T("VobSub index file, v"); const TCHAR* s = str; int i = str.Find(buff); - if(i < 0 || _stscanf(&s[i+_tcslen(buff)], _T("%d"), &ver) != 1 - || ver > VOBSUBIDXVER) - { - TRACE(_T("[CVobSubFile::ReadIdx] Wrong file version!\n")); + if (i < 0 || _stscanf_s(&s[i + _tcslen(buff)], _T("%d"), &ver) != 1 + || ver > VOBSUBIDXVER) { + TRACE(_T("[CVobSubFile::ReadIdx] Wrong file version!\n")); fError = true; continue; } - } - else if(!str.GetLength()) - { + } else if (!str.GetLength()) { continue; - } - else if(str[0] == _T('#')) - { + } else if (str[0] == _T('#')) { TCHAR buff[] = _T("Vob/Cell ID:"); const TCHAR* s = str; int i = str.Find(buff); - if(i >= 0) - { - _stscanf(&s[i+_tcslen(buff)], _T("%d, %d (PTS: %d)"), &vobid, &cellid, &celltimestamp); + if (i >= 0) { + _stscanf_s(&s[i + _tcslen(buff)], _T("%d, %d (PTS: %I64d)"), &vobid, &cellid, &celltimestamp); } continue; } int i = str.Find(':'); - if(i <= 0) continue; + if (i <= 0) { + continue; + } CString entry = str.Left(i).MakeLower(); - str = str.Mid(i+1); + str = str.Mid(i + 1); str.Trim(); - if(str.IsEmpty()) continue; + if (str.IsEmpty()) { + continue; + } - if(entry == _T("size")) - { + if (entry == _T("size")) { int x, y; - if(_stscanf(str, _T("%dx%d"), &x, &y) != 2) fError = true; + if (_stscanf_s(str, _T("%dx%d"), &x, &y) != 2) { + fError = true; + } m_size.cx = x; m_size.cy = y; - } - else if(entry == _T("org")) - { - if(_stscanf(str, _T("%d,%d"), &m_x, &m_y) != 2) fError = true; - else m_org = CPoint(m_x, m_y); - } - else if(entry == _T("scale")) - { - if(ver < 5) - { + } else if (entry == _T("org")) { + if (_stscanf_s(str, _T("%d,%d"), &m_x, &m_y) != 2) { + fError = true; + } else { + m_org = CPoint(m_x, m_y); + } + } else if (entry == _T("scale")) { + if (ver < 5) { int scale = 100; - if(_stscanf(str, _T("%d%%"), &scale) != 1) fError = true; + if (_stscanf_s(str, _T("%d%%"), &scale) != 1) { + fError = true; + } m_scale_x = m_scale_y = scale; + } else { + if (_stscanf_s(str, _T("%d%%,%d%%"), &m_scale_x, &m_scale_y) != 2) { + fError = true; + } } - else - { - if(_stscanf(str, _T("%d%%,%d%%"), &m_scale_x, &m_scale_y) != 2) fError = true; + } else if (entry == _T("alpha")) { + if (_stscanf_s(str, _T("%d"), &m_alpha) != 1) { + fError = true; } - } - else if(entry == _T("alpha")) - { - if(_stscanf(str, _T("%d"), &m_alpha) != 1) fError = true; - } - else if(entry == _T("smooth")) - { + } else if (entry == _T("smooth")) { str.MakeLower(); - if(str.Find(_T("old")) >= 0 || str.Find(_T("2")) >= 0) m_fSmooth = 2; - else if(str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) m_fSmooth = 1; - else if(str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) m_fSmooth = 0; - else fError = true; - } - else if(entry == _T("fadein/out")) - { - if(_stscanf(str, _T("%d,%d"), &m_fadein, &m_fadeout) != 2) fError = true; - } - else if(entry == _T("align")) - { + if (str.Find(_T("old")) >= 0 || str.Find(_T("2")) >= 0) { + m_fSmooth = 2; + } else if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { + m_fSmooth = 1; + } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { + m_fSmooth = 0; + } else { + fError = true; + } + } else if (entry == _T("fadein/out")) { + if (_stscanf_s(str, _T("%d,%d"), &m_fadein, &m_fadeout) != 2) { + fError = true; + } + } else if (entry == _T("align")) { str.MakeLower(); - int i = 0, j = 0; - for(CString token = str.Tokenize(_T(" "), i); - j < 3 && !fError && !token.IsEmpty(); - token = str.Tokenize(_T(" "), i), j++) - { - if(j == 0) - { - if(token == _T("on") || token == _T("1")) m_fAlign = true; - else if(token == _T("off") || token == _T("0")) m_fAlign = false; - else fError = true; - } - else if(j == 1) - { - if(token == _T("at")) {j--; continue;} - - if(token == _T("left")) m_alignhor = 0; - else if(token == _T("center")) m_alignhor = 1; - else if(token == _T("right")) m_alignhor = 2; - else fError = true; + int k = 0; + CString token; + for (int j = 0; j < 3; j++) { + token = str.Tokenize(_T(" "), k); + if (token.IsEmpty()) { + break; } - else if(j == 2) - { - if(token == _T("top")) m_alignver = 0; - else if(token == _T("center")) m_alignver = 1; - else if(token == _T("bottom")) m_alignver = 2; - else fError = true; + + if (j == 0) { + if (token == _T("on") || token == _T("1")) { + m_fAlign = true; + } else if (token == _T("off") || token == _T("0")) { + m_fAlign = false; + } else { + fError = true; + break; + } + } else if (j == 1) { + if (token == _T("at")) { + j--; + continue; + } + + if (token == _T("left")) { + m_alignhor = 0; + } else if (token == _T("center")) { + m_alignhor = 1; + } else if (token == _T("right")) { + m_alignhor = 2; + } else { + fError = true; + break; + } + } else if (j == 2) { + if (token == _T("top")) { + m_alignver = 0; + } else if (token == _T("center")) { + m_alignver = 1; + } else if (token == _T("bottom")) { + m_alignver = 2; + } else { + fError = true; + break; + } } } - } - else if(entry == _T("time offset")) - { + } else if (entry == _T("time offset")) { bool fNegative = false; - if(str[0] == '-') fNegative = true; + if (str[0] == '-') { + fNegative = true; + } str.TrimLeft(_T("+-")); TCHAR c; int hh, mm, ss, ms; int n = _stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms); - m_toff = n == 1 - ? hh * (fNegative ? -1 : 1) - : n == 4+3 - ? (hh*60*60*1000 + mm*60*1000 + ss*1000 + ms) * (fNegative ? -1 : 1) - : fError = true, 0; - } - else if(entry == _T("forced subs")) - { + switch (n) { + case 1: // We have read only one integer, interpret it as an offset expressed in milliseconds + m_toff = hh * (fNegative ? -1 : 1); + break; + case 7: // We have read 4 integers + 3 separators, interpret them as hh:mm:ss.ms + m_toff = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (fNegative ? -1 : 1); + break; + default: + fError = true; + m_toff = 0; + break; + } + } else if (entry == _T("forced subs")) { str.MakeLower(); - if(str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) m_fOnlyShowForcedSubs = true; - else if(str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) m_fOnlyShowForcedSubs = false; - else fError = true; - } - else if(entry == _T("langidx")) - { - if(_stscanf(str, _T("%d"), &m_iLang) != 1) fError = true; - } - else if(entry == _T("palette")) - { - if(_stscanf(str, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"), - &m_orgpal[0], &m_orgpal[1], &m_orgpal[2], &m_orgpal[3], - &m_orgpal[4], &m_orgpal[5], &m_orgpal[6], &m_orgpal[7], - &m_orgpal[8], &m_orgpal[9], &m_orgpal[10], &m_orgpal[11], - &m_orgpal[12], &m_orgpal[13], &m_orgpal[14], &m_orgpal[15] - ) != 16) fError = true; - } - else if(entry == _T("custom colors")) - { + if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { + m_fOnlyShowForcedSubs = true; + } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { + m_fOnlyShowForcedSubs = false; + } else { + fError = true; + } + } else if (entry == _T("langidx")) { + int iLang = -1; + if (_stscanf_s(str, _T("%d"), &iLang) != 1) { + fError = true; + } + m_iLang = (iLang < 0 && size_t(iLang) >= m_langs.size()) ? -1 : size_t(iLang); + } else if (entry == _T("palette")) { + if (_stscanf_s(str, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"), + &m_orgpal[0], &m_orgpal[1], &m_orgpal[2], &m_orgpal[3], + &m_orgpal[4], &m_orgpal[5], &m_orgpal[6], &m_orgpal[7], + &m_orgpal[8], &m_orgpal[9], &m_orgpal[10], &m_orgpal[11], + &m_orgpal[12], &m_orgpal[13], &m_orgpal[14], &m_orgpal[15] + ) != 16) { + fError = true; + } + } else if (entry == _T("custom colors")) { str.MakeLower(); - if(str.Find(_T("on")) == 0 || str.Find(_T("1")) == 0) m_fCustomPal = true; - else if(str.Find(_T("off")) == 0 || str.Find(_T("0")) == 0) m_fCustomPal = false; - else fError = true; + if (str.Find(_T("on")) == 0 || str.Find(_T("1")) == 0) { + m_fCustomPal = true; + } else if (str.Find(_T("off")) == 0 || str.Find(_T("0")) == 0) { + m_fCustomPal = false; + } else { + fError = true; + } i = str.Find(_T("tridx:")); - if(i < 0) {fError = true; continue;} + if (i < 0) { + fError = true; + continue; + } str = str.Mid(i + (int)_tcslen(_T("tridx:"))); int tridx; - if(_stscanf(str, _T("%x"), &tridx) != 1) {fError = true; continue;} - tridx = ((tridx&0x1000)>>12) | ((tridx&0x100)>>7) | ((tridx&0x10)>>2) | ((tridx&1)<<3); + if (_stscanf_s(str, _T("%x"), &tridx) != 1) { + fError = true; + continue; + } + tridx = ((tridx & 0x1000) >> 12) | ((tridx & 0x100) >> 7) | ((tridx & 0x10) >> 2) | ((tridx & 1) << 3); i = str.Find(_T("colors:")); - if(i < 0) {fError = true; continue;} + if (i < 0) { + fError = true; + continue; + } str = str.Mid(i + (int)_tcslen(_T("colors:"))); RGBQUAD pal[4]; - if(_stscanf(str, _T("%x,%x,%x,%x"), &pal[0], &pal[1], &pal[2], &pal[3]) != 4) {fError = true; continue;} + if (_stscanf_s(str, _T("%x,%x,%x,%x"), &pal[0], &pal[1], &pal[2], &pal[3]) != 4) { + fError = true; + continue; + } SetCustomPal(pal, tridx); - } - else if(entry == _T("id")) - { + } else if (entry == _T("id")) { str.MakeLower(); - int langid = ((str[0]&0xff)<<8)|(str[1]&0xff); + WORD langid = ((str[0] & 0xff) << 8) | (str[1] & 0xff); i = str.Find(_T("index:")); - if(i < 0) {fError = true; continue;} + if (i < 0) { + fError = true; + continue; + } str = str.Mid(i + (int)_tcslen(_T("index:"))); - if(_stscanf(str, _T("%d"), &id) != 1 || id < 0 || id >= 32) {fError = true; continue;} + if (_stscanf_s(str, _T("%d"), &id) != 1 || id < 0 || size_t(id) >= m_langs.size()) { + fError = true; + continue; + } + if (m_iLang == -1) { + m_iLang = size_t(id); + } m_langs[id].id = langid; m_langs[id].name = lang_tbl[find_lang(langid)].lang_long; m_langs[id].alt = lang_tbl[find_lang(langid)].lang_long; delay = 0; - } - else if(id >= 0 && entry == _T("alt")) - { + } else if (id >= 0 && entry == _T("alt")) { m_langs[id].alt = str; - } - else if(id >= 0 && entry == _T("delay")) - { + } else if (id >= 0 && entry == _T("delay")) { bool fNegative = false; - if(str[0] == '-') fNegative = true; + if (str[0] == '-') { + fNegative = true; + } str.TrimLeft(_T("+-")); TCHAR c; int hh, mm, ss, ms; if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { - fError = true; continue; + fError = true; + continue; } - delay += (hh*60*60*1000 + mm*60*1000 + ss*1000 + ms) * (fNegative ? -1 : 1); - } - else if(id >= 0 && entry == _T("timestamp")) - { + delay += (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (fNegative ? -1 : 1); + } else if (id >= 0 && entry == _T("timestamp")) { SubPos sb; - sb.vobid = vobid; - sb.cellid = cellid; + sb.vobid = (char)vobid; + sb.cellid = (char)cellid; sb.celltimestamp = celltimestamp; sb.fValid = true; bool fNegative = false; - if(str[0] == '-') fNegative = true; + if (str[0] == '-') { + fNegative = true; + } str.TrimLeft(_T("+-")); TCHAR c; int hh, mm, ss, ms; if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { - fError = true; continue; + fError = true; + continue; } - sb.start = (hh*60*60*1000 + mm*60*1000 + ss*1000 + ms) * (fNegative ? -1 : 1) + delay; + sb.start = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (fNegative ? -1 : 1) + delay; i = str.Find(_T("filepos:")); - if(i < 0) {fError = true; continue;} + if (i < 0) { + fError = true; + continue; + } str = str.Mid(i + (int)_tcslen(_T("filepos:"))); - if(_stscanf(str, _T("%I64x"), &sb.filepos) != 1) {fError = true; continue;} + if (_stscanf_s(str, _T("%I64x"), &sb.filepos) != 1) { + fError = true; + continue; + } - if(delay < 0 && m_langs[id].subpos.GetCount() > 0) - { - __int64 ts = m_langs[id].subpos[m_langs[id].subpos.GetCount()-1].start; + if (delay < 0 && !m_langs[id].subpos.IsEmpty()) { + __int64 ts = m_langs[id].subpos[m_langs[id].subpos.GetCount() - 1].start; - if(sb.start < ts) - { + if (sb.start < ts) { delay += (int)(ts - sb.start); sb.start = ts; } } m_langs[id].subpos.Add(sb); + } else { + fError = true; } - else fError = true; } - return(!fError); + return !fError; } bool CVobSubFile::ReadSub(CString fn) { CFile f; - if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite)) - return(false); + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } m_sub.SetLength(f.GetLength()); m_sub.SeekToBegin(); int len; BYTE buff[2048]; - while((len = f.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) + while ((len = f.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { m_sub.Write(buff, len); + } - return(true); + return true; } -static unsigned char* RARbuff = NULL; +static unsigned char* RARbuff = nullptr; static unsigned int RARpos = 0; static int CALLBACK MyCallbackProc(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2) { - if(msg == UCM_PROCESSDATA) - { + if (msg == UCM_PROCESSDATA) { ASSERT(RARbuff); memcpy(&RARbuff[RARpos], (char*)P1, (size_t)P2); RARpos += (unsigned int)P2; } - return(1); + return 1; } bool CVobSubFile::ReadRar(CString fn) @@ -714,10 +788,9 @@ bool CVobSubFile::ReadRar(CString fn) RARProcessFile ProcessFile = (RARProcessFile)GetProcAddress(h, "RARProcessFile"); RARSetCallback SetCallback = (RARSetCallback)GetProcAddress(h, "RARSetCallback"); - if(!(OpenArchiveEx && CloseArchive && ReadHeaderEx && ProcessFile && SetCallback)) - { + if (!(OpenArchiveEx && CloseArchive && ReadHeaderEx && ProcessFile && SetCallback)) { FreeLibrary(h); - return(false); + return false; } #else @@ -735,52 +808,47 @@ bool CVobSubFile::ReadRar(CString fn) OpenArchiveData.ArcNameW = (LPTSTR)(LPCTSTR)fn; char fnA[MAX_PATH]; size_t size; - if(wcstombs_s(&size, fnA, fn, fn.GetLength())) + if (wcstombs_s(&size, fnA, fn, fn.GetLength())) { fnA[0] = 0; - + } OpenArchiveData.ArcName = fnA; OpenArchiveData.OpenMode = RAR_OM_EXTRACT; OpenArchiveData.CmtBuf = 0; OpenArchiveData.Callback = MyCallbackProc; HANDLE hArcData = OpenArchiveEx(&OpenArchiveData); - if(!hArcData) - { + if (!hArcData) { #ifndef USE_UNRAR_STATIC FreeLibrary(h); #endif - return(false); + return false; } RARHeaderDataEx HeaderDataEx; - HeaderDataEx.CmtBuf = NULL; + HeaderDataEx.CmtBuf = nullptr; - while(ReadHeaderEx(hArcData, &HeaderDataEx) == 0) - { + while (ReadHeaderEx(hArcData, &HeaderDataEx) == 0) { CString subfn(HeaderDataEx.FileNameW); - if(!subfn.Right(4).CompareNoCase(_T(".sub"))) - { + if (!subfn.Right(4).CompareNoCase(_T(".sub"))) { CAutoVectorPtr buff; - if(!buff.Allocate(HeaderDataEx.UnpSize)) - { + if (!buff.Allocate(HeaderDataEx.UnpSize)) { CloseArchive(hArcData); #ifndef USE_UNRAR_STATIC FreeLibrary(h); #endif - return(false); + return false; } RARbuff = buff; RARpos = 0; - if(ProcessFile(hArcData, RAR_TEST, NULL, NULL)) - { + if (ProcessFile(hArcData, RAR_TEST, nullptr, nullptr)) { CloseArchive(hArcData); #ifndef USE_UNRAR_STATIC FreeLibrary(h); #endif - return(false); + return false; } m_sub.SetLength(HeaderDataEx.UnpSize); @@ -788,13 +856,13 @@ bool CVobSubFile::ReadRar(CString fn) m_sub.Write(buff, HeaderDataEx.UnpSize); m_sub.SeekToBegin(); - RARbuff = NULL; + RARbuff = nullptr; RARpos = 0; break; } - ProcessFile(hArcData, RAR_SKIP, NULL, NULL); + ProcessFile(hArcData, RAR_SKIP, nullptr, nullptr); } CloseArchive(hArcData); @@ -802,39 +870,33 @@ bool CVobSubFile::ReadRar(CString fn) FreeLibrary(h); #endif - return(true); + return true; } -#define ReadBEdw(var) \ - f.Read(&((BYTE*)&var)[3], 1); \ - f.Read(&((BYTE*)&var)[2], 1); \ - f.Read(&((BYTE*)&var)[1], 1); \ - f.Read(&((BYTE*)&var)[0], 1); \ - bool CVobSubFile::ReadIfo(CString fn) { CFile f; - if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite)) - return(false); + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } /* PGC1 */ - f.Seek(0xc0+0x0c, SEEK_SET); + f.Seek(0xc0 + 0x0c, SEEK_SET); DWORD pos; ReadBEdw(pos); - f.Seek(pos*0x800 + 0x0c, CFile::begin); + f.Seek(pos * 0x800 + 0x0c, CFile::begin); DWORD offset; ReadBEdw(offset); /* Subpic palette */ - f.Seek(pos*0x800 + offset + 0xa4, CFile::begin); + f.Seek(pos * 0x800 + offset + 0xa4, CFile::begin); - for(int i = 0; i < 16; i++) - { + for (size_t i = 0; i < 16; i++) { BYTE y, u, v, tmp; f.Read(&tmp, 1); @@ -842,21 +904,22 @@ bool CVobSubFile::ReadIfo(CString fn) f.Read(&u, 1); f.Read(&v, 1); - y = (y-16)*255/219; + y = (y - 16) * 255 / 219; m_orgpal[i].rgbRed = (BYTE)min(max(1.0*y + 1.4022*(u-128), 0), 255); m_orgpal[i].rgbGreen = (BYTE)min(max(1.0*y - 0.3456*(u-128) - 0.7145*(v-128), 0), 255); m_orgpal[i].rgbBlue = (BYTE)min(max(1.0*y + 1.7710*(v-128), 0) , 255); } - return(true); + return true; } -bool CVobSubFile::WriteIdx(CString fn) +bool CVobSubFile::WriteIdx(CString fn, int delay) { CTextFile f; - if(!f.Save(fn, CTextFile::DEFAULT_ENCODING)) - return(false); + if (!f.Save(fn, CTextFile::DEFAULT_ENCODING)) { + return false; + } CString str; str.Format(_T("# VobSub index file, v%d (do not modify this line!)\n"), VOBSUBIDXVER); @@ -875,7 +938,7 @@ bool CVobSubFile::WriteIdx(CString fn) f.WriteString(_T("#\t ms: milliseconds (0 <= ms <= 999)\n")); f.WriteString(_T("# \n")); f.WriteString(_T("#\t Note: You can't position a sub before the previous with a negative value.\n")); - f.WriteString(_T("# \n")); + f.WriteString(_T("# \n")); f.WriteString(_T("# You can also modify timestamps or delete a few subs you don't like.\n")); f.WriteString(_T("# Just make sure they stay in increasing order.\n")); f.WriteString(_T("\n")); @@ -886,7 +949,7 @@ bool CVobSubFile::WriteIdx(CString fn) f.WriteString(_T("# Settings\n\n")); f.WriteString(_T("# Original frame size\n")); - str.Format(_T("size: %dx%d\n\n"), m_size.cx, m_size.cy); + str.Format(_T("size: %ldx%ld\n\n"), m_size.cx, m_size.cy); f.WriteString(str); f.WriteString(_T("# Origin, relative to the upper-left corner, can be overloaded by aligment\n")); @@ -910,15 +973,15 @@ bool CVobSubFile::WriteIdx(CString fn) f.WriteString(str); f.WriteString(_T("# Force subtitle placement relative to (org.x, org.y)\n")); - str.Format(_T("align: %s %s %s\n\n"), - m_fAlign ? _T("ON at") : _T("OFF at"), - m_alignhor == 0 ? _T("LEFT") : m_alignhor == 1 ? _T("CENTER") : m_alignhor == 2 ? _T("RIGHT") : _T(""), - m_alignver == 0 ? _T("TOP") : m_alignver == 1 ? _T("CENTER") : m_alignver == 2 ? _T("BOTTOM") : _T("")); + str.Format(_T("align: %s %s %s\n\n"), + m_fAlign ? _T("ON at") : _T("OFF at"), + m_alignhor == 0 ? _T("LEFT") : m_alignhor == 1 ? _T("CENTER") : m_alignhor == 2 ? _T("RIGHT") : _T(""), + m_alignver == 0 ? _T("TOP") : m_alignver == 1 ? _T("CENTER") : m_alignver == 2 ? _T("BOTTOM") : _T("")); f.WriteString(str); f.WriteString(_T("# For correcting non-progressive desync. (in millisecs or hh:mm:ss:ms)\n")); f.WriteString(_T("# Note: Not effective in DirectVobSub, use \"delay: ... \" instead.\n")); - str.Format(_T("time offset: %d\n\n"), m_toff); + str.Format(_T("time offset: %u\n\n"), m_toff); f.WriteString(str); f.WriteString(_T("# ON: displays only forced subtitles, OFF: shows everything\n")); @@ -926,240 +989,299 @@ bool CVobSubFile::WriteIdx(CString fn) f.WriteString(str); f.WriteString(_T("# The original palette of the DVD\n")); - str.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n\n"), - *((unsigned int*)&m_orgpal[0])&0xffffff, - *((unsigned int*)&m_orgpal[1])&0xffffff, - *((unsigned int*)&m_orgpal[2])&0xffffff, - *((unsigned int*)&m_orgpal[3])&0xffffff, - *((unsigned int*)&m_orgpal[4])&0xffffff, - *((unsigned int*)&m_orgpal[5])&0xffffff, - *((unsigned int*)&m_orgpal[6])&0xffffff, - *((unsigned int*)&m_orgpal[7])&0xffffff, - *((unsigned int*)&m_orgpal[8])&0xffffff, - *((unsigned int*)&m_orgpal[9])&0xffffff, - *((unsigned int*)&m_orgpal[10])&0xffffff, - *((unsigned int*)&m_orgpal[11])&0xffffff, - *((unsigned int*)&m_orgpal[12])&0xffffff, - *((unsigned int*)&m_orgpal[13])&0xffffff, - *((unsigned int*)&m_orgpal[14])&0xffffff, - *((unsigned int*)&m_orgpal[15])&0xffffff); + str.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n\n"), + *((unsigned int*)&m_orgpal[0]) & 0xffffff, + *((unsigned int*)&m_orgpal[1]) & 0xffffff, + *((unsigned int*)&m_orgpal[2]) & 0xffffff, + *((unsigned int*)&m_orgpal[3]) & 0xffffff, + *((unsigned int*)&m_orgpal[4]) & 0xffffff, + *((unsigned int*)&m_orgpal[5]) & 0xffffff, + *((unsigned int*)&m_orgpal[6]) & 0xffffff, + *((unsigned int*)&m_orgpal[7]) & 0xffffff, + *((unsigned int*)&m_orgpal[8]) & 0xffffff, + *((unsigned int*)&m_orgpal[9]) & 0xffffff, + *((unsigned int*)&m_orgpal[10]) & 0xffffff, + *((unsigned int*)&m_orgpal[11]) & 0xffffff, + *((unsigned int*)&m_orgpal[12]) & 0xffffff, + *((unsigned int*)&m_orgpal[13]) & 0xffffff, + *((unsigned int*)&m_orgpal[14]) & 0xffffff, + *((unsigned int*)&m_orgpal[15]) & 0xffffff); f.WriteString(str); - int tridx = (!!(m_tridx&1))*0x1000 + (!!(m_tridx&2))*0x100 + (!!(m_tridx&4))*0x10 + (!!(m_tridx&8)); + int tridx = (!!(m_tridx & 1)) * 0x1000 + (!!(m_tridx & 2)) * 0x100 + (!!(m_tridx & 4)) * 0x10 + (!!(m_tridx & 8)); f.WriteString(_T("# Custom colors (transp idxs and the four colors)\n")); - str.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06x\n\n"), - m_fCustomPal ? _T("ON") : _T("OFF"), - tridx, - *((unsigned int*)&m_cuspal[0])&0xffffff, - *((unsigned int*)&m_cuspal[1])&0xffffff, - *((unsigned int*)&m_cuspal[2])&0xffffff, - *((unsigned int*)&m_cuspal[3])&0xffffff); + str.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06x\n\n"), + m_fCustomPal ? _T("ON") : _T("OFF"), + tridx, + *((unsigned int*)&m_cuspal[0]) & 0xffffff, + *((unsigned int*)&m_cuspal[1]) & 0xffffff, + *((unsigned int*)&m_cuspal[2]) & 0xffffff, + *((unsigned int*)&m_cuspal[3]) & 0xffffff); f.WriteString(str); f.WriteString(_T("# Language index in use\n")); - str.Format(_T("langidx: %d\n\n"), m_iLang); + str.Format(_T("langidx: %Iu\n\n"), m_iLang); f.WriteString(str); + if (delay) { + str.Format(_T("delay: %s%02d:%02d:%02d:%03d\n\n"), + delay < 0 ? _T("-") : _T(""), + abs(delay / 1000 / 60 / 60) % 60, + abs(delay / 1000 / 60) % 60, + abs(delay / 1000) % 60, + abs(delay % 1000)); + f.WriteString(str); + } + // Subs - for(int i = 0; i < 32; i++) - { + for (size_t i = 0; i < m_langs.size(); i++) { SubLang& sl = m_langs[i]; CAtlArray& sp = sl.subpos; - if(sp.IsEmpty() && !sl.id) continue; + if (sp.IsEmpty() && !sl.id) { + continue; + } str.Format(_T("# %s\n"), sl.name); f.WriteString(str); ASSERT(sl.id); - if(!sl.id) sl.id = '--'; - str.Format(_T("id: %c%c, index: %d\n"), sl.id>>8, sl.id&0xff, i); + if (!sl.id) { + sl.id = '--'; + } + str.Format(_T("id: %c%c, index: %Iu\n"), sl.id >> 8, sl.id & 0xff, i); f.WriteString(str); - str.Format(_T("# Decomment next line to activate alternative name in DirectVobSub / Windows Media Player 6.x\n")); + str = _T("# Uncomment next line to activate alternative name in DirectVobSub / Windows Media Player 6.x\n"); f.WriteString(str); str.Format(_T("alt: %s\n"), sl.alt); - if(sl.name == sl.alt) str = _T("# ") + str; + if (sl.name == sl.alt) { + str = _T("# ") + str; + } f.WriteString(str); char vobid = -1, cellid = -1; - for(size_t j = 0; j < sp.GetCount(); j++) - { - if(!sp[j].fValid) continue; + for (size_t j = 0; j < sp.GetCount(); j++) { + if (!sp[j].fValid) { + continue; + } - if(sp[j].vobid != vobid || sp[j].cellid != cellid) - { - str.Format(_T("# Vob/Cell ID: %d, %d (PTS: %d)\n"), sp[j].vobid, sp[j].cellid, sp[j].celltimestamp); + if (sp[j].vobid != vobid || sp[j].cellid != cellid) { + str.Format(_T("# Vob/Cell ID: %d, %d (PTS: %I64d)\n"), sp[j].vobid, sp[j].cellid, sp[j].celltimestamp); f.WriteString(str); vobid = sp[j].vobid; cellid = sp[j].cellid; } - str.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64x\n"), - sp[j].start < 0 ? _T("-") : _T(""), - abs(int((sp[j].start/1000/60/60)%60)), - abs(int((sp[j].start/1000/60)%60)), - abs(int((sp[j].start/1000)%60)), - abs(int((sp[j].start)%1000)), - sp[j].filepos); + str.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64x\n"), + sp[j].start < 0 ? _T("-") : _T(""), + abs(int((sp[j].start / 1000 / 60 / 60) % 60)), + abs(int((sp[j].start / 1000 / 60) % 60)), + abs(int((sp[j].start / 1000) % 60)), + abs(int((sp[j].start) % 1000)), + sp[j].filepos); f.WriteString(str); } f.WriteString(_T("\n")); } - return(true); + return true; } bool CVobSubFile::WriteSub(CString fn) { CFile f; - if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite)) - return(false); + if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + return false; + } - if(m_sub.GetLength() == 0) - return(true); // nothing to do... + if (m_sub.GetLength() == 0) { + return true; // nothing to do... + } m_sub.SeekToBegin(); int len; BYTE buff[2048]; - while((len = m_sub.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) + while ((len = m_sub.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { f.Write(buff, len); + } - return(true); + return true; } // -BYTE* CVobSubFile::GetPacket(int idx, int& packetsize, int& datasize, int iLang) +BYTE* CVobSubFile::GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t iLang /*= SIZE_T_ERROR*/) { - BYTE* ret = NULL; + BYTE* ret = nullptr; - if(iLang < 0 || iLang >= 32) iLang = m_iLang; + if (iLang >= m_langs.size()) { + iLang = m_iLang; + } CAtlArray& sp = m_langs[iLang].subpos; - do - { - if(idx < 0 || (size_t)idx >= sp.GetCount()) + do { + if (idx >= sp.GetCount()) { break; + } - if(m_sub.Seek(sp[idx].filepos, CFile::begin) != sp[idx].filepos) + if ((__int64)m_sub.Seek(sp[idx].filepos, CFile::begin) != sp[idx].filepos) { break; + } BYTE buff[0x800]; - if(sizeof(buff) != m_sub.Read(buff, sizeof(buff))) + if (sizeof(buff) != m_sub.Read(buff, sizeof(buff))) { break; + } - BYTE offset = buff[0x16]; + ASSERT(iLang < BYTE_MAX); // let's check a few things to make sure... - if(*(DWORD*)&buff[0x00] != 0xba010000 - || *(DWORD*)&buff[0x0e] != 0xbd010000 - || !(buff[0x15] & 0x80) - || (buff[0x17] & 0xf0) != 0x20 - || (buff[buff[0x16] + 0x17] & 0xe0) != 0x20 - || (buff[buff[0x16] + 0x17] & 0x1f) != iLang) + if (*(DWORD*)&buff[0x00] != 0xba010000 + || *(DWORD*)&buff[0x0e] != 0xbd010000 + || !(buff[0x15] & 0x80) + || (buff[0x17] & 0xf0) != 0x20 + || (buff[buff[0x16] + 0x17] & 0xe0) != 0x20 + || (buff[buff[0x16] + 0x17] & 0x1f) != (BYTE)iLang) { break; + } - packetsize = (buff[buff[0x16] + 0x18] << 8) + buff[buff[0x16] + 0x19]; - datasize = (buff[buff[0x16] + 0x1a] << 8) + buff[buff[0x16] + 0x1b]; + packetSize = (buff[buff[0x16] + 0x18] << 8) + buff[buff[0x16] + 0x19]; + dataSize = (buff[buff[0x16] + 0x1a] << 8) + buff[buff[0x16] + 0x1b]; - ret = new BYTE[packetsize]; - if(!ret) break; + try { + ret = DEBUG_NEW BYTE[packetSize]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + break; + } - int i = 0, sizeleft = packetsize; - for(int size; - i < packetsize; - i += size, sizeleft -= size) - { - int hsize = 0x18 + buff[0x16]; - size = min(sizeleft, 0x800 - hsize); + size_t i = 0, sizeLeft = packetSize; + for (size_t size; i < packetSize; i += size, sizeLeft -= size) { + size_t hsize = 0x18 + buff[0x16]; + size = min(sizeLeft, 0x800 - hsize); memcpy(&ret[i], &buff[hsize], size); - if(size != sizeleft) - { - while(m_sub.Read(buff, sizeof(buff))) - { - if(/*!(buff[0x15] & 0x80) &&*/ buff[buff[0x16] + 0x17] == (iLang|0x20)) + if (size != sizeLeft) { + while (m_sub.Read(buff, sizeof(buff))) { + if (/*!(buff[0x15] & 0x80) &&*/ buff[buff[0x16] + 0x17] == (iLang | 0x20)) { break; + } } } } - if(i != packetsize || sizeleft > 0) - delete [] ret, ret = NULL; + if (i != packetSize || sizeLeft > 0) { + delete [] ret; + ret = nullptr; + } + } while (false); + + return ret; +} + +const CVobSubFile::SubPos* CVobSubFile::GetFrameInfo(size_t idx, size_t iLang /*= SIZE_T_ERROR*/) const +{ + if (iLang >= m_langs.size()) { + iLang = m_iLang; } - while(false); + const CAtlArray& sp = m_langs[iLang].subpos; - return(ret); + if (idx >= sp.GetCount() + || !sp[idx].fValid + || (m_fOnlyShowForcedSubs && !sp[idx].fForced)) { + return nullptr; + } + + return &sp[idx]; } -bool CVobSubFile::GetFrame(int idx, int iLang) +bool CVobSubFile::GetFrame(size_t idx, size_t iLang /*= SIZE_T_ERROR*/, REFERENCE_TIME rt /*= -1*/) { - if(iLang < 0 || iLang >= 32) iLang = m_iLang; + if (iLang >= m_langs.size()) { + iLang = m_iLang; + } CAtlArray& sp = m_langs[iLang].subpos; - if(idx < 0 || (size_t)idx >= sp.GetCount()) - return(false); + if (idx >= sp.GetCount()) { + return false; + } - if(m_img.iLang != iLang || m_img.iIdx != idx) - { - int packetsize = 0, datasize = 0; + if (m_img.iLang != iLang || m_img.iIdx != idx + || (sp[idx].fAnimated && sp[idx].start + m_img.tCurrent <= rt)) { + size_t packetSize = 0, dataSize = 0; CAutoVectorPtr buff; - buff.Attach(GetPacket(idx, packetsize, datasize, iLang)); - if(!buff || packetsize <= 0 || datasize <= 0) return(false); + buff.Attach(GetPacket(idx, packetSize, dataSize, iLang)); + if (!buff || packetSize == 0 || dataSize == 0) { + return false; + } m_img.start = sp[idx].start; - m_img.delay = (size_t)idx < (sp.GetCount()-1) - ? sp[idx+1].start - sp[idx].start - : 3000; - bool ret = m_img.Decode(buff, packetsize, datasize, m_fCustomPal, m_tridx, m_orgpal, m_cuspal, true); + bool ret = m_img.Decode(buff, packetSize, dataSize, rt >= 0 ? int(rt - sp[idx].start) : INT_MAX, + m_fCustomPal, m_tridx, m_orgpal, m_cuspal, true); - if((size_t)idx < (sp.GetCount()-1)) - m_img.delay = min(m_img.delay, sp[idx+1].start - m_img.start); + m_img.delay = sp[idx].stop - sp[idx].start; - if(!ret) return(false); + if (!ret) { + return false; + } m_img.iIdx = idx; m_img.iLang = iLang; } - return(m_fOnlyShowForcedSubs ? m_img.fForced : true); + return (m_fOnlyShowForcedSubs ? m_img.fForced : true); } bool CVobSubFile::GetFrameByTimeStamp(__int64 time) { - return(GetFrame(GetFrameIdxByTimeStamp(time))); + return GetFrame(GetFrameIdxByTimeStamp(time)); } -int CVobSubFile::GetFrameIdxByTimeStamp(__int64 time) +size_t CVobSubFile::GetFrameIdxByTimeStamp(__int64 time) { - if(m_iLang < 0 || m_iLang >= 32) - return(-1); + if (m_iLang >= m_langs.size() || m_langs[m_iLang].subpos.IsEmpty()) { + return -1; + } CAtlArray& sp = m_langs[m_iLang].subpos; - int i = 0, j = (int)sp.GetCount() - 1, ret = -1; + size_t i = 0, j = sp.GetCount() - 1, ret = -1; - if(j >= 0 && time >= sp[j].start) - return(j); + if (time >= sp[j].start) { + return j; + } - while(i < j) - { - int mid = (i + j) >> 1; - int midstart = (int)sp[mid].start; + while (i < j) { + size_t mid = (i + j) >> 1; + __int64 midstart = sp[mid].start; - if(time == midstart) {ret = mid; break;} - else if(time < midstart) {ret = -1; if(j == mid) mid--; j = mid;} - else if(time > midstart) {ret = mid; if(i == mid) mid++; i = mid;} + if (time == midstart) { + ret = mid; + break; + } else if (time < midstart) { + ret = -1; + if (j == mid) { + mid--; + } + j = mid; + } else if (time > midstart) { + ret = mid; + if (i == mid) { + mid++; + } + i = mid; + } } - return(ret); + return ret; } // @@ -1167,9 +1289,9 @@ int CVobSubFile::GetFrameIdxByTimeStamp(__int64 time) STDMETHODIMP CVobSubFile::NonDelegatingQueryInterface(REFIID riid, void** ppv) { CheckPointer(ppv, E_POINTER); - *ppv = NULL; + *ppv = nullptr; - return + return QI(IPersist) QI(ISubStream) QI(ISubPicProvider) @@ -1178,60 +1300,68 @@ STDMETHODIMP CVobSubFile::NonDelegatingQueryInterface(REFIID riid, void** ppv) // ISubPicProvider -// TODO: return segments for the fade-in/out time (with animated set to "true" of course) - STDMETHODIMP_(POSITION) CVobSubFile::GetStartPosition(REFERENCE_TIME rt, double fps) { rt /= 10000; - int i = GetFrameIdxByTimeStamp(rt); + size_t i = GetFrameIdxByTimeStamp(rt); - if(!GetFrame(i)) - return(NULL); + const SubPos* sp = GetFrameInfo(i); + if (!sp) { + return nullptr; + } - if(rt >= (m_img.start + m_img.delay)) - { - if(!GetFrame(++i)) - return(NULL); + if (rt >= sp->stop) { + if (!GetFrameInfo(++i)) { + return nullptr; + } } - return((POSITION)(i+1)); + return (POSITION)(i + 1); } STDMETHODIMP_(POSITION) CVobSubFile::GetNext(POSITION pos) { - int i = (int)pos; - return(GetFrame(i) ? (POSITION)(i+1) : NULL); + size_t i = (size_t)pos; + return (GetFrameInfo(i) ? (POSITION)(i + 1) : nullptr); } STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStart(POSITION pos, double fps) { - int i = (int)pos-1; - return(GetFrame(i) ? 10000i64*m_img.start : 0); + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? 10000i64 * sp->start : 0); } STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStop(POSITION pos, double fps) { - int i = (int)pos-1; - return(GetFrame(i) ? 10000i64*(m_img.start + m_img.delay) : 0); + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? 10000i64 * sp->stop : 0); } STDMETHODIMP_(bool) CVobSubFile::IsAnimated(POSITION pos) { - return(false); + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? sp->fAnimated : false); } STDMETHODIMP CVobSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) { - if(spd.bpp != 32) return E_INVALIDARG; + if (spd.bpp != 32) { + return E_INVALIDARG; + } rt /= 10000; - if(!GetFrame(GetFrameIdxByTimeStamp(rt))) + if (!GetFrame(GetFrameIdxByTimeStamp(rt), -1, rt)) { return E_FAIL; + } - if(rt >= (m_img.start + m_img.delay)) + if (rt >= (m_img.start + m_img.delay)) { return E_FAIL; + } return __super::Render(spd, bbox); } @@ -1248,9 +1378,12 @@ STDMETHODIMP CVobSubFile::GetClassID(CLSID* pClassID) STDMETHODIMP_(int) CVobSubFile::GetStreamCount() { int iStreamCount = 0; - for(int i = 0; i < 32; i++) - if(m_langs[i].subpos.GetCount()) iStreamCount++; - return(iStreamCount); + for(int i = 0; i < 32; i++) { + if(m_langs[i].subpos.GetCount()) { + iStreamCount++; + } + } + return iStreamCount; } STDMETHODIMP CVobSubFile::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID) @@ -1259,20 +1392,20 @@ STDMETHODIMP CVobSubFile::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID { SubLang& sl = m_langs[i]; - if(sl.subpos.IsEmpty() || iStream-- > 0) + if (sl.subpos.IsEmpty() || iStream-- > 0) { continue; + } - if(ppName) - { - *ppName = (WCHAR*)CoTaskMemAlloc((sl.alt.GetLength()+1)*sizeof(WCHAR)); - if(!(*ppName)) + if (ppName) { + *ppName = (WCHAR*)CoTaskMemAlloc((sl.alt.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppName)) { return E_OUTOFMEMORY; + } - wcscpy(*ppName, CStringW(sl.alt)); + wcscpy_s(*ppName, sl.alt.GetLength() + 1, CStringW(sl.alt)); } - if(pLCID) - { + if (pLCID) { *pLCID = 0; // TODO: make lcid out of "sl.id" } @@ -1286,20 +1419,25 @@ STDMETHODIMP_(int) CVobSubFile::GetStream() { int iStream = 0; - for(int i = 0; i < m_iLang; i++) - if(!m_langs[i].subpos.IsEmpty()) iStream++; + if (m_iLang < m_langs.size()) { + for (size_t i = 0; i < m_iLang; i++) { + if (!m_langs[i].subpos.IsEmpty()) { + iStream++; + } + } + } - return(iStream); + return iStream; } STDMETHODIMP CVobSubFile::SetStream(int iStream) { - for(int i = 0; i < 32; i++) - { - CAtlArray& sp = m_langs[i].subpos; + for (size_t i = 0; i < m_langs.size(); i++) { + const CAtlArray& sp = m_langs[i].subpos; - if(sp.IsEmpty() || iStream-- > 0) + if (sp.IsEmpty() || iStream-- > 0) { continue; + } m_iLang = i; @@ -1326,74 +1464,88 @@ static void PixelAtBiLinear(RGBQUAD& c, int x, int y, CVobSubImage& src) h = src.rect.Height(); int x1 = (x >> 16), y1 = (y >> 16) * w, - x2 = min(x1 + 1, w-1), y2 = min(y1 + w, (h-1)*w); + x2 = min(x1 + 1, w - 1), y2 = min(y1 + w, (h - 1) * w); RGBQUAD* ptr = src.lpPixels; - RGBQUAD c11 = ptr[y1 + x1], c12 = ptr[y1 + x2], - c21 = ptr[y2 + x1], c22 = ptr[y2 + x2]; + RGBQUAD c11 = ptr[y1 + x1], c12 = ptr[y1 + x2], + c21 = ptr[y2 + x1], c22 = ptr[y2 + x2]; __int64 u2 = x & 0xffff, - v2 = y & 0xffff, - u1 = 0x10000 - u2, - v1 = 0x10000 - v2; + v2 = y & 0xffff, + u1 = 0x10000 - u2, + v1 = 0x10000 - v2; - int v1u1 = int(v1*u1 >> 16) * c11.rgbReserved, - v1u2 = int(v1*u2 >> 16) * c12.rgbReserved, - v2u1 = int(v2*u1 >> 16) * c21.rgbReserved, - v2u2 = int(v2*u2 >> 16) * c22.rgbReserved; + int v1u1 = int(v1 * u1 >> 16) * c11.rgbReserved, + v1u2 = int(v1 * u2 >> 16) * c12.rgbReserved, + v2u1 = int(v2 * u1 >> 16) * c21.rgbReserved, + v2u2 = int(v2 * u2 >> 16) * c22.rgbReserved; c.rgbRed = (c11.rgbRed * v1u1 + c12.rgbRed * v1u2 - + c21.rgbRed * v2u1 + c22.rgbRed * v2u2) >> 24; + + c21.rgbRed * v2u1 + c22.rgbRed * v2u2) >> 24; c.rgbGreen = (c11.rgbGreen * v1u1 + c12.rgbGreen * v1u2 - + c21.rgbGreen * v2u1 + c22.rgbGreen * v2u2) >> 24; + + c21.rgbGreen * v2u1 + c22.rgbGreen * v2u2) >> 24; c.rgbBlue = (c11.rgbBlue * v1u1 + c12.rgbBlue * v1u2 - + c21.rgbBlue * v2u1 + c22.rgbBlue * v2u2) >> 24; - c.rgbReserved = (v1u1 + v1u2 - + v2u1 + v2u2) >> 16; + + c21.rgbBlue * v2u1 + c22.rgbBlue * v2u2) >> 24; + c.rgbReserved = BYTE((v1u1 + v1u2 + + v2u1 + v2u2) >> 16); } static void StretchBlt(SubPicDesc& spd, CRect dstrect, CVobSubImage& src) { - if(dstrect.IsRectEmpty()) return; + if (dstrect.IsRectEmpty()) { + return; + } - if((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) return; + if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { + return; + } int sw = src.rect.Width(), sh = src.rect.Height(), dw = dstrect.Width(), dh = dstrect.Height(); - int srcx = 0, + int srcx = 0, srcy = 0, - srcdx = (sw << 16) / dw >> 1, + srcdx = (sw << 16) / dw >> 1, srcdy = (sh << 16) / dh >> 1; - if(dstrect.left < 0) {srcx = -dstrect.left * (srcdx<<1); dstrect.left = 0;} - if(dstrect.top < 0) {srcy = -dstrect.top * (srcdy<<1); dstrect.top = 0;} - if(dstrect.right > spd.w) {dstrect.right = spd.w;} - if(dstrect.bottom > spd.h) {dstrect.bottom = spd.h;} + if (dstrect.left < 0) { + srcx = -dstrect.left * (srcdx << 1); + dstrect.left = 0; + } + if (dstrect.top < 0) { + srcy = -dstrect.top * (srcdy << 1); + dstrect.top = 0; + } + if (dstrect.right > spd.w) { + dstrect.right = spd.w; + } + if (dstrect.bottom > spd.h) { + dstrect.bottom = spd.h; + } - if((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) return; + if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { + return; + } dw = dstrect.Width(); dh = dstrect.Height(); - for(int y = dstrect.top; y < dstrect.bottom; y++, srcy += (srcdy<<1)) - { - RGBQUAD* ptr = (RGBQUAD*)&((BYTE*)spd.bits)[y*spd.pitch] + dstrect.left; + for (int y = dstrect.top; y < dstrect.bottom; y++, srcy += (srcdy << 1)) { + RGBQUAD* ptr = (RGBQUAD*) & ((BYTE*)spd.bits)[y * spd.pitch] + dstrect.left; RGBQUAD* endptr = ptr + dw; - for(int sx = srcx; ptr < endptr; sx += (srcdx<<1), ptr++) - { - // PixelAtBiLinear(*ptr, sx, srcy, src); + for (int sx = srcx; ptr < endptr; sx += (srcdx << 1), ptr++) { + // PixelAtBiLinear(*ptr, sx, srcy, src); //// RGBQUAD cc[4]; - PixelAtBiLinear(cc[0], sx, srcy, src); - PixelAtBiLinear(cc[1], sx+srcdx, srcy, src); - PixelAtBiLinear(cc[2], sx, srcy+srcdy, src); - PixelAtBiLinear(cc[3], sx+srcdx, srcy+srcdy, src); + PixelAtBiLinear(cc[0], sx, srcy, src); + PixelAtBiLinear(cc[1], sx + srcdx, srcy, src); + PixelAtBiLinear(cc[2], sx, srcy + srcdy, src); + PixelAtBiLinear(cc[3], sx + srcdx, srcy + srcdy, src); ptr->rgbRed = (cc[0].rgbRed + cc[1].rgbRed + cc[2].rgbRed + cc[3].rgbRed) >> 2; ptr->rgbGreen = (cc[0].rgbGreen + cc[1].rgbGreen + cc[2].rgbGreen + cc[3].rgbGreen) >> 2; @@ -1432,16 +1584,18 @@ void CVobSubSettings::InitSettings() bool CVobSubSettings::GetCustomPal(RGBQUAD* cuspal, int& tridx) { - memcpy(cuspal, m_cuspal, sizeof(RGBQUAD)*4); + memcpy(cuspal, m_cuspal, sizeof(RGBQUAD) * 4); tridx = m_tridx; - return(m_fCustomPal); + return m_fCustomPal; } -void CVobSubSettings::SetCustomPal(RGBQUAD* cuspal, int tridx) +void CVobSubSettings::SetCustomPal(const RGBQUAD* cuspal, int tridx) { - memcpy(m_cuspal, cuspal, sizeof(RGBQUAD)*4); + memcpy(m_cuspal, cuspal, sizeof(RGBQUAD) * 4); m_tridx = tridx & 0xf; - for(int i = 0; i < 4; i++) m_cuspal[i].rgbReserved = (tridx&(1<>1); r.right = -(w>>1) + w; break; // center - case 2: r.left = -w; r.right = 0; break; // right - default: - r.left = MulDiv(m_img.rect.left, m_scale_x, 100); - r.right = MulDiv(m_img.rect.right, m_scale_x, 100); - break; + } else { + switch (m_alignhor) { + case 0: + r.left = 0; + r.right = w; + break; // left + case 1: + r.left = -(w >> 1); + r.right = -(w >> 1) + w; + break; // center + case 2: + r.left = -w; + r.right = 0; + break; // right + default: + r.left = MulDiv(m_img.rect.left, m_scale_x, 100); + r.right = MulDiv(m_img.rect.right, m_scale_x, 100); + break; } - switch(m_alignver) - { - case 0: r.top = 0; r.bottom = h; break; // top - case 1: r.top = -(h>>1); r.bottom = -(h>>1) + h; break; // center - case 2: r.top = -h; r.bottom = 0; break; // bottom - default: - r.top = MulDiv(m_img.rect.top, m_scale_y, 100); - r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); - break; + switch (m_alignver) { + case 0: + r.top = 0; + r.bottom = h; + break; // top + case 1: + r.top = -(h >> 1); + r.bottom = -(h >> 1) + h; + break; // center + case 2: + r.top = -h; + r.bottom = 0; + break; // bottom + default: + r.top = MulDiv(m_img.rect.top, m_scale_y, 100); + r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); + break; } } @@ -1495,39 +1662,34 @@ void CVobSubSettings::GetDestrect(CRect& r, int w, int h) r.bottom = MulDiv(r.bottom, h, m_size.cy); } -void CVobSubSettings::SetAlignment(bool fAlign, int x, int y, int hor, int ver) +void CVobSubSettings::SetAlignment(bool fAlign, int x, int y, int hor /*= 1*/, int ver /*= 1*/) { m_fAlign = fAlign; - if(m_fAlign) - { + if (fAlign) { m_org.x = MulDiv(m_size.cx, x, 100); m_org.y = MulDiv(m_size.cy, y, 100); m_alignhor = min(max(hor, 0), 2); m_alignver = min(max(ver, 0), 2); - } - else - { + } else { m_org.x = m_x; m_org.y = m_y; } } -#include "RTS.h" - HRESULT CVobSubSettings::Render(SubPicDesc& spd, RECT& bbox) { CRect r; GetDestrect(r, spd.w, spd.h); StretchBlt(spd, r, m_img); /* - CRenderedTextSubtitle rts(NULL); - rts.CreateDefaultStyle(DEFAULT_CHARSET); - rts.m_dstScreenSize.SetSize(m_size.cx, m_size.cy); - CStringW assstr; - m_img.Polygonize(assstr, false); - REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay); - rts.Add(assstr, true, rtStart, rtStop); - rts.Render(spd, (rtStart+rtStop)/2, 25, r); + CRenderedTextSubtitle rts(nullptr); + rts.CreateDefaultStyle(DEFAULT_CHARSET); + rts.m_dstScreenSize.SetSize(m_size.cx, m_size.cy); + CStringW assstr; + m_img.Polygonize(assstr, false); + REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay); + rts.Add(assstr, true, rtStart, rtStop); + rts.Render(spd, (rtStart+rtStop)/2, 25, r); */ r &= CRect(CPoint(0, 0), CSize(spd.w, spd.h)); bbox = r; @@ -1538,55 +1700,52 @@ HRESULT CVobSubSettings::Render(SubPicDesc& spd, RECT& bbox) static bool CompressFile(CString fn) { - if(GetVersion() < 0) - return(false); - BOOL b = FALSE; - HANDLE h = CreateFile(fn, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); - if(h != INVALID_HANDLE_VALUE) - { - USHORT us = COMPRESSION_FORMAT_DEFAULT; + HANDLE h = CreateFile(fn, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); + if (h != INVALID_HANDLE_VALUE) { + unsigned short us = COMPRESSION_FORMAT_DEFAULT; DWORD nBytesReturned; - b = DeviceIoControl(h, FSCTL_SET_COMPRESSION, (LPVOID)&us, 2, NULL, 0, (LPDWORD)&nBytesReturned, NULL); + b = DeviceIoControl(h, FSCTL_SET_COMPRESSION, (LPVOID)&us, 2, nullptr, 0, (LPDWORD)&nBytesReturned, nullptr); CloseHandle(h); } - return(!!b); + return !!b; } -bool CVobSubFile::SaveVobSub(CString fn) +bool CVobSubFile::SaveVobSub(CString fn, int delay) { - return WriteIdx(fn + _T(".idx")) && WriteSub(fn + _T(".sub")); + return WriteIdx(fn + _T(".idx"), delay) && WriteSub(fn + _T(".sub")); } -bool CVobSubFile::SaveWinSubMux(CString fn) +bool CVobSubFile::SaveWinSubMux(CString fn, int delay) { TrimExtension(fn); CStdioFile f; - if(!f.Open(fn + _T(".sub"), CFile::modeCreate|CFile::modeWrite|CFile::typeText|CFile::shareDenyWrite)) - return(false); + if (!f.Open(fn + _T(".sub"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } m_img.Invalidate(); CAutoVectorPtr p4bpp; - if(!p4bpp.Allocate(720*576/2)) - return(false); + if (!p4bpp.Allocate(720 * 576 / 2)) { + return false; + } CAtlArray& sp = m_langs[m_iLang].subpos; - for(size_t i = 0; i < sp.GetCount(); i++) - { - if(!GetFrame(i)) continue; + for (size_t i = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } int pal[4] = {0, 1, 2, 3}; - for(int j = 0; j < 5; j++) - { - if(j == 4 || !m_img.pal[j].tr) - { + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { j &= 3; - memset(p4bpp, (j<<4)|j, 720*576/2); + memset(p4bpp, (j << 4) | j, 720 * 576 / 2); pal[j] ^= pal[0], pal[0] ^= pal[j], pal[j] ^= pal[0]; break; } @@ -1594,24 +1753,21 @@ bool CVobSubFile::SaveWinSubMux(CString fn) 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}; - DWORD uipal[4+12]; + DWORD uipal[4 + 12]; - if(!m_fCustomPal) - { + if (!m_fCustomPal) { uipal[0] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[0]].pal]); uipal[1] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[1]].pal]); uipal[2] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[2]].pal]); uipal[3] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[3]].pal]); - } - else - { + } else { uipal[0] = *((DWORD*)&m_img.cuspal[pal[0]]) & 0xffffff; uipal[1] = *((DWORD*)&m_img.cuspal[pal[1]]) & 0xffffff; uipal[2] = *((DWORD*)&m_img.cuspal[pal[2]]) & 0xffffff; uipal[3] = *((DWORD*)&m_img.cuspal[pal[3]]) & 0xffffff; } - CAtlMap palmap; + CAtlMap palmap; palmap[uipal[0]] = 0; palmap[uipal[1]] = 1; palmap[uipal[2]] = 2; @@ -1619,102 +1775,104 @@ bool CVobSubFile::SaveWinSubMux(CString fn) uipal[0] = 0xff; // blue background - int w = m_img.rect.Width()-2; - int h = m_img.rect.Height()-2; - int pitch = (((w+1)>>1) + 3) & ~3; + int w = m_img.rect.Width() - 2; + int h = m_img.rect.Height() - 2; + int pitch = (((w + 1) >> 1) + 3) & ~3; - for(int y = 0; y < h; y++) - { - DWORD* p = (DWORD*)&m_img.lpPixels[(y+1)*(w+2)+1]; + for (ptrdiff_t y = 0; y < h; y++) { + DWORD* p = (DWORD*)&m_img.lpPixels[(y + 1) * (w + 2) + 1]; - for(int x = 0; x < w; x++, p++) - { + for (ptrdiff_t x = 0; x < w; x++, p++) { BYTE c = 0; - if(*p & 0xff000000) - { + if (*p & 0xff000000) { DWORD uic = *p & 0xffffff; palmap.Lookup(uic, c); } - BYTE& c4bpp = p4bpp[(h-y-1)*pitch+(x>>1)]; - c4bpp = (x&1) ? ((c4bpp&0xf0)|c) : ((c4bpp&0x0f)|(c<<4)); + BYTE& c4bpp = p4bpp[(h - y - 1) * pitch + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); } } - int t1 = m_img.start, t2 = t1 + m_img.delay /*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/; + int t1 = (int)m_img.start + delay; + int t2 = t1 + (int)m_img.delay /*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/; - ASSERT(t2>t1); + ASSERT(t2 > t1); - if(t2 <= 0) continue; - if(t1 < 0) t1 = 0; + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } CString bmpfn; - bmpfn.Format(_T("%s_%06d.bmp"), fn, i+1); + bmpfn.Format(_T("%s_%06u.bmp"), fn, i + 1); CString str; - str.Format(_T("%s\t%02d:%02d:%02d:%02d %02d:%02d:%02d:%02d\t%03d %03d %03d %03d %d %d %d %d\n"), - bmpfn, - t1/1000/60/60, (t1/1000/60)%60, (t1/1000)%60, (t1%1000)/10, - t2/1000/60/60, (t2/1000/60)%60, (t2/1000)%60, (t2%1000)/10, - m_img.rect.Width(), m_img.rect.Height(), m_img.rect.left, m_img.rect.top, - (tr[0]<<4)|tr[0], (tr[1]<<4)|tr[1], (tr[2]<<4)|tr[2], (tr[3]<<4)|tr[3]); + str.Format(_T("%s\t%02d:%02d:%02d:%02d %02d:%02d:%02d:%02d\t%03d %03d %03d %03d %d %d %d %d\n"), + bmpfn, + t1 / 1000 / 60 / 60, (t1 / 1000 / 60) % 60, (t1 / 1000) % 60, (t1 % 1000) / 10, + t2 / 1000 / 60 / 60, (t2 / 1000 / 60) % 60, (t2 / 1000) % 60, (t2 % 1000) / 10, + m_img.rect.Width(), m_img.rect.Height(), m_img.rect.left, m_img.rect.top, + (tr[0] << 4) | tr[0], (tr[1] << 4) | tr[1], (tr[2] << 4) | tr[2], (tr[3] << 4) | tr[3]); f.WriteString(str); - BITMAPFILEHEADER fhdr = - { + BITMAPFILEHEADER fhdr = { 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + pitch*h, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + pitch * h, 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) }; - BITMAPINFOHEADER ihdr = - { + BITMAPINFOHEADER ihdr = { sizeof(BITMAPINFOHEADER), w, h, 1, 4, 0, 0, - pitch*h, 0, + pitch * h, 0, 16, 4 }; CFile bmp; - if(bmp.Open(bmpfn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite)) - { + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { bmp.Write(&fhdr, sizeof(fhdr)); bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(uipal, sizeof(RGBQUAD)*16); - bmp.Write(p4bpp, pitch*h); + bmp.Write(uipal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, pitch * h); bmp.Close(); CompressFile(bmpfn); } } - return(true); + return true; } -bool CVobSubFile::SaveScenarist(CString fn) +bool CVobSubFile::SaveScenarist(CString fn, int delay) { TrimExtension(fn); CStdioFile f; - if(!f.Open(fn + _T(".sst"), CFile::modeCreate|CFile::modeWrite|CFile::typeText|CFile::shareDenyWrite)) - return(false); + if (!f.Open(fn + _T(".sst"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } m_img.Invalidate(); fn.Replace('\\', '/'); - CString title = fn.Mid(fn.ReverseFind('/')+1); + CString title = fn.Mid(fn.ReverseFind('/') + 1); TCHAR buff[MAX_PATH], * pFilePart = buff; - if(GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) - return(false); + if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { + return false; + } - CString fullpath = CString(buff).Left(pFilePart - buff); + CString fullpath = CString(buff).Left(int(pFilePart - buff)); fullpath.TrimRight(_T("\\/")); - if(fullpath.IsEmpty()) - return(false); + if (fullpath.IsEmpty()) { + return false; + } CString str, str2; str += _T("st_format\t2\n"); @@ -1733,20 +1891,19 @@ bool CVobSubFile::SaveScenarist(CString fn) str += _T("BG\t(255 255 255 - - - )\n"); str += _T("\n"); str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); - str2.Format(str, - !m_fOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), - m_size.cy == 480 ? _T("NTSC") : _T("PAL"), - m_size.cy-3, - fullpath, - title, - m_size.cy == 480 ? 479 : 574); + str2.Format(str, + !m_fOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), + m_size.cy == 480 ? _T("NTSC") : _T("PAL"), + m_size.cy - 3, + fullpath, + title, + m_size.cy == 480 ? 479 : 574); f.WriteString(str2); f.Flush(); - RGBQUAD pal[16] = - { + RGBQUAD pal[16] = { {255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, @@ -1765,95 +1922,94 @@ bool CVobSubFile::SaveScenarist(CString fn) {125, 0, 125, 0}, }; - BITMAPFILEHEADER fhdr = - { + BITMAPFILEHEADER fhdr = { 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + 360*(m_size.cy-2), + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) }; - BITMAPINFOHEADER ihdr = - { + BITMAPINFOHEADER ihdr = { sizeof(BITMAPINFOHEADER), - 720, m_size.cy-2, 1, 4, 0, - 360*(m_size.cy-2), + 720, m_size.cy - 2, 1, 4, 0, + 360 * (m_size.cy - 2), 0, 0, 16, 4 }; bool fCustomPal = m_fCustomPal; m_fCustomPal = true; - RGBQUAD tempCusPal[4], newCusPal[4+12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; + RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); CAutoVectorPtr p4bpp; - if(!p4bpp.Allocate((m_size.cy-2)*360)) - return(false); + if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { + return false; + } BYTE colormap[16]; - for(int i = 0; i < 16; i++) - { - int idx = 0, maxdif = 255*255*3+1; + for (size_t i = 0; i < 16; i++) { + BYTE idx = 0; + int maxdif = 255 * 255 * 3 + 1; - for(int j = 0; j < 16 && maxdif; j++) - { + for (size_t j = 0; j < 16 && maxdif; j++) { int rdif = pal[j].rgbRed - m_orgpal[i].rgbRed; int gdif = pal[j].rgbGreen - m_orgpal[i].rgbGreen; int bdif = pal[j].rgbBlue - m_orgpal[i].rgbBlue; - int dif = rdif*rdif + gdif*gdif + bdif*bdif; - if(dif < maxdif) {maxdif = dif; idx = j;} + int dif = rdif * rdif + gdif * gdif + bdif * bdif; + if (dif < maxdif) { + maxdif = dif; + idx = (BYTE)j; + } } - colormap[i] = idx+1; + colormap[i] = idx + 1; } int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; CAtlArray& sp = m_langs[m_iLang].subpos; - for(size_t i = 0, k = 0; i < sp.GetCount(); i++) - { - if(!GetFrame(i)) continue; + for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } - for(int j = 0; j < 5; j++) - { - if(j == 4 || !m_img.pal[j].tr) - { + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { j &= 3; - memset(p4bpp, (j<<4)|j, (m_size.cy-2)*360); + memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); break; } } - for(int y = max(m_img.rect.top+1, 2); y < m_img.rect.bottom-1; y++) - { - ASSERT(m_size.cy-y-1 >= 0); - if(m_size.cy-y-1 < 0) break; + for (ptrdiff_t y = max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { + ASSERT(m_size.cy - y - 1 >= 0); + if (m_size.cy - y - 1 < 0) { + break; + } - DWORD* p = (DWORD*)&m_img.lpPixels[(y-m_img.rect.top)*m_img.rect.Width()+1]; + DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; - for(int x = m_img.rect.left+1; x < m_img.rect.right-1; x++, p++) - { - DWORD rgb = *p&0xffffff; + for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { + DWORD rgb = *p & 0xffffff; BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; - BYTE& c4bpp = p4bpp[(m_size.cy-y-1)*360+(x>>1)]; - c4bpp = (x&1) ? ((c4bpp&0xf0)|c) : ((c4bpp&0x0f)|(c<<4)); + BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); } } CString bmpfn; - bmpfn.Format(_T("%s_%04d.bmp"), fn, i+1); - title = bmpfn.Mid(bmpfn.ReverseFind('/')+1); + bmpfn.Format(_T("%s_%04u.bmp"), fn, i + 1); + title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); // E1, E2, P, Bg 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]}; - c[0]^=c[1], c[1]^=c[0], c[0]^=c[1]; + c[0] ^= c[1], c[1] ^= c[0], c[0] ^= c[1]; - if(memcmp(pc, c, sizeof(c))) - { + if (memcmp(pc, c, sizeof(c))) { memcpy(pc, c, sizeof(c)); str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); f.WriteString(str); @@ -1861,62 +2017,86 @@ bool CVobSubFile::SaveScenarist(CString fn) // E1, E2, P, Bg int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; - a[0]^=a[1], a[1]^=a[0], a[0]^=a[1]; + a[0] ^= a[1], a[1] ^= a[0], a[0] ^= a[1]; - if(memcmp(pa, a, sizeof(a))) - { + if (memcmp(pa, a, sizeof(a))) { memcpy(pa, a, sizeof(a)); str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); f.WriteString(str); } - int t1 = sp[i].start; - int h1 = t1/1000/60/60, m1 = (t1/1000/60)%60, s1 = (t1/1000)%60; - int f1 = (int)((m_size.cy==480?29.97:25)*(t1%1000)/1000); + int t1 = (int)sp[i].start + delay; + int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; + int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); - int t2 = sp[i].stop; - int h2 = t2/1000/60/60, m2 = (t2/1000/60)%60, s2 = (t2/1000)%60; - int f2 = (int)((m_size.cy==480?29.97:25)*(t2%1000)/1000); + int t2 = (int)sp[i].stop + delay; + int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; + int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); - if(t2 <= 0) continue; - if(t1 < 0) t1 = 0; + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } - if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) - { + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { f2++; - if(f2 == (m_size.cy==480?30:25)) {f2 = 0; s2++; if(s2 == 60) {s2 = 0; m2++; if(m2 == 60) {m2 = 0; h2++;}}} + if (f2 == (m_size.cy == 480 ? 30 : 25)) { + f2 = 0; + s2++; + if (s2 == 60) { + s2 = 0; + m2++; + if (m2 == 60) { + m2 = 0; + h2++; + } + } + } } - if(i < sp.GetCount()-1) - { - int t3 = sp[i+1].start; - int h3 = t3/1000/60/60, m3 = (t3/1000/60)%60, s3 = (t3/1000)%60; - int f3 = (int)((m_size.cy==480?29.97:25)*(t3%1000)/1000); + if (i + 1 < sp.GetCount()) { + int t3 = (int)sp[i + 1].start + delay; + int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; + int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); - if(h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) - { + if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { f2--; - 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--;}}} + 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--; + } + } + } + } } } - if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { continue; + } - str.Format(_T("%04d\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), - ++k, - h1, m1, s1, f1, - h2, m2, s2, f2, - title); + str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), + ++k, + h1, m1, s1, f1, + h2, m2, s2, f2, + title); f.WriteString(str); CFile bmp; - if(bmp.Open(bmpfn, CFile::modeCreate|CFile::modeWrite|CFile::modeRead|CFile::typeBinary)) - { + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::modeRead | CFile::typeBinary)) { bmp.Write(&fhdr, sizeof(fhdr)); bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(newCusPal, sizeof(RGBQUAD)*16); - bmp.Write(p4bpp, 360*(m_size.cy-2)); + bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, 360 * (m_size.cy - 2)); bmp.Close(); CompressFile(bmpfn); @@ -1926,30 +2106,33 @@ bool CVobSubFile::SaveScenarist(CString fn) m_fCustomPal = fCustomPal; memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); - return(true); + return true; } -bool CVobSubFile::SaveMaestro(CString fn) +bool CVobSubFile::SaveMaestro(CString fn, int delay) { TrimExtension(fn); CStdioFile f; - if(!f.Open(fn + _T(".son"), CFile::modeCreate|CFile::modeWrite|CFile::typeText|CFile::shareDenyWrite)) - return(false); + if (!f.Open(fn + _T(".son"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } m_img.Invalidate(); fn.Replace('\\', '/'); - CString title = fn.Mid(fn.ReverseFind('/')+1); + CString title = fn.Mid(fn.ReverseFind('/') + 1); TCHAR buff[MAX_PATH], * pFilePart = buff; - if(GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) - return(false); + if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { + return false; + } - CString fullpath = CString(buff).Left(pFilePart - buff); + CString fullpath = CString(buff).Left(int(pFilePart - buff)); fullpath.TrimRight(_T("\\/")); - if(fullpath.IsEmpty()) - return(false); + if (fullpath.IsEmpty()) { + return false; + } CString str, str2; str += _T("st_format\t2\n"); @@ -1963,123 +2146,99 @@ bool CVobSubFile::SaveMaestro(CString fn) str += _T("Contrast\t(15 15 15 0)\n"); str += _T("\n"); str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); - str2.Format(str, - !m_fOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), - m_size.cy == 480 ? _T("NTSC") : _T("PAL"), - m_size.cy-3, - fullpath, - title, - m_size.cy == 480 ? 479 : 574); + str2.Format(str, + !m_fOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), + m_size.cy == 480 ? _T("NTSC") : _T("PAL"), + m_size.cy - 3, + fullpath, + title, + m_size.cy == 480 ? 479 : 574); f.WriteString(str2); f.Flush(); - RGBQUAD pal[16] = - { - {255, 0, 0, 0}, - {0, 0, 255, 0}, - {0, 0, 0, 0}, - {255, 255, 255, 0}, - {0, 255, 0, 0}, - {255, 0, 255, 0}, - {0, 255, 255, 0}, - {125, 125, 0, 0}, - {125, 125, 125, 0}, - {225, 225, 225, 0}, - {0, 0, 125, 0}, - {0, 125, 0, 0}, - {125, 0, 0, 0}, - {255, 0, 222, 0}, - {0, 125, 222, 0}, - {125, 0, 125, 0}, - }; - - BITMAPFILEHEADER fhdr = - { + BITMAPFILEHEADER fhdr = { 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + 360*(m_size.cy-2), + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*sizeof(RGBQUAD) + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) }; - BITMAPINFOHEADER ihdr = - { + BITMAPINFOHEADER ihdr = { sizeof(BITMAPINFOHEADER), - 720, m_size.cy-2, 1, 4, 0, - 360*(m_size.cy-2), + 720, m_size.cy - 2, 1, 4, 0, + 360 * (m_size.cy - 2), 0, 0, 16, 4 }; bool fCustomPal = m_fCustomPal; m_fCustomPal = true; - RGBQUAD tempCusPal[4], newCusPal[4+12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; + RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); CAutoVectorPtr p4bpp; - if(!p4bpp.Allocate((m_size.cy-2)*360)) - return(false); + if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { + return false; + } BYTE colormap[16]; - for(int i = 0; i < 16; i++) + for (BYTE i = 0; i < 16; i++) { colormap[i] = i; + } CFile spf; - if(spf.Open(fn + _T(".spf"), CFile::modeCreate|CFile::modeWrite|CFile::typeBinary)) - { - for(int i = 0; i < 16; i++) - { - COLORREF c = (m_orgpal[i].rgbBlue<<16) | (m_orgpal[i].rgbGreen<<8) | m_orgpal[i].rgbRed; + if (spf.Open(fn + _T(".spf"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { + for (size_t i = 0; i < 16; i++) { + COLORREF c = (m_orgpal[i].rgbBlue << 16) | (m_orgpal[i].rgbGreen << 8) | m_orgpal[i].rgbRed; spf.Write(&c, sizeof(COLORREF)); } spf.Close(); } - int pc[4] = {1,1,1,1}, pa[4] = {15,15,15,0}; + int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; - const CAtlArray& sp = m_langs[m_iLang].subpos; - for(int i = 0, k = 0, n=sp.GetCount(); i < n; i++) - { - if(!GetFrame(i)) continue; + CAtlArray& sp = m_langs[m_iLang].subpos; + for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } - for(int j = 0; j < 5; j++) - { - if(j == 4 || !m_img.pal[j].tr) - { + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { j &= 3; - memset(p4bpp, (j<<4)|j, (m_size.cy-2)*360); + memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); break; } } - for(int y = max(m_img.rect.top+1, 2); y < m_img.rect.bottom-1; y++) - { - ASSERT(m_size.cy-y-1 >= 0); - if(m_size.cy-y-1 < 0) break; + for (ptrdiff_t y = max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { + ASSERT(m_size.cy - y - 1 >= 0); + if (m_size.cy - y - 1 < 0) { + break; + } - DWORD* p = (DWORD*)&m_img.lpPixels[(y-m_img.rect.top)*m_img.rect.Width()+1]; + DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; - for(int x = m_img.rect.left+1; x < m_img.rect.right-1; x++, p++) - { - DWORD rgb = *p&0xffffff; + for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { + DWORD rgb = *p & 0xffffff; BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; - BYTE& c4bpp = p4bpp[(m_size.cy-y-1)*360+(x>>1)]; - c4bpp = (x&1) ? ((c4bpp&0xf0)|c) : ((c4bpp&0x0f)|(c<<4)); + BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); } } CString bmpfn; - bmpfn.Format(_T("%s_%04d.bmp"), fn, i+1); - title = bmpfn.Mid(bmpfn.ReverseFind('/')+1); + bmpfn.Format(_T("%s_%04u.bmp"), fn, i + 1); + title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); // E1, E2, P, Bg 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]}; - if(memcmp(pc, c, sizeof(c))) - { + if (memcmp(pc, c, sizeof(c))) { memcpy(pc, c, sizeof(c)); str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); f.WriteString(str); @@ -2088,60 +2247,84 @@ bool CVobSubFile::SaveMaestro(CString fn) // E1, E2, P, Bg int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; - if(memcmp(pa, a, sizeof(a))) - { + if (memcmp(pa, a, sizeof(a))) { memcpy(pa, a, sizeof(a)); str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); f.WriteString(str); } - int t1 = sp[i].start; - int h1 = t1/1000/60/60, m1 = (t1/1000/60)%60, s1 = (t1/1000)%60; - int f1 = (int)((m_size.cy==480?29.97:25)*(t1%1000)/1000); + int t1 = (int)sp[i].start + delay; + int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; + int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); - int t2 = sp[i].stop; - int h2 = t2/1000/60/60, m2 = (t2/1000/60)%60, s2 = (t2/1000)%60; - int f2 = (int)((m_size.cy==480?29.97:25)*(t2%1000)/1000); + int t2 = (int)sp[i].stop + delay; + int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; + int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); - if(t2 <= 0) continue; - if(t1 < 0) t1 = 0; + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } - if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) - { + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { f2++; - if(f2 == (m_size.cy==480?30:25)) {f2 = 0; s2++; if(s2 == 60) {s2 = 0; m2++; if(m2 == 60) {m2 = 0; h2++;}}} + if (f2 == (m_size.cy == 480 ? 30 : 25)) { + f2 = 0; + s2++; + if (s2 == 60) { + s2 = 0; + m2++; + if (m2 == 60) { + m2 = 0; + h2++; + } + } + } } - if(i < n-1) - { - int t3 = sp[i+1].start; - int h3 = t3/1000/60/60, m3 = (t3/1000/60)%60, s3 = (t3/1000)%60; - int f3 = (int)((m_size.cy==480?29.97:25)*(t3%1000)/1000); + if (i < sp.GetCount() - 1) { + int t3 = (int)sp[i + 1].start + delay; + int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; + int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); - if(h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) - { + if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { f2--; - 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--;}}} + 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--; + } + } + } + } } } - if(h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { continue; + } - str.Format(_T("%04d\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), - ++k, - h1, m1, s1, f1, - h2, m2, s2, f2, - title); + str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), + ++k, + h1, m1, s1, f1, + h2, m2, s2, f2, + title); f.WriteString(str); CFile bmp; - if(bmp.Open(bmpfn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary)) - { + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { bmp.Write(&fhdr, sizeof(fhdr)); bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(newCusPal, sizeof(RGBQUAD)*16); - bmp.Write(p4bpp, 360*(m_size.cy-2)); + bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, 360 * (m_size.cy - 2)); bmp.Close(); CompressFile(bmpfn); @@ -2151,7 +2334,7 @@ bool CVobSubFile::SaveMaestro(CString fn) m_fCustomPal = fCustomPal; memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); - return(true); + return true; } // @@ -2175,72 +2358,76 @@ void CVobSubStream::Open(CString name, BYTE* pData, int len) CAtlList lines; Explode(CString(CStringA((CHAR*)pData, len)), lines, '\n'); - while(lines.GetCount()) - { + while (lines.GetCount()) { CAtlList sl; Explode(lines.RemoveHead(), sl, ':', 2); - if(sl.GetCount() != 2) continue; + if (sl.GetCount() != 2) { + continue; + } CString key = sl.GetHead(); CString value = sl.GetTail(); - if(key == _T("size")) - _stscanf(value, _T("%dx %d"), &m_size.cx, &m_size.cy); - else if(key == _T("org")) - _stscanf(value, _T("%d, %d"), &m_org.x, &m_org.y); - else if(key == _T("scale")) - _stscanf(value, _T("%d%%, %d%%"), &m_scale_x, &m_scale_y); - else if(key == _T("alpha")) - _stscanf(value, _T("%d%%"), &m_alpha); - else if(key == _T("smooth")) - m_fSmooth = - value == _T("0") || value == _T("OFF") ? 0 : - value == _T("1") || value == _T("ON") ? 1 : - value == _T("2") || value == _T("OLD") ? 2 : - 0; - else if(key == _T("align")) - { + if (key == _T("size")) { + _stscanf_s(value, _T("%dx %d"), &m_size.cx, &m_size.cy); + } else if (key == _T("org")) { + _stscanf_s(value, _T("%d, %d"), &m_org.x, &m_org.y); + } else if (key == _T("scale")) { + _stscanf_s(value, _T("%d%%, %d%%"), &m_scale_x, &m_scale_y); + } else if (key == _T("alpha")) { + _stscanf_s(value, _T("%d%%"), &m_alpha); + } else if (key == _T("smooth")) + m_fSmooth = + value == _T("0") || value == _T("OFF") ? 0 : + value == _T("1") || value == _T("ON") ? 1 : + value == _T("2") || value == _T("OLD") ? 2 : + 0; + else if (key == _T("align")) { Explode(value, sl, ' '); - if(sl.GetCount() == 4) sl.RemoveAt(sl.FindIndex(1)); - if(sl.GetCount() == 3) - { + if (sl.GetCount() == 4) { + sl.RemoveAt(sl.FindIndex(1)); + } + if (sl.GetCount() == 3) { m_fAlign = sl.RemoveHead() == _T("ON"); CString hor = sl.GetHead(), ver = sl.GetTail(); m_alignhor = hor == _T("LEFT") ? 0 : hor == _T("CENTER") ? 1 : hor == _T("RIGHT") ? 2 : 1; - m_alignver = ver == _T("TOP") ? 0 : ver == _T("CENTER") ? 1 : ver == _T("BOTTOM") ? 2 : 2; + m_alignver = ver == _T("TOP") ? 0 : ver == _T("CENTER") ? 1 : /*ver == _T("BOTTOM") ? 2 :*/ 2; } - } - else if(key == _T("fade in/out")) - _stscanf(value, _T("%d%, %d%"), &m_fadein, &m_fadeout); - else if(key == _T("time offset")) - m_toff = _tcstol(value, NULL, 10); - else if(key == _T("forced subs")) + } else if (key == _T("fade in/out")) { + _stscanf_s(value, _T("%d%, %d%"), &m_fadein, &m_fadeout); + } else if (key == _T("time offset")) { + m_toff = _tcstol(value, nullptr, 10); + } else if (key == _T("forced subs")) { m_fOnlyShowForcedSubs = value == _T("1") || value == _T("ON"); - else if(key == _T("palette")) - { + } else if (key == _T("palette")) { Explode(value, sl, ',', 16); - for(int i = 0; i < 16 && sl.GetCount(); i++) - *(DWORD*)&m_orgpal[i] = _tcstol(sl.RemoveHead(), NULL, 16); - } - else if(key == _T("custom colors")) - { + for (size_t i = 0; i < 16 && sl.GetCount(); i++) { + *(DWORD*)&m_orgpal[i] = _tcstol(sl.RemoveHead(), nullptr, 16); + } + } else if (key == _T("custom colors")) { m_fCustomPal = Explode(value, sl, ',', 3) == _T("ON"); - if(sl.GetCount() == 3) - { + if (sl.GetCount() == 3) { sl.RemoveHead(); CAtlList tridx, colors; + Explode(sl.RemoveHead(), tridx, ':', 2); - if(tridx.RemoveHead() == _T("tridx")) - { + int _tridx = 1; + if (tridx.RemoveHead() == _T("tridx")) { TCHAR tr[4]; _stscanf_s(tridx.RemoveHead(), _T("%c%c%c%c"), &tr[0], 1, &tr[1], 1, &tr[2], 1, &tr[3], 1); - for(int i = 0; i < 4; i++) - m_tridx |= ((tr[i]=='1')?1:0)< p(new SubPic()); + CAutoPtr p(DEBUG_NEW SubPic()); p->tStart = tStart; - p->tStop = vsi.delay > 0 ? (tStart + 10000i64*vsi.delay) : tStop; + p->tStop = vsi.delay > 0 ? (tStart + 10000i64 * vsi.delay) : tStop; + p->fAnimated = vsi.fAnimated; p->pData.SetCount(len); memcpy(p->pData.GetData(), pData, p->pData.GetCount()); CAutoLock cAutoLock(&m_csSubPics); - while(m_subpics.GetCount() && m_subpics.GetTail()->tStart >= tStart) - { + while (m_subpics.GetCount() && m_subpics.GetTail()->tStart >= tStart) { m_subpics.RemoveTail(); m_img.iIdx = -1; } @@ -2271,8 +2460,8 @@ void CVobSubStream::Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData // we have to fix it. tStop = tStart seems to work. if (m_subpics.GetCount() && m_subpics.GetTail()->tStop > p->tStart) { TRACE(_T("[CVobSubStream::Add] Vobsub timestamp overlap detected! ") - _T("Subpicture #%d, StopTime %I64d > %I64d (Next StartTime), making them equal!\n"), - m_subpics.GetCount(), m_subpics.GetTail()->tStop, p->tStart); + _T("Subpicture #%d, StopTime %I64d > %I64d (Next StartTime), making them equal!\n"), + m_subpics.GetCount(), m_subpics.GetTail()->tStop, p->tStart); m_subpics.GetTail()->tStop = p->tStart; } @@ -2289,9 +2478,9 @@ void CVobSubStream::RemoveAll() STDMETHODIMP CVobSubStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) { CheckPointer(ppv, E_POINTER); - *ppv = NULL; + *ppv = nullptr; - return + return QI(IPersist) QI(ISubStream) QI(ISubPicProvider) @@ -2304,16 +2493,16 @@ STDMETHODIMP_(POSITION) CVobSubStream::GetStartPosition(REFERENCE_TIME rt, doubl { CAutoLock cAutoLock(&m_csSubPics); POSITION pos = m_subpics.GetTailPosition(); - for(; pos; m_subpics.GetPrev(pos)) - { + for (; pos; m_subpics.GetPrev(pos)) { SubPic* sp = m_subpics.GetAt(pos); - if(sp->tStart <= rt) - { - if(sp->tStop <= rt) m_subpics.GetNext(pos); + if (sp->tStart <= rt) { + if (sp->tStop <= rt) { + m_subpics.GetNext(pos); + } break; } } - return(pos); + return pos; } STDMETHODIMP_(POSITION) CVobSubStream::GetNext(POSITION pos) @@ -2337,26 +2526,25 @@ STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStop(POSITION pos, double fps) STDMETHODIMP_(bool) CVobSubStream::IsAnimated(POSITION pos) { - return(false); + CAutoLock cAutoLock(&m_csSubPics); + return m_subpics.GetAt(pos)->fAnimated; } STDMETHODIMP CVobSubStream::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) { - if(spd.bpp != 32) return E_INVALIDARG; + if (spd.bpp != 32) { + return E_INVALIDARG; + } - POSITION pos = m_subpics.GetTailPosition(); - for(; pos; m_subpics.GetPrev(pos)) - { + for (POSITION pos = m_subpics.GetTailPosition(); pos; m_subpics.GetPrev(pos)) { SubPic* sp = m_subpics.GetAt(pos); - if(sp->tStart <= rt && rt < sp->tStop) - { - if(m_img.iIdx != (int)pos) - { - BYTE* pData = sp->pData.GetData(); + if (sp->tStart <= rt && rt < sp->tStop) { + if (m_img.iIdx != (size_t)pos || (sp->fAnimated && sp->tStart + m_img.tCurrent * 10000i64 <= rt)) { + BYTE* pData = sp->pData.GetData(); m_img.Decode( - pData, (pData[0]<<8)|pData[1], (pData[2]<<8)|pData[3], + pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3], int((rt - sp->tStart) / 10000i64), m_fCustomPal, m_tridx, m_orgpal, m_cuspal, true); - m_img.iIdx = (int)pos; + m_img.iIdx = (size_t)pos; } return __super::Render(spd, bbox); @@ -2384,16 +2572,15 @@ STDMETHODIMP CVobSubStream::GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID) { CAutoLock cAutoLock(&m_csSubPics); - if(ppName) - { - *ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength()+1)*sizeof(WCHAR)); - if(!(*ppName)) + if (ppName) { + *ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppName)) { return E_OUTOFMEMORY; - wcscpy(*ppName, CStringW(m_name)); + } + wcscpy_s(*ppName, m_name.GetLength() + 1, CStringW(m_name)); } - if(pLCID) - { + if (pLCID) { *pLCID = 0; // TODO } diff --git a/src/subtitles/VobSubFile.h b/src/subtitles/VobSubFile.h index ce089405f..515a12fc9 100644 --- a/src/subtitles/VobSubFile.h +++ b/src/subtitles/VobSubFile.h @@ -1,21 +1,21 @@ -/* - * Copyright (C) 2003-2006 Gabest - * http://www.gabest.org +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 see Authors.txt * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html + * This file is part of MPC-HC. + * + * MPC-HC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * MPC-HC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ @@ -23,162 +23,188 @@ #include #include "VobSubImage.h" -#include "..\SubPic\ISubPic.h" +#include "../SubPic/ISubPic.h" +#include "../SubPic/SubPicProviderImpl.h" #define VOBSUBIDXVER 7 +#define ReadBEb(var) \ + f.Read(&((BYTE*)&var)[0], 1); + +#define ReadBEw(var) \ + f.Read(&((BYTE*)&var)[1], 1); \ + f.Read(&((BYTE*)&var)[0], 1); + +#define ReadBEdw(var) \ + f.Read(&((BYTE*)&var)[3], 1); \ + f.Read(&((BYTE*)&var)[2], 1); \ + f.Read(&((BYTE*)&var)[1], 1); \ + f.Read(&((BYTE*)&var)[0], 1); + extern CString FindLangFromId(WORD id); class CVobSubSettings { protected: - HRESULT Render(SubPicDesc& spd, RECT& bbox); + HRESULT Render(SubPicDesc& spd, RECT& bbox); public: - CSize m_size; - int m_x, m_y; - CPoint m_org; - int m_scale_x, m_scale_y; // % (don't set it to unsigned because as a side effect it will mess up negative coordinates in GetDestrect()) - int m_alpha; // % - int m_fSmooth; // 0: OFF, 1: ON, 2: OLD (means no filtering at all) - int m_fadein, m_fadeout; // ms - bool m_fAlign; - int m_alignhor, m_alignver; // 0: left/top, 1: center, 2: right/bottom - unsigned int m_toff; // ms - bool m_fOnlyShowForcedSubs; - bool m_fCustomPal; - int m_tridx; - RGBQUAD m_orgpal[16], m_cuspal[4]; - - CVobSubImage m_img; - - CVobSubSettings() {InitSettings();} - void InitSettings(); - - bool GetCustomPal(RGBQUAD* cuspal, int& tridx); - void SetCustomPal(RGBQUAD* cuspal, int tridx); - - void GetDestrect(CRect& r); // destrect of m_img, considering the current alignment mode - void GetDestrect(CRect& r, int w, int h); // this will scale it to the frame size of (w, h) - - void SetAlignment(bool fAlign, int x, int y, int hor, int ver); + CSize m_size; + int m_x, m_y; + CPoint m_org; + int m_scale_x, m_scale_y; // % (don't set it to unsigned because as a side effect it will mess up negative coordinates in GetDestrect()) + int m_alpha; // % + int m_fSmooth; // 0: OFF, 1: ON, 2: OLD (means no filtering at all) + int m_fadein, m_fadeout; // ms + bool m_fAlign; + int m_alignhor, m_alignver; // 0: left/top, 1: center, 2: right/bottom + unsigned int m_toff; // ms + bool m_fOnlyShowForcedSubs; + bool m_fCustomPal; + int m_tridx; + RGBQUAD m_orgpal[16], m_cuspal[4]; + + CVobSubImage m_img; + + CVobSubSettings() { InitSettings(); } + void InitSettings(); + + bool GetCustomPal(RGBQUAD* cuspal, int& tridx); + void SetCustomPal(const RGBQUAD* cuspal, int tridx); + + void GetDestrect(CRect& r); // destrect of m_img, considering the current alignment mode + void GetDestrect(CRect& r, int w, int h); // this will scale it to the frame size of (w, h) + + void SetAlignment(bool fAlign, int x, int y, int hor = 1, int ver = 1); }; -[uuid("998D4C9A-460F-4de6-BDCD-35AB24F94ADF")] -class CVobSubFile : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl +class __declspec(uuid("998D4C9A-460F-4de6-BDCD-35AB24F94ADF")) + CVobSubFile : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl { +public: + struct SubPos { + __int64 filepos; + __int64 start; + __int64 stop; + bool fForced; + bool fAnimated; + char vobid; + char cellid; + __int64 celltimestamp; + bool fValid; + }; + + struct SubLang { + WORD id; + CString name, alt; + CAtlArray subpos; + }; + protected: - CString m_title; + CString m_title; - void TrimExtension(CString& fn); - bool ReadIdx(CString fn, int& ver), ReadSub(CString fn), ReadRar(CString fn), ReadIfo(CString fn); - bool WriteIdx(CString fn), WriteSub(CString fn); + void TrimExtension(CString& fn); + bool ReadIdx(CString fn, int& ver), ReadSub(CString fn), ReadRar(CString fn), ReadIfo(CString fn); + bool WriteIdx(CString fn, int delay), WriteSub(CString fn); - CMemFile m_sub; + CMemFile m_sub; - BYTE* GetPacket(int idx, int& packetsize, int& datasize, int iLang = -1); - bool GetFrame(int idx, int iLang = -1); - bool GetFrameByTimeStamp(__int64 time); - int GetFrameIdxByTimeStamp(__int64 time); + BYTE* GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang = -1); + const SubPos* GetFrameInfo(size_t idx, size_t nLang = -1) const; + bool GetFrame(size_t idx, size_t nLang = -1, REFERENCE_TIME rt = -1); + bool GetFrameByTimeStamp(__int64 time); + size_t GetFrameIdxByTimeStamp(__int64 time); - bool SaveVobSub(CString fn); - bool SaveWinSubMux(CString fn); - bool SaveScenarist(CString fn); - bool SaveMaestro(CString fn); + bool SaveVobSub(CString fn, int delay); + bool SaveWinSubMux(CString fn, int delay); + bool SaveScenarist(CString fn, int delay); + bool SaveMaestro(CString fn, int delay); public: - typedef struct - { - __int64 filepos; - __int64 start, stop; - bool fForced; - char vobid, cellid; - __int64 celltimestamp; - bool fValid; - } SubPos; - - typedef struct - { - int id; - CString name, alt; - CAtlArray subpos; - } SubLang; - - int m_iLang; - SubLang m_langs[32]; + size_t m_iLang; + std::array m_langs; -public: - CVobSubFile(CCritSec* pLock); - virtual ~CVobSubFile(); + CVobSubFile(CCritSec* pLock); + virtual ~CVobSubFile(); - bool Copy(CVobSubFile& vsf); + bool Copy(CVobSubFile& vsf); - typedef enum {None,VobSub,WinSubMux,Scenarist,Maestro} SubFormat; + enum SubFormat { + None, + VobSub, + WinSubMux, + Scenarist, + Maestro + }; - bool Open(CString fn); - bool Save(CString fn, SubFormat sf = VobSub); - void Close(); + bool Open(CString fn); + bool Save(CString fn, int delay = 0, SubFormat sf = VobSub); + void Close(); - CString GetTitle() {return(m_title);} + CString GetTitle() { return m_title; } - DECLARE_IUNKNOWN + DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - - // IPersist - STDMETHODIMP GetClassID(CLSID* pClassID); - - // ISubStream - STDMETHODIMP_(int) GetStreamCount(); - STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); - STDMETHODIMP_(int) GetStream(); - STDMETHODIMP SetStream(int iStream); - STDMETHODIMP Reload(); + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + + // IPersist + STDMETHODIMP GetClassID(CLSID* pClassID); + + // ISubStream + STDMETHODIMP_(int) GetStreamCount(); + STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); + STDMETHODIMP_(int) GetStream(); + STDMETHODIMP SetStream(int iStream); + STDMETHODIMP Reload(); }; -[uuid("D7FBFB45-2D13-494F-9B3D-FFC9557D5C45")] -class CVobSubStream : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl +class __declspec(uuid("D7FBFB45-2D13-494F-9B3D-FFC9557D5C45")) + CVobSubStream : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl { - CString m_name; + CString m_name; - CCritSec m_csSubPics; - struct SubPic {REFERENCE_TIME tStart, tStop; CAtlArray pData;}; - CAutoPtrList m_subpics; + CCritSec m_csSubPics; + struct SubPic { + REFERENCE_TIME tStart, tStop; + bool fAnimated; + CAtlArray pData; + }; + CAutoPtrList m_subpics; public: - CVobSubStream(CCritSec* pLock); - virtual ~CVobSubStream(); + CVobSubStream(CCritSec* pLock); + virtual ~CVobSubStream(); - void Open(CString name, BYTE* pData, int len); + void Open(CString name, BYTE* pData, int len); void Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len); - void RemoveAll(); + void RemoveAll(); - DECLARE_IUNKNOWN + DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - - // IPersist - STDMETHODIMP GetClassID(CLSID* pClassID); - - // ISubStream - STDMETHODIMP_(int) GetStreamCount(); - STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); - STDMETHODIMP_(int) GetStream(); - STDMETHODIMP SetStream(int iStream); - STDMETHODIMP Reload() {return E_NOTIMPL;} + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + + // IPersist + STDMETHODIMP GetClassID(CLSID* pClassID); + + // ISubStream + STDMETHODIMP_(int) GetStreamCount(); + STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); + STDMETHODIMP_(int) GetStream(); + STDMETHODIMP SetStream(int iStream); + STDMETHODIMP Reload() { return E_NOTIMPL; } }; diff --git a/src/subtitles/VobSubFileRipper.cpp b/src/subtitles/VobSubFileRipper.cpp index 3a7710730..a92128198 100644 --- a/src/subtitles/VobSubFileRipper.cpp +++ b/src/subtitles/VobSubFileRipper.cpp @@ -1,1259 +1,1187 @@ -/* - * Copyright (C) 2003-2006 Gabest - * http://www.gabest.org +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 see Authors.txt + * + * This file is part of MPC-HC. + * + * MPC-HC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * MPC-HC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ -#include "StdAfx.h" -#include "vobsubfileripper.h" -#include "..\decss\VobDec.h" -#include "..\subtitles\CCDecoder.h" +#include "stdafx.h" +#include +#include "VobSubFile.h" +#include "VobSubFileRipper.h" +#include "../DeCSS/VobDec.h" +#include "CCDecoder.h" // // CVobSubFileRipper // CVobSubFileRipper::CVobSubFileRipper() - : CVobSubFile(NULL) - , m_fThreadActive(false) - , m_fBreakThread(false) - , m_fIndexing(false) + : CVobSubFile(nullptr) + , m_bThreadActive(false) + , m_bBreakThread(false) + , m_bIndexing(false) { - m_rd.Reset(); - CAMThread::Create(); + m_rd.Reset(); + CAMThread::Create(); } CVobSubFileRipper::~CVobSubFileRipper() { - CAMThread::CallWorker(CMD_EXIT); - CAMThread::Close(); + CAMThread::CallWorker(CMD_EXIT); + CAMThread::Close(); } STDMETHODIMP CVobSubFileRipper::NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(IVSFRipper) - __super::NonDelegatingQueryInterface(riid, ppv); + return + QI(IVSFRipper) + __super::NonDelegatingQueryInterface(riid, ppv); } void CVobSubFileRipper::Log(log_t type, LPCTSTR lpszFormat, ...) { - CAutoLock cAutoLock(&m_csCallback); - if(!m_pCallback) return; - - TCHAR buff[1024]; - - va_list args; - va_start(args, lpszFormat); - _vstprintf(buff, countof(buff), lpszFormat, args); - va_end(args); - - CString msg; - switch(type) - { - default: - case LOG_INFO: msg = _T(""); break; - case LOG_WARNING: msg = _T("WARNING: "); break; - case LOG_ERROR: msg = _T("ERROR: "); break; - } - - msg += buff; - - m_pCallback->OnMessage(msg); + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } + + TCHAR buff[1024]; + + va_list args; + va_start(args, lpszFormat); + _vstprintf_s(buff, _countof(buff), lpszFormat, args); + va_end(args); + + CString msg; + switch (type) { + default: + case LOG_INFO: + msg = _T(""); + break; + case LOG_WARNING: + msg = _T("WARNING: "); + break; + case LOG_ERROR: + msg = _T("ERROR: "); + break; + } + + msg += buff; + + m_pCallback->OnMessage(msg); } void CVobSubFileRipper::Progress(double progress) { - CAutoLock cAutoLock(&m_csCallback); - if(!m_pCallback) return; + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } - m_pCallback->OnProgress(progress); + m_pCallback->OnProgress(progress); } -void CVobSubFileRipper::Finished(bool fSucceeded) +void CVobSubFileRipper::Finished(bool bSucceeded) { - CAutoLock cAutoLock(&m_csCallback); - if(!m_pCallback) return; + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } - m_pCallback->OnFinished(fSucceeded); + m_pCallback->OnFinished(bSucceeded); } -#define ReadBEb(var) \ - f.Read(&((BYTE*)&var)[0], 1); \ - -#define ReadBEw(var) \ - f.Read(&((BYTE*)&var)[1], 1); \ - f.Read(&((BYTE*)&var)[0], 1); \ - -#define ReadBEdw(var) \ - f.Read(&((BYTE*)&var)[3], 1); \ - f.Read(&((BYTE*)&var)[2], 1); \ - f.Read(&((BYTE*)&var)[1], 1); \ - f.Read(&((BYTE*)&var)[0], 1); \ - bool CVobSubFileRipper::LoadIfo(CString fn) { - CString str; + CFileStatus status; + if (!CFileGetStatus(fn, status) || !status.m_size) { + Log(LOG_ERROR, _T("Invalid ifo")); + return false; + } - CFileStatus status; - if(!CFileGetStatus(fn, status) || !status.m_size) - { - Log(LOG_ERROR, _T("Invalid ifo")); - return(false); - } + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + Log(LOG_ERROR, _T("Cannot open ifo")); + return false; + } - CFile f; - if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite)) - { - Log(LOG_ERROR, _T("Cannot open ifo")); - return(false); - } + Log(LOG_INFO, _T("Opening ifo OK")); - Log(LOG_INFO, _T("Opening ifo OK")); + char hdr[13]; + f.Read(hdr, 12); + hdr[12] = 0; + if (strcmp(hdr, "DVDVIDEO-VTS")) { + Log(LOG_ERROR, _T("Not a Video Title Set IFO file!")); + return false; + } - char hdr[13]; - f.Read(hdr, 12); - hdr[12] = 0; - if(strcmp(hdr, "DVDVIDEO-VTS")) - { - Log(LOG_ERROR, _T("Not a Video Title Set IFO file!")); - return(false); - } + // lang ids - // lang ids + f.Seek(0x254, CFile::begin); - f.Seek(0x254, CFile::begin); + WORD ids[32]; + ZeroMemory(ids, sizeof(ids)); - WORD ids[32]; - memset(ids, 0, sizeof(ids)); + int len = 0; + ReadBEw(len); - int len = 0; - ReadBEw(len); + for (ptrdiff_t i = 0; i < len; i++) { + f.Seek(2, CFile::current); // 01 00 ? + ReadBEw(ids[i]); + if (ids[i] == 0) { + ids[i] = '--'; + } + f.Seek(2, CFile::current); // 00 00 ? + } - for(int i = 0; i < len; i++) - { - f.Seek(2, CFile::current); // 01 00 ? - ReadBEw(ids[i]); - if(ids[i] == 0) ids[i] = '--'; - f.Seek(2, CFile::current); // 00 00 ? - } + /* Video info */ - /* Video info */ + f.Seek(0x200, CFile::begin); + f.Read(&m_rd.vidinfo, 2); - f.Seek(0x200, CFile::begin); - f.Read(&m_rd.vidinfo, 2); + SIZE res[4][2] = { + {{720, 480}, {720, 576}}, + {{704, 480}, {704, 576}}, + {{352, 480}, {352, 576}}, + {{352, 240}, {352, 288}} + }; - SIZE res[4][2] = - { - {{720,480},{720,576}}, - {{704,480},{704,576}}, - {{352,480},{352,576}}, - {{352,240},{352,288}} - }; + m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system & 1]; - m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system&1]; + double rate = (m_rd.vidinfo.system == 0) ? 30.0 / 29.97 : 1.0; - double rate = (m_rd.vidinfo.system == 0) ? 30.0/29.97 : 1.0; + /* PGCs */ - /* PGCs */ + { + DWORD offset; - { - DWORD offset; + DWORD pgcpos; + f.Seek(0xc0 + 0x0c, CFile::begin); + ReadBEdw(pgcpos); + pgcpos *= 0x800; - DWORD pgcpos; - f.Seek(0xc0+0x0c, CFile::begin); - ReadBEdw(pgcpos); - pgcpos *= 0x800; + WORD nPGC; + f.Seek(pgcpos, CFile::begin); + ReadBEw(nPGC); - WORD nPGC; - f.Seek(pgcpos, CFile::begin); - ReadBEw(nPGC); + m_rd.pgcs.RemoveAll(); + m_rd.pgcs.SetCount(nPGC); - m_rd.pgcs.RemoveAll(); - m_rd.pgcs.SetCount(nPGC); + for (size_t i = 0; i < nPGC; i++) { + PGC& pgc = m_rd.pgcs[i]; - for(int i = 0; i < nPGC; i++) - { - PGC& pgc = m_rd.pgcs[i]; + f.Seek(pgcpos + 8 + i * 8 + 4, CFile::begin); + ReadBEdw(offset); + offset += pgcpos; - f.Seek(pgcpos + 8 + i*8 + 4, CFile::begin); - ReadBEdw(offset); - offset += pgcpos; + BYTE nProgs, nCells; + f.Seek(offset + 2, CFile::begin); + ReadBEb(nProgs); + ReadBEb(nCells); - BYTE nProgs, nCells; - f.Seek(offset + 2, CFile::begin); - ReadBEb(nProgs); - ReadBEb(nCells); + // - // + memcpy(pgc.ids, ids, sizeof(ids)); - memcpy(pgc.ids, ids, sizeof(ids)); + struct splanginfo { + BYTE res1, id1, id2, res2; + }; + splanginfo splinfo[32]; - struct splanginfo {BYTE res1, id1, id2, res2;}; - splanginfo splinfo[32]; + f.Seek(offset + 0x1c, CFile::begin); + f.Read(splinfo, 32 * 4); - f.Seek(offset + 0x1c, CFile::begin); - f.Read(splinfo, 32*4); + for (size_t j = 0; j < 32; j++) { + if (splinfo[j].id1 || splinfo[i].id2) { - for(int j = 0; j < 32; j++) - { - if(splinfo[j].id1 || splinfo[i].id2) - { - WORD tmpids[32]; - memset(tmpids, 0, sizeof(tmpids)); + for (j = 0; j < 32; j++) { + if (!(splinfo[j].res1 & 0x80)) { + break; + } - for(j = 0; j < 32; j++) - { - if(!(splinfo[j].res1 & 0x80)) break; + pgc.ids[splinfo[j].id1] = ids[j]; + pgc.ids[splinfo[j].id2] = ids[j]; + } - pgc.ids[splinfo[j].id1] = ids[j]; - pgc.ids[splinfo[j].id2] = ids[j]; - } + break; + } + } - break; - } - } - - // + // - f.Seek(offset + 0xa4, CFile::begin); + f.Seek(offset + 0xa4, CFile::begin); - for(int j = 0; j < 16; j++) - { - BYTE y, u, v, tmp; + for (size_t j = 0; j < 16; j++) { + BYTE y, u, v, tmp; - f.Read(&tmp, 1); - f.Read(&y, 1); - f.Read(&u, 1); - f.Read(&v, 1); + f.Read(&tmp, 1); + f.Read(&y, 1); + f.Read(&u, 1); + f.Read(&v, 1); - y = (y-16)*255/219; + y = (y - 16) * 255 / 219; pgc.pal[j].rgbRed = (BYTE)min(max(1.0*y + 1.4022*(u-128), 0), 255); pgc.pal[j].rgbGreen = (BYTE)min(max(1.0*y - 0.3456*(u-128) - 0.7145*(v-128), 0), 255); pgc.pal[j].rgbBlue = (BYTE)min(max(1.0*y + 1.7710*(v-128), 0) , 255); } - // + // - WORD progoff, celladdroff, vobcelloff; - f.Seek(offset + 0xe6, CFile::begin); - ReadBEw(progoff); - f.Seek(offset + 0xe8, CFile::begin); - ReadBEw(celladdroff); - f.Seek(offset + 0xea, CFile::begin); - ReadBEw(vobcelloff); + WORD progoff, celladdroff, vobcelloff; + f.Seek(offset + 0xe6, CFile::begin); + ReadBEw(progoff); + f.Seek(offset + 0xe8, CFile::begin); + ReadBEw(celladdroff); + f.Seek(offset + 0xea, CFile::begin); + ReadBEw(vobcelloff); - // + // CAtlArray progs; - progs.SetCount(nProgs); - f.Seek(offset + progoff, CFile::begin); - f.Read(progs.GetData(), nProgs); - - // - - pgc.angles[0].SetCount(nCells); - pgc.iSelAngle = 0; - - // - - f.Seek(offset + vobcelloff, CFile::begin); - for(int j = 0; j < nCells; j++) - { - ReadBEw(pgc.angles[0][j].vob); - ReadBEw(pgc.angles[0][j].cell); - } - - // - - DWORD tOffset = 0, tTotal = 0; - - int iAngle = 0; - - pgc.nAngles = 0; - - f.Seek(offset + celladdroff, CFile::begin); - for(int j = 0; j < nCells; j++) - { - BYTE b; - ReadBEb(b); - switch(b>>6) - { - case 0: iAngle = 0; break; // normal - case 1: iAngle = 1; break; // first angle block - case 2: iAngle++; break; // middle angle block - case 3: iAngle++; break; // last angle block (no more should follow) - } - pgc.angles[0][j].iAngle = iAngle; - pgc.nAngles = max(pgc.nAngles, iAngle); - - f.Seek(3, CFile::current); - ReadBEdw(pgc.angles[0][j].tTime); - ReadBEdw(pgc.angles[0][j].start); - f.Seek(8, CFile::current); - ReadBEdw(pgc.angles[0][j].end); - - float fps; - switch((pgc.angles[0][j].tTime>>6)&0x3) - { - default: - case 3: fps = 30; break; - case 1: fps = 25; break; - } - - int t = pgc.angles[0][j].tTime; - int hh = ((t>>28)&0xf)*10+((t>>24)&0xf); - int mm = ((t>>20)&0xf)*10+((t>>16)&0xf); - int ss = ((t>>12)&0xf)*10+((t>>8)&0xf); - int ms = (int)(1000.0 * (((t>>4)&0x3)*10+((t>>0)&0xf)) / fps); - pgc.angles[0][j].tTime = (DWORD)((((hh*60+mm)*60+ss)*1000+ms)*rate); - - // time discontinuity - if(b&0x02) tOffset = tTotal; - pgc.angles[0][j].fDiscontinuity = !!(b&0x02); - - pgc.angles[0][j].tTotal = tTotal; - pgc.angles[0][j].tOffset = tOffset; - - tTotal += pgc.angles[0][j].tTime; - } - - for(iAngle = 1; iAngle <= 9; iAngle++) - { - tOffset = tTotal = 0; - - for(int j = 0, k = 0; j < nCells; j++) - { - if(pgc.angles[0][j].iAngle != 0 - && pgc.angles[0][j].iAngle != iAngle) - continue; - - pgc.angles[iAngle].Add(pgc.angles[0][j]); - - if(pgc.angles[iAngle][k].fDiscontinuity) tOffset = tTotal; - - pgc.angles[iAngle][k].tTotal = tTotal; - pgc.angles[iAngle][k].tOffset = tOffset; - - tTotal += pgc.angles[iAngle][k].tTime; - - k++; - } - } - } - } + progs.SetCount(nProgs); + f.Seek(offset + progoff, CFile::begin); + f.Read(progs.GetData(), nProgs); + + // + + pgc.angles[0].SetCount(nCells); + pgc.iSelAngle = 0; + + // + + f.Seek(offset + vobcelloff, CFile::begin); + for (size_t j = 0; j < nCells; j++) { + ReadBEw(pgc.angles[0][j].vob); + ReadBEw(pgc.angles[0][j].cell); + } + + // + + DWORD tOffset = 0, tTotal = 0; + + int iAngle = 0; + + pgc.nAngles = 0; + + f.Seek(offset + celladdroff, CFile::begin); + for (size_t j = 0; j < nCells; j++) { + BYTE b; + ReadBEb(b); + switch (b >> 6) { + case 0: + iAngle = 0; + break; // normal + case 1: + iAngle = 1; + break; // first angle block + case 2: + iAngle++; + break; // middle angle block + case 3: + iAngle++; + break; // last angle block (no more should follow) + } + pgc.angles[0][j].iAngle = iAngle; + pgc.nAngles = max(pgc.nAngles, iAngle); + + f.Seek(3, CFile::current); + ReadBEdw(pgc.angles[0][j].tTime); + ReadBEdw(pgc.angles[0][j].start); + f.Seek(8, CFile::current); + ReadBEdw(pgc.angles[0][j].end); + + float fps; + switch ((pgc.angles[0][j].tTime >> 6) & 0x3) { + default: + case 3: + fps = 30; + break; + case 1: + fps = 25; + break; + } + + int t = pgc.angles[0][j].tTime; + int hh = ((t >> 28) & 0xf) * 10 + ((t >> 24) & 0xf); + int mm = ((t >> 20) & 0xf) * 10 + ((t >> 16) & 0xf); + int ss = ((t >> 12) & 0xf) * 10 + ((t >> 8) & 0xf); + int ms = (int)(1000.0 * (((t >> 4) & 0x3) * 10 + ((t >> 0) & 0xf)) / fps); + pgc.angles[0][j].tTime = (DWORD)((((hh * 60 + mm) * 60 + ss) * 1000 + ms) * rate); + + // time discontinuity + if (b & 0x02) { + tOffset = tTotal; + } + pgc.angles[0][j].bDiscontinuity = !!(b & 0x02); + + pgc.angles[0][j].tTotal = tTotal; + pgc.angles[0][j].tOffset = tOffset; + + tTotal += pgc.angles[0][j].tTime; + } + + for (iAngle = 1; iAngle <= 9; iAngle++) { + tOffset = tTotal = 0; + + for (size_t j = 0, k = 0; j < nCells; j++) { + if (pgc.angles[0][j].iAngle != 0 + && pgc.angles[0][j].iAngle != iAngle) { + continue; + } + + pgc.angles[iAngle].Add(pgc.angles[0][j]); + + if (pgc.angles[iAngle][k].bDiscontinuity) { + tOffset = tTotal; + } + + pgc.angles[iAngle][k].tTotal = tTotal; + pgc.angles[iAngle][k].tOffset = tOffset; + + tTotal += pgc.angles[iAngle][k].tTime; + + k++; + } + } + } + } Log(LOG_INFO, _T("Parsing ifo OK")); - return(true); + return true; } bool CVobSubFileRipper::LoadVob(CString fn) { - Log(LOG_INFO, _T("Searching vobs...")); -/* - CAtlList m_vobs; - - fn = fn.Left(fn.ReverseFind('.')+1); - fn.TrimRight(_T(".0123456789")); - for(int i = 0; i < 100; i++) - { - CString vob; - vob.Format(_T("%s%d.vob"), fn, i); - - CFileStatus status; - if(!(CFileGetStatus(vob, status) && status.m_size)) - { - if(i > 0) break; - else continue; - } - - if(status.m_size&0x7ff) - { - Log(LOG_ERROR, _T("Length of %s is not n*2048!"), vob); - m_vobs.RemoveAll(); - break; - } - - CString str = _T("Found ") + vob; - - if(i == 0) - { - str += _T(" (skipping, if not a menu vob rename it)"); - } - else - { - m_vobs.AddTail(vob); - } - - Log(LOG_INFO, str); - } - - if(m_vobs.GetCount() <= 0) - { - Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn); - return(false); - } -*/ - CAtlList vobs; - if(!m_vob.Open(fn, vobs/*m_vobs*/)) - { - Log(LOG_ERROR, _T("Cannot open vob sequence")); - return(false); - } - - if(vobs.GetCount() <= 0) - { - Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn); - return(false); - } - - POSITION pos = vobs.GetHeadPosition(); - while(pos) Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos)); - - if(m_vob.IsDVD()) - { - Log(LOG_INFO, _T("DVD detected...")); - - BYTE key[5]; - - if(m_vob.HasDiscKey(key)) - Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); - else - Log(LOG_WARNING, _T("Couldn't get the disc key")); - - if(m_vob.HasTitleKey(key)) - Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); - else - Log(LOG_WARNING, _T("Couldn't get the title key")); - - BYTE buff[2048]; - - m_vob.Seek(0); - if(!m_vob.Read(buff)) - { - Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!")); - return(false); - } - m_vob.Seek(0); - } - - return(true); + Log(LOG_INFO, _T("Searching vobs...")); + + CAtlList vobs; + if (!m_vob.Open(fn, vobs/*m_vobs*/)) { + Log(LOG_ERROR, _T("Cannot open vob sequence")); + return false; + } + + if (vobs.GetCount() <= 0) { + Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn); + return false; + } + + POSITION pos = vobs.GetHeadPosition(); + while (pos) { + Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos)); + } + + if (m_vob.IsDVD()) { + Log(LOG_INFO, _T("DVD detected...")); + + BYTE key[5]; + + if (m_vob.HasDiscKey(key)) { + Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); + } else { + Log(LOG_WARNING, _T("Couldn't get the disc key")); + } + + if (m_vob.HasTitleKey(key)) { + Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); + } else { + Log(LOG_WARNING, _T("Couldn't get the title key")); + } + + BYTE buff[2048]; + + m_vob.Seek(0); + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!")); + return false; + } + m_vob.Seek(0); + } + + return true; } DWORD CVobSubFileRipper::ThreadProc() -{ - SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL); - - while(1) - { - DWORD cmd = GetRequest(); - - m_fThreadActive = true; - - switch(cmd) - { - case CMD_EXIT: - Reply(S_OK); - return 0; - - case CMD_INDEX: - Reply(S_OK); - { - m_fIndexing = true; - bool fSucceeded = Create(); - m_fIndexing = false; - Finished(fSucceeded); - } - break; - - default: - Reply(E_FAIL); - return -1; - } - - m_fBreakThread = false; - m_fThreadActive = false; - } - - return 1; +{ + SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL); + + for (;;) { + DWORD cmd = GetRequest(); + + m_bThreadActive = true; + + switch (cmd) { + case CMD_EXIT: + Reply(S_OK); + return 0; + + case CMD_INDEX: + Reply(S_OK); + { + m_bIndexing = true; + bool bSucceeded = Create(); + m_bIndexing = false; + Finished(bSucceeded); + } + break; + + default: + Reply((DWORD)E_FAIL); + return -1; + } + + m_bBreakThread = false; + m_bThreadActive = false; + } + + return 1; } static int SubPosSortProc(const void* e1, const void* e2) { - return((int)(((CVobSubFile::SubPos*)e1)->start - ((CVobSubFile::SubPos*)e2)->start)); + return ((int)(((CVobSubFile::SubPos*)e1)->start - ((CVobSubFile::SubPos*)e2)->start)); } bool CVobSubFileRipper::Create() { - CAutoLock cAutoLock(&m_csAccessLock); - - if(m_rd.iSelPGC < 0 || m_rd.iSelPGC >= m_rd.pgcs.GetCount()) - { - Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC); - return(false); - } - - PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; - - if(pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].GetCount() == 0) - { - Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle); - return(false); - } - - CAtlArray& angle = pgc.angles[pgc.iSelAngle]; - - if(m_rd.selids.GetCount() == 0 && !m_rd.fClosedCaption) - { - Log(LOG_ERROR, _T("No valid stream set to be extacted!")); - return(false); - } - - if(m_rd.selvcs.GetCount() == 0) - { - Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!")); - return(false); - } - - Log(LOG_INFO, _T("Indexing...")); - - // initalize CVobSubFile - CVobSubFile::Close(); - InitSettings(); - m_title = m_outfn; - m_size = m_rd.vidsize; - TrimExtension(m_title); - memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal)); - m_sub.SetLength(0); - - CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw")); - - CVobDec vd; - - __int64 SCR, PTS, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0; - int vob = 0, cell = 0; - bool fDiscontinuity = false, fDiscontinuityFixApplied = false, fNavpackFound = false; - - int PTSframeoffset = 0, minPTSframeoffset = 0; - - if(m_rd.fResetTime) - { - for(size_t i = 0; i < angle.GetCount() && ((angle[i].vob<<16)|angle[i].cell) != m_rd.selvcs[0]; i++) - tStart += angle[i].tTime; - - Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), - tStart, m_rd.selvcs[0]>>16, m_rd.selvcs[0]&0xffff); - } - - CAtlMap selvcmap; - selvcmap.RemoveAll(); - for(size_t i = 0; i < m_rd.selvcs.GetCount(); i++) - selvcmap[m_rd.selvcs[i]] = 90000; - - CAtlArray chunks, foundchunks, loadedchunks; - - if(m_vob.IsDVD()) - { - Log(LOG_INFO, _T("Indexing mode: DVD")); - - for(size_t i = 0; i < angle.GetCount(); i++) - { - DWORD vc = (angle[i].vob<<16)|angle[i].cell; - if(!selvcmap.Lookup(vc)) - continue; - - vcchunk c = {2048i64*angle[i].start, 2048i64*angle[i].end+2048, vc}; - chunks.Add(c); - - Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), - angle[i].start, angle[i].end, angle[i].vob, angle[i].cell); - } - } - else if(LoadChunks(loadedchunks)) - { - Log(LOG_INFO, _T("Indexing mode: File")); - - for(size_t i = 0; i < loadedchunks.GetCount(); i++) - { - DWORD vcid = loadedchunks[i].vc; - if(!selvcmap.Lookup(vcid)) - continue; - - chunks.Add(loadedchunks[i]); - } - - Log(LOG_INFO, _T(".chunk file loaded")); - } - else - { - Log(LOG_INFO, _T("Indexing mode: File")); - - chunks.RemoveAll(); - vcchunk c = {0, 2048i64*m_vob.GetLength(), 0}; - chunks.Add(c); - } - - __int64 sizedone = 0, sizetotal = 0; - for(size_t i = 0; i < chunks.GetCount(); i++) - sizetotal += chunks[i].end - chunks[i].start; - - for(size_t i = 0; !m_fBreakThread && i < chunks.GetCount(); i++) - { - __int64 curpos = chunks[i].start, endpos = chunks[i].end; - - vcchunk curchunk = {curpos, curpos, chunks[i].vc}; - - for(m_vob.Seek((int)(curpos/2048)); !m_fBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048) - { - if(!(curpos&0x7ffff)) - Progress(1.0 * sizedone / sizetotal); - - static BYTE buff[2048]; - - if(!m_vob.Read(buff)) - { - Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); - return(false); - } + CAutoLock cAutoLock(&m_csAccessLock); - curchunk.end = curpos; + if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { + Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC); + return false; + } - if(buff[0x14] & 0x30) - { - if(!vd.m_fFoundKey) - { - Log(LOG_INFO, _T("Encrypted sector found, searching key...")); + PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; - __int64 savepos = curpos; + if (pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].IsEmpty()) { + Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle); + return false; + } - m_vob.Seek(0); - for(__int64 pos = 0; !m_fBreakThread && pos < endpos; pos += 2048) - { - if(!m_vob.Read(buff)) - { - Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); - return(false); - } + CAtlArray& angle = pgc.angles[pgc.iSelAngle]; - if(vd.FindKey(buff)) - break; - } + if (m_rd.selids.IsEmpty() && !m_rd.bClosedCaption) { + Log(LOG_ERROR, _T("No valid stream set to be extacted!")); + return false; + } - if(m_fBreakThread) - break; + if (m_rd.selvcs.IsEmpty()) { + Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!")); + return false; + } - if(!vd.m_fFoundKey) - { - Log(LOG_ERROR, _T("Key not found, can't decrypt!")); - return(false); - } + Log(LOG_INFO, _T("Indexing...")); - Log(LOG_INFO, _T("Key found, continuing extraction...")); + // initalize CVobSubFile + CVobSubFile::Close(); + InitSettings(); + m_title = m_outfn; + m_size = m_rd.vidsize; + TrimExtension(m_title); + memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal)); + m_sub.SetLength(0); - m_vob.Seek((int)((curpos = savepos)/2048)); - m_vob.Read(buff); - } + CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw")); - vd.Decrypt(buff); - } + CVobDec vd; - if(*((DWORD*)&buff[0]) != 0xba010000) - { - Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos/2048)); + __int64 PTS = 0, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0; + int vob = 0, cell = 0; + bool bDiscontinuity = false, bDiscontinuityFixApplied = false, bNavpackFound = false; - if(AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO) - { - Log(LOG_ERROR, _T("Terminated!")); - return(false); - } - } - - SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30 - | __int64(buff[0x04] & 0x03) << 28 - | __int64(buff[0x05]) << 20 - | (__int64(buff[0x06] & 0xf8) >> 3) << 15 - | __int64(buff[0x06] & 0x03) << 13 - | __int64(buff[0x07]) << 5 - | (__int64(buff[0x08] & 0xf8) >> 3) << 0; - - bool hasPTS = false; - - if((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000) - && buff[0x15] & 0x80) - { - PTS = (__int64)(buff[0x17] & 0x0e) << 29 // 32-30 (+marker) - | ((__int64)(buff[0x18]) << 22) // 29-22 - | ((__int64)(buff[0x19] & 0xfe) << 14) // 21-15 (+marker) - | ((__int64)(buff[0x1a]) << 7) // 14-07 - | ((__int64)(buff[0x1b]) >> 1); // 06-00 (+marker) - - hasPTS = true; - } + int PTSframeoffset = 0, minPTSframeoffset = 0; - if(*((DWORD*)&buff[0x0e]) == 0xbb010000) - { - fNavpackFound = true; - - if(vob == buff[0x420] && cell == buff[0x422]) - continue; - - vob = buff[0x420]; - cell = buff[0x422]; - - tOffset = tTotal = 0; - - for(size_t i = 0; i < angle.GetCount(); i++) - { - if(angle[i].vob == vob && angle[i].cell == cell) - { - tPrevOffset = tOffset; - tOffset = (__int64)angle[i].tOffset; - tTotal = (__int64)angle[i].tTotal; - fDiscontinuity = angle[i].fDiscontinuity; - fDiscontinuityFixApplied = false; - break; - } - } - - if(curchunk.vc != ((vob<<16)|cell)) - { - if(curchunk.vc != 0) foundchunks.Add(curchunk); - curchunk.start = curchunk.end = curpos; - curchunk.vc = (vob<<16)|cell; - } - - CString str, str2; - str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos/2048)); - UINT vcid = (vob<<16)|cell; - if(!selvcmap.Lookup(vcid, minPTSframeoffset)) str2 = _T(", skipping"); - else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), - tTotal, tOffset, -tStart, (int)fDiscontinuity); - Log(LOG_INFO, str + str2); - } + if (m_rd.bResetTime) { + for (size_t i = 0; i < angle.GetCount() && (UINT)((angle[i].vob << 16) | angle[i].cell) != m_rd.selvcs[0]; i++) { + tStart += angle[i].tTime; + } - DWORD vcid = (vob<<16)|cell; - if(!selvcmap.Lookup(vcid, minPTSframeoffset)) - continue; - - if(hasPTS && fDiscontinuity && !fDiscontinuityFixApplied) - { - __int64 tDiff = tOffset - tPrevOffset; - if(tDiff > 0 && tDiff < (PTS/90+1000)) - { - CString str; - str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff); - Log(LOG_INFO, str); - - tStart += tDiff; - } - fDiscontinuityFixApplied = true; - } + Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), + tStart, m_rd.selvcs[0] >> 16, m_rd.selvcs[0] & 0xffff); + } - if(*(DWORD*)&buff[0x0e] == 0xe0010000) - { - if(fDiscontinuity) - { - if(PTS < minPTSframeoffset) - { - selvcmap[vcid] = PTSframeoffset = PTS; - } + CAtlMap selvcmap; + selvcmap.RemoveAll(); + for (size_t i = 0; i < m_rd.selvcs.GetCount(); i++) { + selvcmap[m_rd.selvcs[i]] = 90000; + } - fDiscontinuity = false; - } + CAtlArray chunks, foundchunks, loadedchunks; - if(m_rd.fClosedCaption) - ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart); - } - else if(*(DWORD*)&buff[0x0e] == 0xbd010000) - { - BYTE id = buff[0x17 + buff[0x16]], iLang = id&0x1f; - - if((id & 0xe0) == 0x20 && m_rd.selids.Lookup(iLang)) - { - if(hasPTS) - { - SubPos sb; - sb.filepos = m_sub.GetPosition(); - sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart; - sb.vobid = (char)vob; - sb.cellid = (char)cell; - sb.celltimestamp = tTotal; - sb.fValid = true; - m_langs[iLang].subpos.Add(sb); - } - - m_sub.Write(buff, 2048); - } - } - } - - if(curchunk.vc != ((vob<<16)|cell)) - { - if(curchunk.vc != 0) foundchunks.Add(curchunk); - curchunk.start = curchunk.end = curpos; - curchunk.vc = (vob<<16)|cell; - } - } - - if(sizedone < sizetotal) - { - Log(LOG_ERROR, _T("Indexing terminated before reaching the end!")); - Progress(0); - return(false); - } - - if(!fNavpackFound) - { - Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)")); - if(!m_vob.IsDVD()) Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets.")); - Progress(0); - return(false); - } - - Log(LOG_INFO, _T("Indexing finished")); - Progress(1); - - for(int i = 0; i < 32; i++) - { - if(m_iLang == -1 && m_langs[i].subpos.GetCount() > 0) m_iLang = i; - m_langs[i].id = pgc.ids[i]; - m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id); - - CAtlArray& sp = m_langs[i].subpos; - qsort(sp.GetData(), sp.GetCount(), sizeof(SubPos), SubPosSortProc); - - if(m_rd.fForcedOnly) - { - Log(LOG_INFO, _T("Searching for forced subs...")); - Progress(0); - - for(int j = 0, len = sp.GetCount(); j < len; j++) - { - Progress(1.0 * j / len); - - sp[j].fValid = false; - int packetsize = 0, datasize = 0; - if(BYTE* buff = GetPacket(j, packetsize, datasize, i)) - { - m_img.GetPacketInfo(buff, packetsize, datasize); - sp[j].fValid = m_img.fForced; - delete [] buff; - } - } + if (m_vob.IsDVD()) { + Log(LOG_INFO, _T("Indexing mode: DVD")); - Progress(1); - } - } + for (size_t i = 0; i < angle.GetCount(); i++) { + DWORD vc = (angle[i].vob << 16) | angle[i].cell; + if (!selvcmap.Lookup(vc)) { + continue; + } - Log(LOG_INFO, _T("Saving files...")); + vcchunk c = {2048i64 * angle[i].start, 2048i64 * angle[i].end + 2048, vc}; + chunks.Add(c); + + Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), + angle[i].start, angle[i].end, angle[i].vob, angle[i].cell); + } + } else if (LoadChunks(loadedchunks)) { + Log(LOG_INFO, _T("Indexing mode: File")); - if(m_iLang != -1) - { - if(!Save(m_title)) - { - Log(LOG_ERROR, _T("Could not save output files!")); - return(false); - } - } + for (size_t i = 0; i < loadedchunks.GetCount(); i++) { + DWORD vcid = loadedchunks[i].vc; + if (!selvcmap.Lookup(vcid)) { + continue; + } + + chunks.Add(loadedchunks[i]); + } - Log(LOG_INFO, _T("Subtitles saved")); + Log(LOG_INFO, _T(".chunk file loaded")); + } else { + Log(LOG_INFO, _T("Indexing mode: File")); - if(!m_vob.IsDVD() && loadedchunks.GetCount() == 0) - { - if(SaveChunks(foundchunks)) - { - Log(LOG_INFO, _T(".chunk file saved")); - } - } + chunks.RemoveAll(); + vcchunk c = {0, 2048i64 * m_vob.GetLength(), 0}; + chunks.Add(c); + } - Log(LOG_INFO, _T("Done!")); + __int64 sizedone = 0, sizetotal = 0; + for (size_t i = 0; i < chunks.GetCount(); i++) { + sizetotal += chunks[i].end - chunks[i].start; + } - return(true); + for (size_t i = 0; !m_bBreakThread && i < chunks.GetCount(); i++) { + __int64 curpos = chunks[i].start, endpos = chunks[i].end; + + vcchunk curchunk = {curpos, curpos, chunks[i].vc}; + + for (m_vob.Seek((int)(curpos / 2048)); !m_bBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048) { + if (!(curpos & 0x7ffff)) { + Progress(1.0 * sizedone / sizetotal); + } + + static BYTE buff[2048]; + + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); + return false; + } + + curchunk.end = curpos; + + if (buff[0x14] & 0x30) { + if (!vd.m_fFoundKey) { + Log(LOG_INFO, _T("Encrypted sector found, searching key...")); + + __int64 savepos = curpos; + + m_vob.Seek(0); + for (__int64 pos = 0; !m_bBreakThread && pos < endpos; pos += 2048) { + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); + return false; + } + + if (vd.FindKey(buff)) { + break; + } + } + + if (m_bBreakThread) { + break; + } + + if (!vd.m_fFoundKey) { + Log(LOG_ERROR, _T("Key not found, can't decrypt!")); + return false; + } + + Log(LOG_INFO, _T("Key found, continuing extraction...")); + + m_vob.Seek((int)((curpos = savepos) / 2048)); + m_vob.Read(buff); + } + + vd.Decrypt(buff); + } + + if (*((DWORD*)&buff[0]) != 0xba010000) { + Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos / 2048)); + + if (AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO) { + Log(LOG_ERROR, _T("Terminated!")); + return false; + } + } + + /*__int64 SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30 + | __int64(buff[0x04] & 0x03) << 28 + | __int64(buff[0x05]) << 20 + | (__int64(buff[0x06] & 0xf8) >> 3) << 15 + | __int64(buff[0x06] & 0x03) << 13 + | __int64(buff[0x07]) << 5 + | (__int64(buff[0x08] & 0xf8) >> 3) << 0;*/ + + bool hasPTS = false; + + if ((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000) + && buff[0x15] & 0x80) { + PTS = (__int64)(buff[0x17] & 0x0e) << 29 // 32-30 (+marker) + | ((__int64)(buff[0x18]) << 22) // 29-22 + | ((__int64)(buff[0x19] & 0xfe) << 14) // 21-15 (+marker) + | ((__int64)(buff[0x1a]) << 7) // 14-07 + | ((__int64)(buff[0x1b]) >> 1); // 06-00 (+marker) + + hasPTS = true; + } + + if (*((DWORD*)&buff[0x0e]) == 0xbb010000) { + bNavpackFound = true; + + if (vob == buff[0x420] && cell == buff[0x422]) { + continue; + } + + vob = buff[0x420]; + cell = buff[0x422]; + + tOffset = tTotal = 0; + + for (size_t j = 0; j < angle.GetCount(); j++) { + if (angle[j].vob == vob && angle[j].cell == cell) { + tPrevOffset = tOffset; + tOffset = (__int64)angle[j].tOffset; + tTotal = (__int64)angle[j].tTotal; + bDiscontinuity = angle[j].bDiscontinuity; + bDiscontinuityFixApplied = false; + break; + } + } + + if (curchunk.vc != (DWORD)((vob << 16) | cell)) { + if (curchunk.vc != 0) { + foundchunks.Add(curchunk); + } + curchunk.start = curchunk.end = curpos; + curchunk.vc = (vob << 16) | cell; + } + + CString str, str2; + str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos / 2048)); + UINT vcid = (vob << 16) | cell; + if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { + str2 = _T(", skipping"); + } else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), + tTotal, tOffset, -tStart, (int)bDiscontinuity); + Log(LOG_INFO, str + str2); + } + + DWORD vcid = (vob << 16) | cell; + if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { + continue; + } + + if (hasPTS && bDiscontinuity && !bDiscontinuityFixApplied) { + __int64 tDiff = tOffset - tPrevOffset; + if (tDiff > 0 && tDiff < (PTS / 90 + 1000)) { + CString str; + str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff); + Log(LOG_INFO, str); + + tStart += tDiff; + } + bDiscontinuityFixApplied = true; + } + + if (*(DWORD*)&buff[0x0e] == 0xe0010000) { + if (bDiscontinuity) { + if (PTS < minPTSframeoffset) { + selvcmap[vcid] = PTSframeoffset = (int)PTS; + } + + bDiscontinuity = false; + } + + if (m_rd.bClosedCaption) { + ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart); + } + } else if (*(DWORD*)&buff[0x0e] == 0xbd010000) { + BYTE id = buff[0x17 + buff[0x16]], iLang = id & 0x1f; + + if ((id & 0xe0) == 0x20 && m_rd.selids.Lookup(iLang)) { + if (hasPTS) { + SubPos sb; + sb.filepos = m_sub.GetPosition(); + sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart; + sb.vobid = (char)vob; + sb.cellid = (char)cell; + sb.celltimestamp = tTotal; + sb.fValid = true; + m_langs[iLang].subpos.Add(sb); + } + + m_sub.Write(buff, 2048); + } + } + } + + if (curchunk.vc != (DWORD)((vob << 16) | cell)) { + if (curchunk.vc != 0) { + foundchunks.Add(curchunk); + } + curchunk.start = curchunk.end = curpos; + curchunk.vc = (vob << 16) | cell; + } + } + + if (sizedone < sizetotal) { + Log(LOG_ERROR, _T("Indexing terminated before reaching the end!")); + Progress(0); + return false; + } + + if (!bNavpackFound) { + Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)")); + if (!m_vob.IsDVD()) { + Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets.")); + } + Progress(0); + return false; + } + + Log(LOG_INFO, _T("Indexing finished")); + Progress(1); + + for (size_t i = 0; i < m_langs.size(); i++) { + if (m_iLang == -1 && !m_langs[i].subpos.IsEmpty()) { + m_iLang = i; + } + m_langs[i].id = pgc.ids[i]; + m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id); + + CAtlArray& sp = m_langs[i].subpos; + qsort(sp.GetData(), sp.GetCount(), sizeof(SubPos), SubPosSortProc); + + if (m_rd.fForcedOnly) { + Log(LOG_INFO, _T("Searching for forced subs...")); + Progress(0); + + for (size_t j = 0, len = sp.GetCount(); j < len; j++) { + Progress(1.0 * j / len); + + sp[j].fValid = false; + size_t packetSize = 0, dataSize = 0; + if (BYTE* buff = GetPacket(j, packetSize, dataSize, i)) { + m_img.GetPacketInfo(buff, packetSize, dataSize); + sp[j].fValid = m_img.fForced; + delete [] buff; + } + } + + Progress(1); + } + } + + Log(LOG_INFO, _T("Saving files...")); + + if (m_iLang != -1) { + if (!Save(m_title)) { + Log(LOG_ERROR, _T("Could not save output files!")); + return false; + } + } + + Log(LOG_INFO, _T("Subtitles saved")); + + if (!m_vob.IsDVD() && loadedchunks.IsEmpty()) { + if (SaveChunks(foundchunks)) { + Log(LOG_INFO, _T(".chunk file saved")); + } + } + + Log(LOG_INFO, _T("Done!")); + + return true; } static const DWORD s_version = 1; bool CVobSubFileRipper::LoadChunks(CAtlArray& chunks) { - CFile f; - - CString fn = m_infn; - TrimExtension(fn); - fn += _T(".chunks"); - - DWORD chksum = 0, chunklen, version; - __int64 voblen; - - if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite)) - return(false); - f.Read(&version, sizeof(version)); - if(version == 1) - { - f.Read(&chksum, sizeof(chksum)); - f.Read(&voblen, sizeof(voblen)); - f.Read(&chunklen, sizeof(chunklen)); - chunks.SetCount(chunklen); - f.Read(chunks.GetData(), sizeof(vcchunk)*chunks.GetCount()); - } - f.Close(); - - if(voblen != m_vob.GetLength()) - { - chunks.RemoveAll(); - return(false); - } - - if(!f.Open(m_infn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite)) - return(false); - DWORD dw, chksum2 = 0; - while(f.Read(&dw, sizeof(dw)) == sizeof(dw)) chksum2 += dw; - f.Close(); - - if(chksum != chksum2) - { - chunks.RemoveAll(); - return(false); - } - - return(true); + CFile f; + + CString fn = m_infn; + TrimExtension(fn); + fn += _T(".chunks"); + + DWORD chksum = 0, chunklen, version; + __int64 voblen = 0; + + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + f.Read(&version, sizeof(version)); + if (version == 1) { + f.Read(&chksum, sizeof(chksum)); + f.Read(&voblen, sizeof(voblen)); + f.Read(&chunklen, sizeof(chunklen)); + chunks.SetCount(chunklen); + f.Read(chunks.GetData(), UINT(sizeof(vcchunk)*chunks.GetCount())); + } + f.Close(); + + if (voblen != m_vob.GetLength()) { + chunks.RemoveAll(); + return false; + } + + if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + DWORD dw, chksum2 = 0; + while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { + chksum2 += dw; + } + f.Close(); + + if (chksum != chksum2) { + chunks.RemoveAll(); + return false; + } + + return true; } bool CVobSubFileRipper::SaveChunks(CAtlArray& chunks) { - CFile f; - - CString fn = m_infn; - TrimExtension(fn); - fn += _T(".chunks"); - - DWORD chksum = 0, chunklen = chunks.GetCount(); - __int64 voblen = m_vob.GetLength(); - - if(!f.Open(m_infn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite)) - return(false); - DWORD dw; - while(f.Read(&dw, sizeof(dw)) == sizeof(dw)) chksum += dw; - f.Close(); - - if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite)) - return(false); - f.Write(&s_version, sizeof(s_version)); - f.Write(&chksum, sizeof(chksum)); - f.Write(&voblen, sizeof(voblen)); - f.Write(&chunklen, sizeof(chunklen)); - f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen); - f.Close(); - - return(true); + CFile f; + + CString fn = m_infn; + TrimExtension(fn); + fn += _T(".chunks"); + + DWORD chksum = 0, chunklen = (DWORD)chunks.GetCount(); + __int64 voblen = m_vob.GetLength(); + + if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + DWORD dw; + while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { + chksum += dw; + } + f.Close(); + + if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + return false; + } + f.Write(&s_version, sizeof(s_version)); + f.Write(&chksum, sizeof(chksum)); + f.Write(&voblen, sizeof(voblen)); + f.Write(&chunklen, sizeof(chunklen)); + f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen); + f.Close(); + + return true; } // IVSFRipper STDMETHODIMP CVobSubFileRipper::SetCallBack(IVSFRipperCallback* pCallback) { - CAutoLock cAutoLock(&m_csCallback); - m_pCallback = pCallback; - return S_OK; + CAutoLock cAutoLock(&m_csCallback); + m_pCallback = pCallback; + return S_OK; } STDMETHODIMP CVobSubFileRipper::LoadParamFile(CString fn) { - CAutoLock cAutoLock(&m_csAccessLock); - - m_rd.Reset(); - - CStdioFile f; - if(!f.Open(fn, CFile::modeRead|CFile::typeText)) - return E_FAIL; - - TCHAR langid[256]; - - enum {P_INPUT, P_OUTPUT, P_PGC, P_ANGLE, P_LANGS, P_OPTIONS}; - int phase = P_INPUT; - - CString line; - while(f.ReadString(line)) - { - if(line.Trim().IsEmpty() || line[0] == '#') continue; - - if(phase == P_INPUT) - { - if(S_OK != SetInput(line)) break; - phase = P_OUTPUT; - } - else if(phase == P_OUTPUT) - { - if(S_OK != SetOutput(line)) break; - phase = P_PGC; - } - else if(phase == P_PGC) - { - m_rd.iSelPGC = _tcstol(line, NULL, 10)-1; - if(m_rd.iSelPGC < 0 || m_rd.iSelPGC >= m_rd.pgcs.GetCount()) break; - phase = P_ANGLE; - } - else if(phase == 3) - { - PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; - - pgc.iSelAngle = _tcstol(line, NULL, 10); - if(pgc.iSelAngle < 0 || pgc.iSelAngle > max(1, pgc.nAngles) || pgc.iSelAngle > 9) break; - - CAtlArray& angle = pgc.angles[pgc.iSelAngle]; - - if(line.Find('v') >= 0) - { - int vob = 0, cell = 0; - - line += ' '; - - TCHAR* s = (LPTSTR)(LPCTSTR)line; - TCHAR* e = s + line.GetLength(); - while(s < e) - { - if(*s == 'v' || s == e-1) - { - s++; - if(vob != 0 && cell == 0) - { - for(size_t i = 0; i < angle.GetCount(); i++) - { - if(angle[i].vob == vob) - m_rd.selvcs.Add((angle[i].vob<<16)|angle[i].cell); - } - } - - vob = _tcstol(s, &s, 10); - cell = 0; - } - else if(*s == 'c' && vob > 0) - { - s++; - cell = _tcstol(s, &s, 10); - - for(size_t i = 0; i < angle.GetCount(); i++) - { - if(angle[i].vob == vob && angle[i].cell == cell) - { - m_rd.selvcs.Add((vob<<16)|cell); - break; - } - } - } - else - { - s++; - } - } - } - else - { - for(size_t i = 0; i < angle.GetCount(); i++) - m_rd.selvcs.Add((angle[i].vob<<16)|angle[i].cell); - } - - phase = P_LANGS; - } - else if(phase == 4) - { - if(!line.CompareNoCase(_T("ALL"))) - { - for(int i = 0; i < 32; i++) m_rd.selids[i] = true; - m_rd.fClosedCaption = true; - phase = P_OPTIONS; - } - else - { - line += ' '; - - while(line.GetLength() > 0) - { - int n = line.Find(_T(" ")); - - CString lang = line.Left(n); - - line = line.Mid(n); - line.TrimLeft(); - - n = 0; - - int langnum; - - if(_istdigit(lang[0])) - { - n = _stscanf(lang, _T("%d"), &langnum); - if(n != 1) break; - - m_rd.selids[langnum] = true; - } - else if(_istalpha(lang[0])) - { - n = _stscanf(lang, _T("%s"), langid); - if(n != 1) break; - - int id = (langid[0] << 8) + langid[1]; - - if(id == 'cc') - { - m_rd.fClosedCaption = true; - } - else - { - m_rd.selids[id] = true; - } - } - else break; - - if(n != 1) break; - } - - if((m_rd.selids.GetCount() > 0 || m_rd.fClosedCaption) && line.IsEmpty()) - phase = P_OPTIONS; - } - } - else if(phase == 5 && !line.CompareNoCase(_T("CLOSE"))) - m_rd.fClose = true; - else if(phase == 5 && !line.CompareNoCase(_T("BEEP"))) - m_rd.fBeep = true; - else if(phase == 5 && !line.CompareNoCase(_T("RESETTIME"))) - m_rd.fResetTime = true; - else if(phase == 5 && !line.CompareNoCase(_T("FORCEDONLY"))) - m_rd.fForcedOnly = true; - else if(phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS"))) - m_rd.fCloseIgnoreError = true; - - } - - m_rd.fAuto = true; - - return phase == P_OPTIONS ? S_OK : E_FAIL; + CAutoLock cAutoLock(&m_csAccessLock); + + m_rd.Reset(); + + CStdioFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeText)) { + return E_FAIL; + } + + TCHAR langid[256]; + + enum { + P_INPUT, + P_OUTPUT, + P_PGC, + P_ANGLE, + P_LANGS, + P_OPTIONS + }; + int phase = P_INPUT; + + CString line; + while (f.ReadString(line)) { + if (line.Trim().IsEmpty() || line[0] == '#') { + continue; + } + + if (phase == P_INPUT) { + if (S_OK != SetInput(line)) { + break; + } + phase = P_OUTPUT; + } else if (phase == P_OUTPUT) { + if (S_OK != SetOutput(line)) { + break; + } + phase = P_PGC; + } else if (phase == P_PGC) { + m_rd.iSelPGC = _tcstol(line, nullptr, 10) - 1; + if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { + break; + } + phase = P_ANGLE; + } else if (phase == 3) { + PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; + + pgc.iSelAngle = _tcstol(line, nullptr, 10); + if (pgc.iSelAngle < 0 || pgc.iSelAngle > max(1, pgc.nAngles) || pgc.iSelAngle > 9) { + break; + } + + CAtlArray& angle = pgc.angles[pgc.iSelAngle]; + + if (line.Find('v') >= 0) { + int vob = 0, cell = 0; + + line += ' '; + + TCHAR* s = (LPTSTR)(LPCTSTR)line; + TCHAR* e = s + line.GetLength(); + while (s < e) { + if (*s == 'v' || s == e - 1) { + s++; + if (vob != 0 && cell == 0) { + for (size_t i = 0; i < angle.GetCount(); i++) { + if (angle[i].vob == vob) { + m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); + } + } + } + + vob = _tcstol(s, &s, 10); + cell = 0; + } else if (*s == 'c' && vob > 0) { + s++; + cell = _tcstol(s, &s, 10); + + for (size_t i = 0; i < angle.GetCount(); i++) { + if (angle[i].vob == vob && angle[i].cell == cell) { + m_rd.selvcs.Add((vob << 16) | cell); + break; + } + } + } else { + s++; + } + } + } else { + for (size_t i = 0; i < angle.GetCount(); i++) { + m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); + } + } + + phase = P_LANGS; + } else if (phase == 4) { + if (!line.CompareNoCase(_T("ALL"))) { + for (BYTE i = 0; i < 32; i++) { + m_rd.selids[i] = true; + } + m_rd.bClosedCaption = true; + phase = P_OPTIONS; + } else { + line += ' '; + + while (!line.IsEmpty()) { + int n = line.Find(_T(" ")); + + CString lang = line.Left(n); + + line = line.Mid(n); + line.TrimLeft(); + + n = 0; + if (_istdigit(lang[0])) { + int langnum; + n = _stscanf_s(lang, _T("%d"), &langnum); + if (n != 1) { + break; + } + + m_rd.selids[(BYTE)langnum] = true; + } else if (_istalpha(lang[0])) { + n = _stscanf_s(lang, _T("%s"), langid, _countof(langid)); + if (n != 1) { + break; + } + + int id = (langid[0] << 8) + langid[1]; + + if (id == 'cc') { + m_rd.bClosedCaption = true; + } else { + ASSERT(id <= BYTE_MAX); + m_rd.selids[(BYTE)id] = true; + } + } else { + break; + } + } + + if ((!m_rd.selids.IsEmpty() || m_rd.bClosedCaption) && line.IsEmpty()) { + phase = P_OPTIONS; + } + } + } else if (phase == 5 && !line.CompareNoCase(_T("CLOSE"))) { + m_rd.bClose = true; + } else if (phase == 5 && !line.CompareNoCase(_T("BEEP"))) { + m_rd.bBeep = true; + } else if (phase == 5 && !line.CompareNoCase(_T("RESETTIME"))) { + m_rd.bResetTime = true; + } else if (phase == 5 && !line.CompareNoCase(_T("FORCEDONLY"))) { + m_rd.fForcedOnly = true; + } else if (phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS"))) { + m_rd.bCloseIgnoreError = true; + } + + } + + m_rd.bAuto = true; + + return phase == P_OPTIONS ? S_OK : E_FAIL; } STDMETHODIMP CVobSubFileRipper::SetInput(CString infn) { - CAutoLock cAutoLock(&m_csAccessLock); + CAutoLock cAutoLock(&m_csAccessLock); - m_rd.Reset(); + m_rd.Reset(); - if(!LoadIfo(infn) || !LoadVob(infn)) - return E_INVALIDARG; + if (!LoadIfo(infn) || !LoadVob(infn)) { + return E_INVALIDARG; + } - m_infn = infn; + m_infn = infn; - return S_OK; + return S_OK; } STDMETHODIMP CVobSubFileRipper::SetOutput(CString outfn) { - CAutoLock cAutoLock(&m_csAccessLock); - m_outfn = outfn; - return S_OK; + CAutoLock cAutoLock(&m_csAccessLock); + m_outfn = outfn; + return S_OK; } STDMETHODIMP CVobSubFileRipper::GetRipperData(VSFRipperData& rd) { - CAutoLock cAutoLock(&m_csAccessLock); - rd.Copy(m_rd); - return S_OK; + CAutoLock cAutoLock(&m_csAccessLock); + rd.Copy(m_rd); + return S_OK; } STDMETHODIMP CVobSubFileRipper::UpdateRipperData(VSFRipperData& rd) { - CAutoLock cAutoLock(&m_csAccessLock); - m_rd.Copy(rd); - return S_OK; + CAutoLock cAutoLock(&m_csAccessLock); + m_rd.Copy(rd); + return S_OK; } STDMETHODIMP CVobSubFileRipper::Index() { - if(m_fIndexing) return E_FAIL; - CAMThread::CallWorker(CMD_INDEX); - return S_OK; + if (m_bIndexing) { + return E_FAIL; + } + CAMThread::CallWorker(CMD_INDEX); + return S_OK; } STDMETHODIMP CVobSubFileRipper::IsIndexing() { - return m_fIndexing ? S_OK : S_FALSE; + return m_bIndexing ? S_OK : S_FALSE; } -STDMETHODIMP CVobSubFileRipper::Abort(bool fSavePartial) +STDMETHODIMP CVobSubFileRipper::Abort(bool bSavePartial) { - m_fBreakThread = true; - return S_OK; + m_bBreakThread = true; + return S_OK; } // void VSFRipperData::Reset() { - vidsize.SetSize(0,0); - memset(&vidinfo, 0, sizeof(vidinfo)); - pgcs.RemoveAll(); - iSelPGC = -1; - fResetTime = fClosedCaption = true; - fForcedOnly = false; - fClose = fBeep = fAuto = false; - fCloseIgnoreError = false; - - selvcs.RemoveAll(); - selids.RemoveAll(); + vidsize.SetSize(0, 0); + ZeroMemory(&vidinfo, sizeof(vidinfo)); + pgcs.RemoveAll(); + iSelPGC = -1; + bResetTime = bClosedCaption = true; + fForcedOnly = false; + bClose = bBeep = bAuto = false; + bCloseIgnoreError = false; + + selvcs.RemoveAll(); + selids.RemoveAll(); } void VSFRipperData::Copy(VSFRipperData& rd) { - Reset(); - - vidsize = rd.vidsize; - vidinfo = rd.vidinfo; - if(int len = rd.pgcs.GetCount()) - { - pgcs.SetCount(len); - for(int i = 0; i < len; i++) - { - PGC& src = rd.pgcs[i]; - PGC& dst = pgcs[i]; - dst.nAngles = src.nAngles; - for(int i = 0; i < countof(dst.angles); i++) - dst.angles[i].Copy(src.angles[i]); - dst.iSelAngle = src.iSelAngle; - memcpy(dst.pal, src.pal, sizeof(src.pal)); - memcpy(dst.ids, src.ids, sizeof(src.ids)); - } - } - iSelPGC = rd.iSelPGC; - fResetTime = rd.fResetTime; - fClosedCaption = rd.fClosedCaption; - fForcedOnly = rd.fForcedOnly; - fClose = rd.fClose; - fBeep = rd.fBeep; - fAuto = rd.fAuto; - fCloseIgnoreError = rd.fCloseIgnoreError; - selvcs.Copy(rd.selvcs); - POSITION pos = rd.selids.GetStartPosition(); - while(pos) - { - BYTE key; - bool val; - rd.selids.GetNextAssoc(pos, key, val); - selids[key] = val; - } + Reset(); + + vidsize = rd.vidsize; + vidinfo = rd.vidinfo; + if (size_t len = rd.pgcs.GetCount()) { + pgcs.SetCount(len); + for (size_t i = 0; i < len; i++) { + PGC& src = rd.pgcs[i]; + PGC& dst = pgcs[i]; + dst.nAngles = src.nAngles; + for (size_t j = 0; j < _countof(dst.angles); j++) { + dst.angles[j].Copy(src.angles[j]); + } + dst.iSelAngle = src.iSelAngle; + memcpy(dst.pal, src.pal, sizeof(src.pal)); + memcpy(dst.ids, src.ids, sizeof(src.ids)); + } + } + iSelPGC = rd.iSelPGC; + bResetTime = rd.bResetTime; + bClosedCaption = rd.bClosedCaption; + fForcedOnly = rd.fForcedOnly; + bClose = rd.bClose; + bBeep = rd.bBeep; + bAuto = rd.bAuto; + bCloseIgnoreError = rd.bCloseIgnoreError; + selvcs.Copy(rd.selvcs); + POSITION pos = rd.selids.GetStartPosition(); + while (pos) { + BYTE key; + bool val; + rd.selids.GetNextAssoc(pos, key, val); + selids[key] = val; + } } - diff --git a/src/subtitles/VobSubFileRipper.h b/src/subtitles/VobSubFileRipper.h index 2abccc4ad..ff9ccb182 100644 --- a/src/subtitles/VobSubFileRipper.h +++ b/src/subtitles/VobSubFileRipper.h @@ -1,85 +1,82 @@ -/* - * Copyright (C) 2003-2006 Gabest - * http://www.gabest.org +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 see Authors.txt * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html + * This file is part of MPC-HC. + * + * MPC-HC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * MPC-HC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ #pragma once #include -#include "..\decss\VobFile.h" +#include "../DeCSS/VobFile.h" +#include "../DSUtil/DSUtil.h" #include "VobSubFile.h" -#pragma pack(push) -#pragma pack(1) +#pragma pack(push, 1) +struct vidinfo { + WORD perm_displ : 2; + WORD ratio : 2; + WORD system : 2; + WORD compression : 2; + WORD mode : 1; + WORD letterboxed : 1; + WORD source_res : 2; + WORD cbrvbr : 2; + WORD line21_2 : 1; + WORD line21_1 : 1; +}; -typedef struct -{ - WORD perm_displ : 2; - WORD ratio : 2; - WORD system : 2; - WORD compression : 2; - WORD mode : 1; - WORD letterboxed : 1; - WORD source_res : 2; - WORD cbrvbr : 2; - WORD line21_2 : 1; - WORD line21_1 : 1; -} vidinfo; - -typedef struct -{ - BYTE vob, cell; - DWORD tTime, tOffset, tTotal; - DWORD start, end; - int iAngle; - bool fDiscontinuity; -} vc_t; - -typedef struct -{ - int nAngles; - CAtlArray angles[10]; - int iSelAngle; - RGBQUAD pal[16]; - WORD ids[32]; -} PGC; - -typedef struct VSFRipperData_t -{ - CSize vidsize; - vidinfo vidinfo; - CAtlArray pgcs; - int iSelPGC; - bool fResetTime, fClosedCaption, fForcedOnly; +struct vc_t { + BYTE vob, cell; + DWORD tTime, tOffset, tTotal; + DWORD start, end; + int iAngle; + bool bDiscontinuity; +}; + +struct PGC { + int nAngles; + CAtlArray angles[10]; + int iSelAngle; + RGBQUAD pal[16]; + WORD ids[32]; +}; - bool fClose, fBeep, fAuto; // only used by the UI externally, but may be set through the parameter file - bool fCloseIgnoreError; +struct VSFRipperData { + CSize vidsize; + vidinfo vidinfo; + CAtlArray pgcs; + int iSelPGC; + bool bResetTime, bClosedCaption, fForcedOnly; - CAtlArray selvcs; - CAtlMap selids; + bool bClose, bBeep, bAuto; // only used by the UI externally, but may be set through the parameter file + bool bCloseIgnoreError; - void Reset(); - void Copy(struct VSFRipperData_t& rd); + CAtlArray selvcs; + CAtlMap selids; -} VSFRipperData; + void Reset(); + void Copy(struct VSFRipperData& rd); +}; -typedef struct {__int64 start, end; DWORD vc;} vcchunk; +struct vcchunk { + __int64 start, end; + DWORD vc; +}; #pragma pack(pop) @@ -89,105 +86,104 @@ typedef struct {__int64 start, end; DWORD vc;} vcchunk; // IVSFRipperCallback // -[uuid("9E2EBB5C-AD7C-452f-A48B-38685716AC46")] -interface IVSFRipperCallback : public IUnknown -{ - STDMETHOD (OnMessage) (LPCTSTR msg) PURE; - STDMETHOD (OnProgress) (double progress /*0->1*/) PURE; - STDMETHOD (OnFinished) (bool fSucceeded) PURE; +interface __declspec(uuid("9E2EBB5C-AD7C-452f-A48B-38685716AC46")) +IVSFRipperCallback : +public IUnknown { + STDMETHOD(OnMessage)(LPCTSTR msg) PURE; + STDMETHOD(OnProgress)(double progress /*0.0 -> 1.0*/) PURE; + STDMETHOD(OnFinished)(bool bSucceeded) PURE; }; // IVSFRipperCallbackImpl -#ifndef QI -#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : -#endif - class IVSFRipperCallbackImpl : public CUnknown, public IVSFRipperCallback { protected: - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) - { - return - QI(IVSFRipperCallback) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IVSFRipperCallback - STDMETHODIMP OnMessage(LPCTSTR msg) {return S_FALSE;} - STDMETHODIMP OnProgress(double progress /*0->1*/) {return S_FALSE;} - STDMETHODIMP OnFinished(bool fSucceeded) {return S_FALSE;} + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(IVSFRipperCallback) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IVSFRipperCallback + STDMETHODIMP OnMessage(LPCTSTR msg) { return S_FALSE; } + STDMETHODIMP OnProgress(double progress /*0.0 -> 1.0*/) { return S_FALSE; } + STDMETHODIMP OnFinished(bool bSucceeded) { return S_FALSE; } public: - IVSFRipperCallbackImpl() : CUnknown(NAME("IVSFRipperCallbackImpl"), NULL) {} + IVSFRipperCallbackImpl() : CUnknown(NAME("IVSFRipperCallbackImpl"), nullptr) {} }; // // IVSFRipper // -[uuid("69F935BB-B8D0-43f5-AA2E-BBD0851CC9A6")] -interface IVSFRipper : public IUnknown -{ - STDMETHOD (SetCallBack) (IVSFRipperCallback* pCallback) PURE; - STDMETHOD (LoadParamFile) (CString fn) PURE; - STDMETHOD (SetInput) (CString infn) PURE; - STDMETHOD (SetOutput) (CString outfn) PURE; - STDMETHOD (GetRipperData) (VSFRipperData& rd) PURE; - STDMETHOD (UpdateRipperData) (VSFRipperData& rd) PURE; - STDMETHOD (Index) () PURE; - STDMETHOD (IsIndexing) () PURE; - STDMETHOD (Abort) (bool fSavePartial) PURE; +interface __declspec(uuid("69F935BB-B8D0-43f5-AA2E-BBD0851CC9A6")) +IVSFRipper : +public IUnknown { + STDMETHOD(SetCallBack)(IVSFRipperCallback * pCallback) PURE; + STDMETHOD(LoadParamFile)(CString fn) PURE; + STDMETHOD(SetInput)(CString infn) PURE; + STDMETHOD(SetOutput)(CString outfn) PURE; + STDMETHOD(GetRipperData)(VSFRipperData & rd) PURE; + STDMETHOD(UpdateRipperData)(VSFRipperData & rd) PURE; + STDMETHOD(Index)() PURE; + STDMETHOD(IsIndexing)() PURE; + STDMETHOD(Abort)(bool bSavePartial) PURE; }; class CVobSubFileRipper : public CVobSubFile, protected CAMThread, public IVSFRipper { private: - bool m_fThreadActive, m_fBreakThread, m_fIndexing; - enum {CMD_EXIT, CMD_INDEX}; - DWORD ThreadProc(); - bool Create(); + bool m_bThreadActive, m_bBreakThread, m_bIndexing; + enum { CMD_EXIT, CMD_INDEX }; + DWORD ThreadProc(); + bool Create(); - // + // - typedef enum {LOG_INFO, LOG_WARNING, LOG_ERROR} log_t; - void Log(log_t type, LPCTSTR lpszFormat, ...); - void Progress(double progress); - void Finished(bool fSucceeded); + enum log_t { + LOG_INFO, + LOG_WARNING, + LOG_ERROR + }; + void Log(log_t type, LPCTSTR lpszFormat, ...); + void Progress(double progress); + void Finished(bool bSucceeded); - // + // - CCritSec m_csAccessLock; - CString m_infn, m_outfn; - CVobFile m_vob; - VSFRipperData m_rd; + CCritSec m_csAccessLock; + CString m_infn, m_outfn; + CVobFile m_vob; + VSFRipperData m_rd; - bool LoadIfo(CString fn); - bool LoadVob(CString fn); - bool LoadChunks(CAtlArray& chunks); - bool SaveChunks(CAtlArray& chunks); + bool LoadIfo(CString fn); + bool LoadVob(CString fn); + bool LoadChunks(CAtlArray& chunks); + bool SaveChunks(CAtlArray& chunks); - // + // - CCritSec m_csCallback; - CComPtr m_pCallback; + CCritSec m_csCallback; + CComPtr m_pCallback; public: CVobSubFileRipper(); virtual ~CVobSubFileRipper(); - DECLARE_IUNKNOWN + DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - // IVSFRipper - STDMETHODIMP SetCallBack(IVSFRipperCallback* pCallback); - STDMETHODIMP LoadParamFile(CString fn); - STDMETHODIMP SetInput(CString infn); - STDMETHODIMP SetOutput(CString outfn); - STDMETHODIMP GetRipperData(VSFRipperData& rd); - STDMETHODIMP UpdateRipperData(VSFRipperData& rd); - STDMETHODIMP Index(); - STDMETHODIMP IsIndexing(); - STDMETHODIMP Abort(bool fSavePartial); + // IVSFRipper + STDMETHODIMP SetCallBack(IVSFRipperCallback* pCallback); + STDMETHODIMP LoadParamFile(CString fn); + STDMETHODIMP SetInput(CString infn); + STDMETHODIMP SetOutput(CString outfn); + STDMETHODIMP GetRipperData(VSFRipperData& rd); + STDMETHODIMP UpdateRipperData(VSFRipperData& rd); + STDMETHODIMP Index(); + STDMETHODIMP IsIndexing(); + STDMETHODIMP Abort(bool bSavePartial); }; diff --git a/src/subtitles/VobSubImage.cpp b/src/subtitles/VobSubImage.cpp index 429f8f122..7b051ae8c 100644 --- a/src/subtitles/VobSubImage.cpp +++ b/src/subtitles/VobSubImage.cpp @@ -1,1196 +1,1361 @@ -/* - * Copyright (C) 2003-2006 Gabest - * http://www.gabest.org +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 see Authors.txt + * + * This file is part of MPC-HC. + * + * MPC-HC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html + * MPC-HC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ #include "stdafx.h" #include "VobSubImage.h" +#include "RTS.h" +#include +#include CVobSubImage::CVobSubImage() + : org(CSize(0, 0)) + , lpTemp1(nullptr) + , lpTemp2(nullptr) + , nPlane(0) + , fCustomPal(false) + , fAligned(true) + , tridx(0) + , orgpal(nullptr) + , cuspal(nullptr) + , iLang(-1) + , iIdx(-1) + , fForced(false) + , fAnimated(false) + , tCurrent(-1) + , start(0) + , delay(0) + , rect(CRect(0, 0, 0, 0)) + , lpPixels(nullptr) { - iLang = iIdx = -1; - fForced = false; - start = delay = 0; - rect = CRect(0,0,0,0); - lpPixels = lpTemp1 = lpTemp2 = NULL; - org = CSize(0,0); + ZeroMemory(&pal, sizeof(pal)); } CVobSubImage::~CVobSubImage() { - Free(); + Free(); } bool CVobSubImage::Alloc(int w, int h) { - // if there is nothing to crop TrimSubImage might even add a 1 pixel - // wide border around the text, that's why we need a bit more memory - // to be allocated. - - if(lpTemp1 == NULL || w*h > org.cx*org.cy || (w+2)*(h+2) > (org.cx+2)*(org.cy+2)) - { - Free(); - - lpTemp1 = new RGBQUAD[w*h]; - if(!lpTemp1) return(false); - - lpTemp2 = new RGBQUAD[(w+2)*(h+2)]; - if(!lpTemp2) {delete [] lpTemp1; lpTemp1 = NULL; return(false);} - - org.cx = w; - org.cy = h; - } + // if there is nothing to crop TrimSubImage might even add a 1 pixel + // wide border around the text, that's why we need a bit more memory + // to be allocated. + + if (lpTemp1 == nullptr || w * h > org.cx * org.cy || (w + 2) * (h + 2) > (org.cx + 2) * (org.cy + 2)) { + Free(); + + try { + lpTemp1 = DEBUG_NEW RGBQUAD[w * h]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return false; + } + + try { + lpTemp2 = DEBUG_NEW RGBQUAD[(w + 2) * (h + 2)]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + delete [] lpTemp1; + lpTemp1 = nullptr; + return false; + } + + org.cx = w; + org.cy = h; + } - lpPixels = lpTemp1; + lpPixels = lpTemp1; - return(true); + return true; } void CVobSubImage::Free() { - if(lpTemp1) delete [] lpTemp1; - lpTemp1 = NULL; + SAFE_DELETE_ARRAY(lpTemp1); + SAFE_DELETE_ARRAY(lpTemp2); - if(lpTemp2) delete [] lpTemp2; - lpTemp2 = NULL; - - lpPixels = NULL; + lpPixels = nullptr; } -bool CVobSubImage::Decode(BYTE* lpData, int packetsize, int datasize, - bool fCustomPal, - int tridx, - RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, - bool fTrim) +bool CVobSubImage::Decode(BYTE* lpData, size_t packetSize, size_t dataSize, int t, + bool fCustomPal, + int tridx, + RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, + bool fTrim) { - GetPacketInfo(lpData, packetsize, datasize); - - if(!Alloc(rect.Width(), rect.Height())) return(false); + GetPacketInfo(lpData, packetSize, dataSize, t); - lpPixels = lpTemp1; + if (!Alloc(rect.Width(), rect.Height())) { + return false; + } - nPlane = 0; - fAligned = 1; + lpPixels = lpTemp1; - this->fCustomPal = fCustomPal; - this->orgpal = orgpal; - this->tridx = tridx; - this->cuspal = cuspal; + nPlane = 0; + fAligned = true; - CPoint p(rect.left, rect.top); + this->fCustomPal = fCustomPal; + this->orgpal = orgpal; + this->tridx = tridx; + this->cuspal = cuspal; - int end0 = nOffset[1]; - int end1 = datasize; + CPoint p = rect.TopLeft(); - if (nOffset[0] > nOffset[1]) { - end1 = nOffset[0]; - end0 = datasize; - } + size_t end[] = { nOffset[1], dataSize }; - while((nPlane == 0 && nOffset[0] < end0) || (nPlane == 1 && nOffset[1] < end1)) - { - DWORD code; + while (nOffset[nPlane] < end[nPlane]) { + DWORD code; - if((code = GetNibble(lpData)) >= 0x4 - || (code = (code << 4) | GetNibble(lpData)) >= 0x10 - || (code = (code << 4) | GetNibble(lpData)) >= 0x40 - || (code = (code << 4) | GetNibble(lpData)) >= 0x100) - { - DrawPixels(p, code >> 2, code & 3); - if((p.x += code >> 2) < rect.right) continue; - } + if ((code = GetNibble(lpData)) >= 0x4 + || (code = (code << 4) | GetNibble(lpData)) >= 0x10 + || (code = (code << 4) | GetNibble(lpData)) >= 0x40 + || (code = (code << 4) | GetNibble(lpData)) >= 0x100) { + DrawPixels(p, code >> 2, code & 3); + if ((p.x += code >> 2) < rect.right) { + continue; + } + } - DrawPixels(p, rect.right - p.x, code & 3); + DrawPixels(p, rect.right - p.x, code & 3); - if(!fAligned) GetNibble(lpData); // align to byte + if (!fAligned) { + GetNibble(lpData); // align to byte + } - p.x = rect.left; - p.y++; - nPlane = 1 - nPlane; - } + p.x = rect.left; + p.y++; + nPlane = 1 - nPlane; + } - rect.bottom = min(p.y, rect.bottom); + rect.bottom = min(p.y, rect.bottom); - if(fTrim) TrimSubImage(); + if (fTrim) { + TrimSubImage(); + } - return(true); + return true; } -void CVobSubImage::GetPacketInfo(BYTE* lpData, int packetsize, int datasize) +void CVobSubImage::GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t /*= INT_MAX*/) { -// delay = 0; - - int i, nextctrlblk = datasize; - WORD pal = 0, tr = 0; - - do - { - i = nextctrlblk; - - int t = (lpData[i] << 8) | lpData[i+1]; i += 2; - nextctrlblk = (lpData[i] << 8) | lpData[i+1]; i += 2; - - if(nextctrlblk > packetsize || nextctrlblk < datasize) - { - ASSERT(0); - return; - } - - bool fBreak = false; - - while(!fBreak) - { - int len = 0; - - switch(lpData[i]) - { - case 0x00: len = 0; break; - case 0x01: len = 0; break; - case 0x02: len = 0; break; - case 0x03: len = 2; break; - case 0x04: len = 2; break; - case 0x05: len = 6; break; - case 0x06: len = 4; break; - default: len = 0; break; - } - - if(i+len >= packetsize) - { - TRACE(_T("Warning: Wrong subpicture parameter block ending\n")); - break; - } - - switch(lpData[i++]) - { - case 0x00: // forced start displaying - fForced = true; - break; - case 0x01: // start displaying - fForced = false; - break; - case 0x02: // stop displaying - delay = 1024 * t / 90; - break; - case 0x03: - pal = (lpData[i] << 8) | lpData[i+1]; i += 2; - break; - case 0x04: - if (lpData[i] || lpData[i+1]) { - tr = (lpData[i] << 8) | lpData[i+1]; - } + // delay = 0; + + size_t i, nextctrlblk = dataSize; + WORD pal = 0, tr = 0; + WORD nPal = 0, nTr = 0; + + do { + i = nextctrlblk; + + tCurrent = 1024 * ((lpData[i] << 8) | lpData[i + 1]) / 90; + i += 2; + nextctrlblk = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + + if (nextctrlblk > packetSize || nextctrlblk < dataSize) { + ASSERT(0); + return; + } + + if (tCurrent > t) { + break; + } + + bool bBreak = false; + + while (!bBreak) { + size_t len = 0; + + switch (lpData[i]) { + case 0x00: + len = 0; + break; + case 0x01: + len = 0; + break; + case 0x02: + len = 0; + break; + case 0x03: + len = 2; + break; + case 0x04: + len = 2; + break; + case 0x05: + len = 6; + break; + case 0x06: + len = 4; + break; + default: + len = 0; + break; + } + + if (i + len >= packetSize) { + TRACE(_T("Warning: Wrong subpicture parameter block ending\n")); + break; + } + + switch (lpData[i++]) { + case 0x00: // forced start displaying + fForced = true; + break; + case 0x01: // start displaying + fForced = false; + break; + case 0x02: // stop displaying + delay = tCurrent; + break; + case 0x03: + pal = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + nPal++; + break; + case 0x04: + tr = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + nTr++; + //tr &= 0x00f0; + break; + case 0x05: + rect = CRect((lpData[i] << 4) + (lpData[i + 1] >> 4), + (lpData[i + 3] << 4) + (lpData[i + 4] >> 4), + ((lpData[i + 1] & 0x0f) << 8) + lpData[i + 2] + 1, + ((lpData[i + 4] & 0x0f) << 8) + lpData[i + 5] + 1); + i += 6; + break; + case 0x06: + nOffset[0] = (lpData[i] << 8) + lpData[i + 1]; i += 2; -//tr &= 0x00f0; - break; - case 0x05: - rect = CRect((lpData[i] << 4) + (lpData[i+1] >> 4), - (lpData[i+3] << 4) + (lpData[i+4] >> 4), - ((lpData[i+1] & 0x0f) << 8) + lpData[i+2] + 1, - ((lpData[i+4] & 0x0f) << 8) + lpData[i+5] + 1); - i += 6; - break; - case 0x06: - nOffset[0] = (lpData[i] << 8) + lpData[i+1]; i += 2; - nOffset[1] = (lpData[i] << 8) + lpData[i+1]; i += 2; - break; - case 0xff: // end of ctrlblk - fBreak = true; - continue; - default: // skip this ctrlblk - fBreak = true; - break; - } - } - } - while(i <= nextctrlblk && i < packetsize); - - for(i = 0; i < 4; i++) - { - this->pal[i].pal = (pal >> (i << 2)) & 0xf; - this->pal[i].tr = (tr >> (i << 2)) & 0xf; - } + nOffset[1] = (lpData[i] << 8) + lpData[i + 1]; + i += 2; + break; + case 0xff: // end of ctrlblk + bBreak = true; + continue; + default: // skip this ctrlblk + bBreak = true; + break; + } + } + } while (i <= nextctrlblk && i < packetSize); + + for (i = 0; i < 4; i++) { + this->pal[i].pal = (pal >> (i << 2)) & 0xf; + this->pal[i].tr = (tr >> (i << 2)) & 0xf; + } + + fAnimated = (nPal > 1 || nTr > 1); } -BYTE CVobSubImage::GetNibble(BYTE* lpData) +BYTE CVobSubImage::GetNibble(const BYTE* lpData) { - WORD& off = nOffset[nPlane]; - BYTE ret = (lpData[off] >> (fAligned << 2)) & 0x0f; - fAligned = !fAligned; - off += fAligned; - return(ret); + size_t& off = nOffset[nPlane]; + BYTE ret = lpData[off]; + if (fAligned) { + ret >>= 4; + } + ret &= 0x0f; + fAligned = !fAligned; + if (fAligned) { + off++; + } + return ret; } -void CVobSubImage::DrawPixels(CPoint p, int length, int colorid) +void CVobSubImage::DrawPixels(CPoint p, int length, size_t colorId) { - if(length <= 0 - || p.x + length < rect.left - || p.x >= rect.right - || p.y < rect.top - || p.y >= rect.bottom) - { - return; - } - - if(p.x < rect.left) p.x = rect.left; - if(p.x + length >= rect.right) length = rect.right - p.x; - - RGBQUAD* ptr = &lpPixels[rect.Width() * (p.y - rect.top) + (p.x - rect.left)]; - - RGBQUAD c; - - if(!fCustomPal) - { - c = orgpal[pal[colorid].pal]; - c.rgbReserved = (pal[colorid].tr<<4)|pal[colorid].tr; - } - else - { - c = cuspal[colorid]; - } - - while(length-- > 0) *ptr++ = c; + if (length <= 0 + || p.x + length < rect.left + || p.x >= rect.right + || p.y < rect.top + || p.y >= rect.bottom) { + return; + } + + if (p.x < rect.left) { + p.x = rect.left; + } + if (p.x + length >= rect.right) { + length = rect.right - p.x; + } + + RGBQUAD* ptr = &lpPixels[rect.Width() * (p.y - rect.top) + (p.x - rect.left)]; + + RGBQUAD c; + + if (!fCustomPal) { + c = orgpal[pal[colorId].pal]; + c.rgbReserved = (pal[colorId].tr << 4) | pal[colorId].tr; + } else { + c = cuspal[colorId]; + } + + while (length-- > 0) { + *ptr++ = c; + } } void CVobSubImage::TrimSubImage() { - CRect r; - r.left = rect.Width(); - r.top = rect.Height(); - r.right = 0; - r.bottom = 0; - - RGBQUAD* ptr = lpTemp1; - - for(int j = 0, y = rect.Height(); j < y; j++) - { - for(int i = 0, x = rect.Width(); i < x; i++, ptr++) - { - if(ptr->rgbReserved) - { - if(r.top > j) r.top = j; - if(r.bottom < j) r.bottom = j; - if(r.left > i) r.left = i; - if(r.right < i) r.right = i; - } - } - } + CRect r; + r.left = rect.Width(); + r.top = rect.Height(); + r.right = 0; + r.bottom = 0; + + RGBQUAD* ptr = lpTemp1; + + for (int j = 0, y = rect.Height(); j < y; j++) { + for (int i = 0, x = rect.Width(); i < x; i++, ptr++) { + if (ptr->rgbReserved) { + if (r.top > j) { + r.top = j; + } + if (r.bottom < j) { + r.bottom = j; + } + if (r.left > i) { + r.left = i; + } + if (r.right < i) { + r.right = i; + } + } + } + } - if(r.left > r.right || r.top > r.bottom) return; + if (r.left > r.right || r.top > r.bottom) { + return; + } - r += CRect(0, 0, 1, 1); + r += CRect(0, 0, 1, 1); - r &= CRect(CPoint(0,0), rect.Size()); + r &= CRect(CPoint(0, 0), rect.Size()); - int w = r.Width(), h = r.Height(); + int w = r.Width(), h = r.Height(); - DWORD offset = r.top*rect.Width() + r.left; + DWORD offset = r.top * rect.Width() + r.left; - r += CRect(1, 1, 1, 1); + r += CRect(1, 1, 1, 1); - DWORD* src = (DWORD*)&lpTemp1[offset]; - DWORD* dst = (DWORD*)&lpTemp2[1 + w + 1]; + DWORD* src = (DWORD*)&lpTemp1[offset]; + DWORD* dst = (DWORD*)&lpTemp2[1 + w + 1]; - memset(lpTemp2, 0, (1 + w + 1)*sizeof(RGBQUAD)); + ZeroMemory(lpTemp2, (1 + w + 1)*sizeof(RGBQUAD)); - for(int height = h; height; height--, src += rect.Width()) - { - *dst++ = 0; - memcpy(dst, src, w*sizeof(RGBQUAD)); dst += w; - *dst++ = 0; - } + for (int height = h; height; height--, src += rect.Width()) { + *dst++ = 0; + memcpy(dst, src, w * sizeof(RGBQUAD)); + dst += w; + *dst++ = 0; + } - memset(dst, 0, (1 + w + 1)*sizeof(RGBQUAD)); + ZeroMemory(dst, (1 + w + 1)*sizeof(RGBQUAD)); - lpPixels = lpTemp2; + lpPixels = lpTemp2; - rect = r + rect.TopLeft(); + rect = r + rect.TopLeft(); } //////////////////////////////// -#include "RTS.h" -#include - -#define GP(xx, yy) (((xx) < 0 || (yy) < 0 || (xx) >= w || (yy) >= h) ? 0 : p[(yy)*w+(xx)]) +#define GP(xx, yy) (((xx) < 0 || (yy) < 0 || (xx) >= w || (yy) >= h) ? 0 : p[(yy) * w + (xx)]) CAutoPtrList* CVobSubImage::GetOutlineList(CPoint& topleft) { - int w = rect.Width(), h = rect.Height(), len = w*h; - if(len <= 0) return NULL; - - CAutoVectorPtr p; - if(!p.Allocate(len)) return NULL; - - CAutoPtrList* ol = new CAutoPtrList(); - if(!ol) return NULL; - - BYTE* cp = p; - RGBQUAD* rgbp = (RGBQUAD*)lpPixels; - - for(int i = 0; i < len; i++, cp++, rgbp++) - *cp = !!rgbp->rgbReserved; - - enum {UP, RIGHT, DOWN, LEFT}; - - topleft.x = topleft.y = INT_MAX; - - while(1) - { - cp = p; - - int x, y; - - for(y = 0; y < h; y++) - { - for(x = 0; x < w-1; x++, cp++) - { - if(cp[0] == 0 && cp[1] == 1) break; - } - - if(x < w-1) break; - - cp++; - } - - if(y == h) break; - - int prevdir, dir = UP; - - int ox = x, oy = y, odir = dir; - - CAutoPtr o(new COutline); - if(!o) break; - - do - { - CPoint pp; - BYTE fl, fr, br; - - prevdir = dir; - - switch(prevdir) - { - case UP: - pp = CPoint(x+1, y); - fl = GP(x, y-1); - fr = GP(x+1, y-1); - br = GP(x+1, y); - break; - case RIGHT: - pp = CPoint(x+1, y+1); - fl = GP(x+1, y); - fr = GP(x+1, y+1); - br = GP(x, y+1); - break; - case DOWN: - pp = CPoint(x, y+1); - fl = GP(x, y+1); - fr = GP(x-1, y+1); - br = GP(x-1, y); - break; - case LEFT: - pp = CPoint(x, y); - fl = GP(x-1, y); - fr = GP(x-1, y-1); - br = GP(x, y-1); - break; - } - - // turning left if: - // o . | o . - // ^ o | < o - // turning right if: - // x x | x > - // ^ o | x o - // - // o set, x empty, . can be anything - - if(fl==1) dir = (dir-1+4)&3; - else if(fl!=1 && fr!=1 && br==1) dir = (dir+1)&3; - else if(p[y*w+x]&16) {ASSERT(0); break;} // we are going around in one place (this must not happen if the starting conditions were correct) - - p[y*w+x] = (p[y*w+x]<<1) | 2; // increase turn count (== log2(highordbit(*p))) - - switch(dir) - { - case UP: - if(prevdir == LEFT) {x--; y--;} - if(prevdir == UP) y--; - break; - case RIGHT: - if(prevdir == UP) {x++; y--;} - if(prevdir == RIGHT) x++; - break; - case DOWN: - if(prevdir == RIGHT) {x++; y++;} - if(prevdir == DOWN) y++; - break; - case LEFT: - if(prevdir == DOWN) {x--; y++;} - if(prevdir == LEFT) x--; - break; - } - - int d = dir - prevdir; - o->Add(pp, d == 3 ? -1 : d == -3 ? 1 : d); - - if(topleft.x > pp.x) topleft.x = pp.x; - if(topleft.y > pp.y) topleft.y = pp.y; - } - while(!(x == ox && y == oy && dir == odir)); - - if(o->pa.GetCount() > 0 && (x == ox && y == oy && dir == odir)) - { - ol->AddTail(o); - } - else - { - ASSERT(0); - } - } - - return(ol); -} + int w = rect.Width(), h = rect.Height(), len = w * h; + if (len <= 0) { + return nullptr; + } -static bool FitLine(COutline& o, int& start, int& end) -{ - int len = o.pa.GetCount(); - if(len < 7) return(false); // small segments should be handled with beziers... + CAutoVectorPtr p; + if (!p.Allocate(len)) { + return nullptr; + } - for(start = 0; start < len && !o.da[start]; start++); - for(end = len-1; end > start && !o.da[end]; end--); + CAutoPtrList* ol; + try { + ol = DEBUG_NEW CAutoPtrList(); + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return nullptr; + } - if(end-start < 8 || end-start < (len-end)+(start-0)) return(false); + BYTE* cp = p; + RGBQUAD* rgbp = (RGBQUAD*)lpPixels; - CUIntArray la, ra; + for (int i = 0; i < len; i++, cp++, rgbp++) { + *cp = !!rgbp->rgbReserved; + } - int i, j, k; + enum { UP, RIGHT, DOWN, LEFT }; + + topleft.x = topleft.y = INT_MAX; + + for (;;) { + cp = p; + + int x = 0; + int y = 0; + + for (y = 0; y < h; y++) { + for (x = 0; x < w - 1; x++, cp++) { + if (cp[0] == 0 && cp[1] == 1) { + break; + } + } + + if (x < w - 1) { + break; + } + + cp++; + } + + if (y == h) { + break; + } + + int dir = UP; + + int ox = x, oy = y, odir = dir; + + CAutoPtr o; + try { + o.Attach(DEBUG_NEW COutline); + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + break; + } + + do { + CPoint pp; + BYTE fl = 0; + BYTE fr = 0; + BYTE br = 0; + + int prevdir = dir; + + switch (prevdir) { + case UP: + pp = CPoint(x + 1, y); + fl = GP(x, y - 1); + fr = GP(x + 1, y - 1); + br = GP(x + 1, y); + break; + case RIGHT: + pp = CPoint(x + 1, y + 1); + fl = GP(x + 1, y); + fr = GP(x + 1, y + 1); + br = GP(x, y + 1); + break; + case DOWN: + pp = CPoint(x, y + 1); + fl = GP(x, y + 1); + fr = GP(x - 1, y + 1); + br = GP(x - 1, y); + break; + case LEFT: + pp = CPoint(x, y); + fl = GP(x - 1, y); + fr = GP(x - 1, y - 1); + br = GP(x, y - 1); + break; + } + + // turning left if: + // o . | o . + // ^ o | < o + // turning right if: + // x x | x > + // ^ o | x o + // + // o set, x empty, . can be anything + + if (fl == 1) { + dir = (dir - 1 + 4) & 3; + } else if (fl != 1 && fr != 1 && br == 1) { + dir = (dir + 1) & 3; + } else if (p[y * w + x] & 16) { + ASSERT(0); // we are going around in one place (this must not happen if the starting conditions were correct) + break; + } + + p[y * w + x] = (p[y * w + x] << 1) | 2; // increase turn count (== log2(highordbit(*p))) + + switch (dir) { + case UP: + if (prevdir == LEFT) { + x--; + y--; + } + if (prevdir == UP) { + y--; + } + break; + case RIGHT: + if (prevdir == UP) { + x++; + y--; + } + if (prevdir == RIGHT) { + x++; + } + break; + case DOWN: + if (prevdir == RIGHT) { + x++; + y++; + } + if (prevdir == DOWN) { + y++; + } + break; + case LEFT: + if (prevdir == DOWN) { + x--; + y++; + } + if (prevdir == LEFT) { + x--; + } + break; + } + + int d = dir - prevdir; + o->Add(pp, d == 3 ? -1 : d == -3 ? 1 : d); + + if (topleft.x > pp.x) { + topleft.x = pp.x; + } + if (topleft.y > pp.y) { + topleft.y = pp.y; + } + } while (!(x == ox && y == oy && dir == odir)); + + if (!o->pa.IsEmpty() && (x == ox && y == oy && dir == odir)) { + ol->AddTail(o); + } else { + ASSERT(0); + } + } - for(i = start+1, j = end, k = start; i <= j; i++) - { - if(!o.da[i]) continue; - if(o.da[i] == o.da[k]) return(false); - if(o.da[i] == -1) la.Add(i-k); - else ra.Add(i-k); - k = i; - } + return ol; +} - bool fl = true, fr = true; +static bool FitLine(const COutline& o, int& start, int& end) +{ + int len = (int)o.pa.GetCount(); + if (len < 7) { + return false; // small segments should be handled with beziers... + } - // these tests are completly heuristic and might be redundant a bit... + for (start = 0; start < len && !o.da[start]; start++) { + ; + } + for (end = len - 1; end > start && !o.da[end]; end--) { + ; + } - for(i = 0, j = la.GetSize(); i < j && fl; i++) {if(la[i] != 1) fl = false;} - for(i = 0, j = ra.GetSize(); i < j && fr; i++) {if(ra[i] != 1) fr = false;} + if (end - start < 8 || end - start < (len - end) + (start - 0)) { + return false; + } - if(!fl && !fr) return(false); // can't be a line if there are bigger steps than one in both directions (lines are usually drawn by stepping one either horizontally or vertically) - if(fl && fr && 1.0*(end-start)/((len-end)*2+(start-0)*2) > 0.4) return(false); // if this section is relatively too small it may only be a rounded corner - if(!fl && la.GetSize() > 0 && la.GetSize() <= 4 && (la[0] == 1 && la[la.GetSize()-1] == 1)) return(false); // one step at both ends, doesn't sound good for a line (may be it was skewed, so only eliminate smaller sections where beziers going to look just as good) - if(!fr && ra.GetSize() > 0 && ra.GetSize() <= 4 && (ra[0] == 1 && ra[ra.GetSize()-1] == 1)) return(false); // -''- + CUIntArray la, ra; + + UINT i, j, k; + + for (i = start + 1, j = end, k = start; i <= j; i++) { + if (!o.da[i]) { + continue; + } + if (o.da[i] == o.da[k]) { + return false; + } + if (o.da[i] == -1) { + la.Add(i - k); + } else { + ra.Add(i - k); + } + k = i; + } - CUIntArray& a = !fl ? la : ra; + bool fl = true, fr = true; - len = a.GetSize(); + // these tests are completly heuristic and might be redundant a bit... - int sum = 0; + for (i = 0, j = (UINT)la.GetSize(); i < j && fl; i++) { + if (la[i] != 1) { + fl = false; + } + } + for (i = 0, j = (UINT)ra.GetSize(); i < j && fr; i++) { + if (ra[i] != 1) { + fr = false; + } + } - for(i = 0, j = INT_MAX, k = 0; i < len; i++) - { - if(j > a[i]) j = a[i]; - if(k < a[i]) k = a[i]; - sum += a[i]; - } + if (!fl && !fr) { + return false; // can't be a line if there are bigger steps than one in both directions (lines are usually drawn by stepping one either horizontally or vertically) + } + if (fl && fr && 1.0 * (end - start) / ((len - end) * 2 + (start - 0) * 2) > 0.4) { + return false; // if this section is relatively too small it may only be a rounded corner + } + if (!fl && !la.IsEmpty() && la.GetSize() <= 4 && (la[0] == 1 && la[la.GetSize() - 1] == 1)) { + return false; // one step at both ends, doesn't sound good for a line (may be it was skewed, so only eliminate smaller sections where beziers going to look just as good) + } + if (!fr && !ra.IsEmpty() && ra.GetSize() <= 4 && (ra[0] == 1 && ra[ra.GetSize() - 1] == 1)) { + return false; // -''- + } - if(k - j > 2 && 1.0*sum/len < 2) return(false); - if(k - j > 2 && 1.0*sum/len >= 2 && len < 4) return(false); + CUIntArray& a = !fl ? la : ra; - if((la.GetSize()/2+ra.GetSize()/2)/2 <= 2) - { - if((k+j)/2 < 2 && k*j!=1) return(false); - } + len = (int)a.GetSize(); - double err = 0; + int sum = 0; - CPoint sp = o.pa[start], ep = o.pa[end]; + for (i = 0, j = INT_MAX, k = 0; i < (UINT)len; i++) { + if (j > a[i]) { + j = a[i]; + } + if (k < a[i]) { + k = a[i]; + } + sum += a[i]; + } - double minerr = 0, maxerr = 0; - - double vx = ep.x - sp.x, vy = ep.y - sp.y, l = sqrt(vx*vx+vy*vy); - vx /= l; vy /= l; + if (k - j > 2 && 1.0 * sum / len < 2) { + return false; + } + if (k - j > 2 && 1.0 * sum / len >= 2 && len < 4) { + return false; + } - for(i = start+1, j = end-1; i <= j; i++) - { - CPoint p = o.pa[i], dp = p - sp; - double t = vx*dp.x+vy*dp.y, dx = vx*t + sp.x - p.x, dy = vy*t + sp.y - p.y; - t = dx*dx+dy*dy; - err += t; - t = sqrt(t); - if(vy*dx-dy*vx < 0) {if(minerr > -t) minerr = -t;} - else {if(maxerr < t) maxerr = t;} - } + if ((la.GetSize() / 2 + ra.GetSize() / 2) / 2 <= 2) { + if ((k + j) / 2 < 2 && k * j != 1) { + return false; + } + } - return((maxerr-minerr)/l < 0.1 || err/l < 1.5 || (fabs(maxerr) < 8 && fabs(minerr) < 8)); + double err = 0; + + CPoint sp = o.pa[start], ep = o.pa[end]; + + double minerr = 0, maxerr = 0; + + double vx = ep.x - sp.x, vy = ep.y - sp.y, l = sqrt(vx * vx + vy * vy); + vx /= l; + vy /= l; + + for (i = start + 1, j = end - 1; i <= j; i++) { + CPoint p = o.pa[i], dp = p - sp; + double t = vx * dp.x + vy * dp.y, dx = vx * t + sp.x - p.x, dy = vy * t + sp.y - p.y; + t = dx * dx + dy * dy; + err += t; + t = sqrt(t); + if (vy * dx - dy * vx < 0) { + if (minerr > -t) { + minerr = -t; + } + } else { + if (maxerr < t) { + maxerr = t; + } + } + } + + return ((maxerr - minerr) / l < 0.1 || err / l < 1.5 || (fabs(maxerr) < 8 && fabs(minerr) < 8)); } -static int CalcPossibleCurveDegree(COutline& o) +static int CalcPossibleCurveDegree(const COutline& o) { - int len2 = o.da.GetCount(); + size_t len2 = o.da.GetCount(); - CUIntArray la; + CUIntArray la; - for(int i = 0, j = 0; j < len2; j++) - { - if(j == len2-1 || o.da[j]) - { - la.Add(j-i); - i = j; - } - } + for (size_t i = 0, j = 0; j < len2; j++) { + if (j + 1 == len2 || o.da[j]) { + la.Add(UINT(j - i)); + i = j; + } + } - int len = la.GetCount(); + ptrdiff_t len = la.GetCount(); - int ret = 0; + int ret = 0; - // check if we can find a reason to add a penalty degree, or two :P - // it is mainly about looking for distant corners - { - int penalty = 0; + // check if we can find a reason to add a penalty degree, or two :P + // it is mainly about looking for distant corners + { + int penalty = 0; - int ma[2] = {0, 0}; - for(int i = 0; i < len; i++) ma[i&1] += la[i]; + int ma[2] = {0, 0}; + for (ptrdiff_t i = 0; i < len; i++) { + ma[i & 1] += la[i]; + } - int ca[2] = {ma[0], ma[1]}; - for(int i = 0; i < len; i++) - { - ca[i&1] -= la[i]; + int ca[2] = {ma[0], ma[1]}; + for (ptrdiff_t i = 0; i < len; i++) { + ca[i & 1] -= la[i]; - double c1 = 1.0*ca[0]/ma[0], c2 = 1.0*ca[1]/ma[1], c3 = 1.0*la[i]/ma[i&1]; + double c1 = 1.0 * ca[0] / ma[0], c2 = 1.0 * ca[1] / ma[1], c3 = 1.0 * la[i] / ma[i & 1]; - if(len2 > 16 && (fabs(c1-c2) > 0.7 || (c3 > 0.6 && la[i] > 5))) - {penalty = 2; break;} + if (len2 > 16 && (fabs(c1 - c2) > 0.7 || (c3 > 0.6 && la[i] > 5))) { + penalty = 2; + break; + } - if(fabs(c1-c2) > 0.6 || (c3 > 0.4 && la[i] > 5)) - {penalty = 1;} - } + if (fabs(c1 - c2) > 0.6 || (c3 > 0.4 && la[i] > 5)) { + penalty = 1; + } + } - ret += penalty; - } + ret += penalty; + } - la[0] <<= 1; - la[len-1] <<= 1; + la[0] <<= 1; + la[len - 1] <<= 1; - for(int i = 0; i < len; i+=2) - { - if(la[i] > 1) {ret++; i--;} // prependicular to the last chosen section and bigger then 1 -> add a degree and continue with the other dir - } + for (ptrdiff_t i = 0; i < len; i += 2) { + if (la[i] > 1) { + ret++; // prependicular to the last chosen section and bigger then 1 -> add a degree and continue with the other dir + i--; + } + } - return(ret); + return ret; } inline double vectlen(CPoint p) { - return(sqrt((double)(p.x*p.x+p.y*p.y))); + return sqrt((double)(p.x * p.x + p.y * p.y)); } inline double vectlen(CPoint p1, CPoint p2) { - return(vectlen(p2 - p1)); + return vectlen(p2 - p1); } -static bool MinMaxCosfi(COutline& o, double& mincf, double& maxcf) // not really cosfi, it is weighted by the distance from the segment endpoints, and since it would be always between -1 and 0, the applied sign marks side +static bool MinMaxCosfi(COutline& o, double& mincf, double& maxcf) // not really cosfi, it is weighted by the distance from the segment endpoints, and since it would be always between -1 and 0, the applied sign marks side { - CAtlArray& pa = o.pa; + CAtlArray& pa = o.pa; - int len = (int)pa.GetCount(); - if(len < 6) return(false); + int len = (int)pa.GetCount(); + if (len < 6) { + return false; + } - mincf = 1; - maxcf = -1; + mincf = 1; + maxcf = -1; - CPoint p = pa[len-1] - pa[0]; - double l = vectlen(p); + CPoint p = pa[len - 1] - pa[0]; + double l = vectlen(p); + UNREFERENCED_PARAMETER(l); - for(int i = 2; i < len-2; i++) // skip the endpoints, they aren't accurate - { - CPoint p1 = pa[0] - pa[i], p2 = pa[len-1] - pa[i]; - double l1 = vectlen(p1), l2 = vectlen(p2); - int sign = p1.x*p.y-p1.y*p.x >= 0 ? 1 : -1; + for (ptrdiff_t i = 2; i < len - 2; i++) { // skip the endpoints, they aren't accurate + CPoint p1 = pa[0] - pa[i], p2 = pa[len - 1] - pa[i]; + double l1 = vectlen(p1), l2 = vectlen(p2); + int sign = p1.x * p.y - p1.y * p.x >= 0 ? 1 : -1; - double c = (1.0*len/2 - fabs(i - 1.0*len/2)) / len * 2; // c: 0 -> 1 -> 0 + double c = (1.0 * len / 2 - fabs(i - 1.0 * len / 2)) / len * 2; // c: 0 -> 1 -> 0 - double cosfi = (1+(p1.x*p2.x+p1.y*p2.y)/(l1*l2)) * sign * c; - if(mincf > cosfi) mincf = cosfi; - if(maxcf < cosfi) maxcf = cosfi; - } + double cosfi = (1 + (p1.x * p2.x + p1.y * p2.y) / (l1 * l2)) * sign * c; + if (mincf > cosfi) { + mincf = cosfi; + } + if (maxcf < cosfi) { + maxcf = cosfi; + } + } - return(true); + return true; } static bool FitBezierVH(COutline& o, CPoint& p1, CPoint& p2) { - int i; - - CAtlArray& pa = o.pa; - - int len = (int)pa.GetCount(); - - if(len <= 1) - { - return(false); - } - else if(len == 2) - { - CPoint mid = pa[0]+pa[1]; - mid.x >>= 1; - mid.y >>= 1; - p1 = p2 = mid; - return(true); - } - - CPoint dir1 = pa[1] - pa[0], dir2 = pa[len-2] - pa[len-1]; - if((dir1.x&&dir1.y)||(dir2.x&&dir2.y)) - return(false); // we are only fitting beziers with hor./ver. endings - - if(CalcPossibleCurveDegree(o) > 3) - return(false); - - double mincf, maxcf; - if(MinMaxCosfi(o, mincf, maxcf)) - { - if(maxcf-mincf > 0.8 - || maxcf-mincf > 0.6 && (maxcf >= 0.4 || mincf <= -0.4)) - return(false); - } - - CPoint p0 = p1 = pa[0]; - CPoint p3 = p2 = pa[len-1]; - - CAtlArray pl; - pl.SetCount(len); - - double c10 = 0, c11 = 0, c12 = 0, c13 = 0, c1x = 0, c1y = 0; - double c20 = 0, c21 = 0, c22 = 0, c23 = 0, c2x = 0, c2y = 0; - double length = 0; - - for(pl[0] = 0, i = 1; i < len; i++) - { - CPoint diff = (pa[i] - pa[i-1]); - pl[i] = (length += sqrt((double)(diff.x*diff.x+diff.y*diff.y))); - } - - for(i = 0; i < len; i++) - { - double t1 = pl[i] / length; - double t2 = t1*t1; - double t3 = t2*t1; - double it1 = 1 - t1; - double it2 = it1*it1; - double it3 = it2*it1; - - double dc1 = 3.0*it2*t1; - double dc2 = 3.0*it1*t2; - - c10 += it3*dc1; - c11 += dc1*dc1; - c12 += dc2*dc1; - c13 += t3*dc1; - c1x += pa[i].x*dc1; - c1y += pa[i].y*dc1; - - c20 += it3*dc2; - c21 += dc1*dc2; - c22 += dc2*dc2; - c23 += t3*dc2; - c2x += pa[i].x*dc2; - c2y += pa[i].y*dc2; - } - - if(dir1.y == 0 && dir2.x == 0) - { - p1.x = (int)((c1x - c10*p0.x - c12*p3.x - c13*p3.x) / c11 + 0.5); - p2.y = (int)((c2y - c20*p0.y - c21*p0.y - c23*p3.y) / c22 + 0.5); - } - else if(dir1.x == 0 && dir2.y == 0) - { - p2.x = (int)((c2x - c20*p0.x - c21*p0.x - c23*p3.x) / c22 + 0.5); - p1.y = (int)((c1y - c10*p0.y - c12*p3.y - c13*p3.y) / c11 + 0.5); - } - else if(dir1.y == 0 && dir2.y == 0) - { - // cramer's rule - double D = c11*c22 - c12*c21; - p1.x = (int)(((c1x-c10*p0.x-c13*p3.x)*c22 - c12*(c2x-c20*p0.x-c23*p3.x)) / D + 0.5); - p2.x = (int)((c11*(c2x-c20*p0.x-c23*p3.x) - (c1x-c10*p0.x-c13*p3.x)*c21) / D + 0.5); - } - else if(dir1.x == 0 && dir2.x == 0) - { - // cramer's rule - double D = c11*c22 - c12*c21; - p1.y = (int)(((c1y-c10*p0.y-c13*p3.y)*c22 - c12*(c2y-c20*p0.y-c23*p3.y)) / D + 0.5); - p2.y = (int)((c11*(c2y-c20*p0.y-c23*p3.y) - (c1y-c10*p0.y-c13*p3.y)*c21) / D + 0.5); - } - else // must not happen - { - ASSERT(0); - return(false); - } - - // check for "inside-out" beziers - CPoint dir3 = p1 - p0, dir4 = p2 - p3; - if((dir1.x*dir3.x+dir1.y*dir3.y) <= 0 || (dir2.x*dir4.x+dir2.y*dir4.y) <= 0) - return(false); - - return(true); -} + int i; -int CVobSubImage::GrabSegment(int start, COutline& o, COutline& ret) -{ - ret.RemoveAll(); + CAtlArray& pa = o.pa; + + int len = (int)pa.GetCount(); + + if (len <= 1) { + return false; + } else if (len == 2) { + CPoint mid = pa[0] + pa[1]; + mid.x >>= 1; + mid.y >>= 1; + p1 = p2 = mid; + return true; + } - int len = o.pa.GetCount(); - - int cur = (start)%len, first = -1, last = -1; - int curDir = 0, lastDir = 0; + CPoint dir1 = pa[1] - pa[0], dir2 = pa[len - 2] - pa[len - 1]; + if ((dir1.x && dir1.y) || (dir2.x && dir2.y)) { + return false; // we are only fitting beziers with hor./ver. endings + } - for(int i = 0; i < len; i++) - { - cur = (cur+1)%len; + if (CalcPossibleCurveDegree(o) > 3) { + return false; + } - if(o.da[cur] == 0) continue; + double mincf, maxcf; + if (MinMaxCosfi(o, mincf, maxcf)) { + if (maxcf - mincf > 0.8 + || maxcf - mincf > 0.6 && (maxcf >= 0.4 || mincf <= -0.4)) { + return false; + } + } - if(first == -1) first = cur; + CPoint p0 = p1 = pa[0]; + CPoint p3 = p2 = pa[len - 1]; - if(lastDir == o.da[cur]) - { - CPoint startp = o.pa[first]+o.pa[start]; startp.x >>= 1; startp.y >>= 1; - CPoint endp = o.pa[last]+o.pa[cur]; endp.x >>= 1; endp.y >>= 1; + CAtlArray pl; + pl.SetCount(len); - if(first < start) first += len; - start = ((start+first)>>1)+1; - if(start >= len) start -= len; - if(cur < last) cur += len; - cur = ((last+cur+1)>>1); - if(cur >= len) cur -= len; + double c10 = 0, c11 = 0, c12 = 0, c13 = 0, c1x = 0, c1y = 0; + double c20 = 0, c21 = 0, c22 = 0, c23 = 0, c2x = 0, c2y = 0; + double length = 0; - ret.Add(startp, 0); + for (pl[0] = 0, i = 1; i < len; i++) { + CPoint diff = (pa[i] - pa[i - 1]); + pl[i] = (length += sqrt((double)(diff.x * diff.x + diff.y * diff.y))); + } - while(start != cur) - { - ret.Add(o.pa[start], o.da[start]); + for (i = 0; i < len; i++) { + double t1 = pl[i] / length; + double t2 = t1 * t1; + double t3 = t2 * t1; + double it1 = 1 - t1; + double it2 = it1 * it1; + double it3 = it2 * it1; + + double dc1 = 3.0 * it2 * t1; + double dc2 = 3.0 * it1 * t2; + + c10 += it3 * dc1; + c11 += dc1 * dc1; + c12 += dc2 * dc1; + c13 += t3 * dc1; + c1x += pa[i].x * dc1; + c1y += pa[i].y * dc1; + + c20 += it3 * dc2; + c21 += dc1 * dc2; + c22 += dc2 * dc2; + c23 += t3 * dc2; + c2x += pa[i].x * dc2; + c2y += pa[i].y * dc2; + } - start++; - if(start >= len) start -= len; - } + if (dir1.y == 0 && dir2.x == 0) { + p1.x = (int)((c1x - c10 * p0.x - c12 * p3.x - c13 * p3.x) / c11 + 0.5); + p2.y = (int)((c2y - c20 * p0.y - c21 * p0.y - c23 * p3.y) / c22 + 0.5); + } else if (dir1.x == 0 && dir2.y == 0) { + p2.x = (int)((c2x - c20 * p0.x - c21 * p0.x - c23 * p3.x) / c22 + 0.5); + p1.y = (int)((c1y - c10 * p0.y - c12 * p3.y - c13 * p3.y) / c11 + 0.5); + } else if (dir1.y == 0 && dir2.y == 0) { + // cramer's rule + double D = c11 * c22 - c12 * c21; + p1.x = (int)(((c1x - c10 * p0.x - c13 * p3.x) * c22 - c12 * (c2x - c20 * p0.x - c23 * p3.x)) / D + 0.5); + p2.x = (int)((c11 * (c2x - c20 * p0.x - c23 * p3.x) - (c1x - c10 * p0.x - c13 * p3.x) * c21) / D + 0.5); + } else if (dir1.x == 0 && dir2.x == 0) { + // cramer's rule + double D = c11 * c22 - c12 * c21; + p1.y = (int)(((c1y - c10 * p0.y - c13 * p3.y) * c22 - c12 * (c2y - c20 * p0.y - c23 * p3.y)) / D + 0.5); + p2.y = (int)((c11 * (c2y - c20 * p0.y - c23 * p3.y) - (c1y - c10 * p0.y - c13 * p3.y) * c21) / D + 0.5); + } else { // must not happen + ASSERT(0); + return false; + } - ret.Add(endp, 0); + // check for "inside-out" beziers + CPoint dir3 = p1 - p0, dir4 = p2 - p3; + if ((dir1.x * dir3.x + dir1.y * dir3.y) <= 0 || (dir2.x * dir4.x + dir2.y * dir4.y) <= 0) { + return false; + } - return(last); - } + return true; +} - lastDir = o.da[cur]; - last = cur; - } +int CVobSubImage::GrabSegment(int start, const COutline& o, COutline& ret) +{ + ret.RemoveAll(); + + int len = int(o.pa.GetCount()); + + int cur = (start) % len, first = -1, last = -1; + int lastDir = 0; + + for (ptrdiff_t i = 0; i < len; i++) { + cur = (cur + 1) % len; + + if (o.da[cur] == 0) { + continue; + } + + if (first == -1) { + first = cur; + } + + if (lastDir == o.da[cur]) { + CPoint startp = o.pa[first] + o.pa[start]; + startp.x >>= 1; + startp.y >>= 1; + CPoint endp = o.pa[last] + o.pa[cur]; + endp.x >>= 1; + endp.y >>= 1; + + if (first < start) { + first += len; + } + start = ((start + first) >> 1) + 1; + if (start >= len) { + start -= len; + } + if (cur < last) { + cur += len; + } + cur = ((last + cur + 1) >> 1); + if (cur >= len) { + cur -= len; + } + + ret.Add(startp, 0); + + while (start != cur) { + ret.Add(o.pa[start], o.da[start]); + + start++; + if (start >= len) { + start -= len; + } + } + + ret.Add(endp, 0); + + return last; + } + + lastDir = o.da[cur]; + last = cur; + } - ASSERT(0); + ASSERT(0); - return(start); + return start; } -void CVobSubImage::SplitOutline(COutline& o, COutline& o1, COutline& o2) +void CVobSubImage::SplitOutline(const COutline& o, COutline& o1, COutline& o2) { - int len = o.pa.GetCount(); - if(len < 4) return; - - CAtlArray la, sa, ea; - - int i, j, k; - - for(i = 0, j = 0; j < len; j++) - { - if(j == len-1 || o.da[j]) - { - la.Add(j-i); - sa.Add(i); - ea.Add(j); - i = j; - } - } - - int maxlen = 0, maxidx = -1; - int maxlen2 = 0, maxidx2 = -1; - - for(i = 0; i < la.GetCount(); i++) - { - if(maxlen < la[i]) - { - maxlen = la[i]; - maxidx = i; - } - - if(maxlen2 < la[i] && i > 0 && i < la.GetCount()-1) - { - maxlen2 = la[i]; - maxidx2 = i; - } - } - - if(maxlen == maxlen2) maxidx = maxidx2; // if equal choose the inner section - - j = (sa[maxidx] + ea[maxidx]) >> 1, k = (sa[maxidx] + ea[maxidx] + 1) >> 1; - - o1.RemoveAll(); - o2.RemoveAll(); - - for(i = 0; i <= j; i++) - o1.Add(o.pa[i], o.da[i]); - - if(j != k) - { - CPoint mid = o.pa[j]+o.pa[k]; mid.x >>= 1; mid.y >>= 1; - o1.Add(mid, 0); - o2.Add(mid, 0); - } - - for(i = k; i < len; i++) - o2.Add(o.pa[i], o.da[i]); + size_t len = o.pa.GetCount(); + if (len < 4) { + return; + } + + CAtlArray la, sa, ea; + + size_t i, j, k; + + for (i = 0, j = 0; j < len; j++) { + if (j + 1 == len || o.da[j]) { + la.Add(unsigned int(j - i)); + sa.Add(unsigned int(i)); + ea.Add(unsigned int(j)); + i = j; + } + } + + size_t maxlen = 0, maxidx = -1; + size_t maxlen2 = 0, maxidx2 = -1; + + for (i = 0; i < la.GetCount(); i++) { + if (maxlen < la[i]) { + maxlen = la[i]; + maxidx = i; + } + + if (maxlen2 < la[i] && i > 0 && i < la.GetCount() - 1) { + maxlen2 = la[i]; + maxidx2 = i; + } + } + + ASSERT(maxidx != -1 && maxidx2 != -1); + + if (maxlen == maxlen2) { + maxidx = maxidx2; // if equal choose the inner section + } + + j = (sa[maxidx] + ea[maxidx]) >> 1, k = (sa[maxidx] + ea[maxidx] + 1) >> 1; + + o1.RemoveAll(); + o2.RemoveAll(); + + for (i = 0; i <= j; i++) { + o1.Add(o.pa[i], o.da[i]); + } + + if (j != k) { + CPoint mid = o.pa[j] + o.pa[k]; + mid.x >>= 1; + mid.y >>= 1; + o1.Add(mid, 0); + o2.Add(mid, 0); + } + + for (i = k; i < len; i++) { + o2.Add(o.pa[i], o.da[i]); + } } void CVobSubImage::AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints) { - int i, len = o.pa.GetCount(); - if(len < 3) return; - - int nLeftTurns = 0, nRightTurns = 0; - - for(i = 0; i < len; i++) - { - if(o.da[i] == -1) nLeftTurns++; - else if(o.da[i] == 1) nRightTurns++; - } - - if(nLeftTurns == 0 && nRightTurns == 0) // line - { - pathTypes.Add(PT_LINETO); - pathPoints.Add(o.pa[len-1]); - - return; - } - - if(nLeftTurns == 0 || nRightTurns == 0) // b-spline - { - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[0]+(o.pa[0]-o.pa[1])); - - for(i = 0; i < 3; i++) - { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[i]); - } - - for(; i < len; i++) - { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[i]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[len-1]+(o.pa[len-1]-o.pa[len-2])); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[len-1]); - - return; - } - - int start, end; - if(FitLine(o, start, end)) // b-spline, line, b-spline - { - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[0]+(o.pa[0]-o.pa[1])); - - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[0]); - - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[1]); - - CPoint p[4], pp, d = o.pa[end] - o.pa[start]; - double l = sqrt((double)(d.x*d.x+d.y*d.y)), dx = 1.0 * d.x / l, dy = 1.0 * d.y / l; - - pp = o.pa[start]-o.pa[start-1]; - double l1 = abs(pp.x)+abs(pp.y); - pp = o.pa[end]-o.pa[end+1]; - double l2 = abs(pp.x)+abs(pp.y); - p[0] = CPoint((int)(1.0 * o.pa[start].x + dx*l1 + 0.5), (int)(1.0 * o.pa[start].y + dy*l1 + 0.5)); - p[1] = CPoint((int)(1.0 * o.pa[start].x + dx*l1*2 + 0.5), (int)(1.0 * o.pa[start].y + dy*l1*2 + 0.5)); - p[2] = CPoint((int)(1.0 * o.pa[end].x - dx*l2*2 + 0.5), (int)(1.0 * o.pa[end].y - dy*l2*2 + 0.5)); - p[3] = CPoint((int)(1.0 * o.pa[end].x - dx*l2 + 0.5), (int)(1.0 * o.pa[end].y - dy*l2 + 0.5)); - - if(start == 1) - { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(p[0]); - } - else - { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[2]); - - for(int i = 3; i <= start; i++) - { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[i]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[0]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[1]); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(p[0]); - - pathTypes.Add(PT_LINETO); - pathPoints.Add(p[3]); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(p[2]); - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[3]); - - for(i = end; i < len; i++) - { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[i]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[len-1]+(o.pa[len-1]-o.pa[len-2])); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[len-1]); - - return; - } - - CPoint p1, p2; - if(FitBezierVH(o, p1, p2)) // bezier - { - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(p1); - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(p2); - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(o.pa[o.pa.GetCount()-1]); - - return; - } - - COutline o1, o2; - SplitOutline(o, o1, o2); - AddSegment(o1, pathTypes, pathPoints); - AddSegment(o2, pathTypes, pathPoints); + int i, len = int(o.pa.GetCount()); + if (len < 3) { + return; + } + + int nLeftTurns = 0, nRightTurns = 0; + + for (i = 0; i < len; i++) { + if (o.da[i] == -1) { + nLeftTurns++; + } else if (o.da[i] == 1) { + nRightTurns++; + } + } + + if (nLeftTurns == 0 && nRightTurns == 0) { // line + pathTypes.Add(PT_LINETO); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + if (nLeftTurns == 0 || nRightTurns == 0) { // b-spline + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); + + for (i = 0; i < 3; i++) { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[i]); + } + + for (; i < len; i++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[i]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + int start, end; + if (FitLine(o, start, end)) { // b-spline, line, b-spline + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); + + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[0]); + + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[1]); + + CPoint p[4], pp, d = o.pa[end] - o.pa[start]; + double l = sqrt((double)(d.x * d.x + d.y * d.y)), dx = 1.0 * d.x / l, dy = 1.0 * d.y / l; + + pp = o.pa[start] - o.pa[start - 1]; + double l1 = abs(pp.x) + abs(pp.y); + pp = o.pa[end] - o.pa[end + 1]; + double l2 = abs(pp.x) + abs(pp.y); + p[0] = CPoint((int)(1.0 * o.pa[start].x + dx * l1 + 0.5), (int)(1.0 * o.pa[start].y + dy * l1 + 0.5)); + p[1] = CPoint((int)(1.0 * o.pa[start].x + dx * l1 * 2 + 0.5), (int)(1.0 * o.pa[start].y + dy * l1 * 2 + 0.5)); + p[2] = CPoint((int)(1.0 * o.pa[end].x - dx * l2 * 2 + 0.5), (int)(1.0 * o.pa[end].y - dy * l2 * 2 + 0.5)); + p[3] = CPoint((int)(1.0 * o.pa[end].x - dx * l2 + 0.5), (int)(1.0 * o.pa[end].y - dy * l2 + 0.5)); + + if (start == 1) { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(p[0]); + } else { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[2]); + + for (ptrdiff_t k = 3; k <= start; k++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[k]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[0]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[1]); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(p[0]); + + pathTypes.Add(PT_LINETO); + pathPoints.Add(p[3]); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(p[2]); + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[3]); + + for (i = end; i < len; i++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[i]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + CPoint p1, p2; + if (FitBezierVH(o, p1, p2)) { // bezier + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(p1); + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(p2); + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(o.pa[o.pa.GetCount() - 1]); + + return; + } + + COutline o1, o2; + SplitOutline(o, o1, o2); + AddSegment(o1, pathTypes, pathPoints); + AddSegment(o2, pathTypes, pathPoints); } bool CVobSubImage::Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool fSmooth, int scale) { - CPoint topleft; - CAutoPtr > ol(GetOutlineList(topleft)); - if(!ol) return(false); - - POSITION pos; - - pos = ol->GetHeadPosition(); - while(pos) - { - CAtlArray& pa = ol->GetNext(pos)->pa; - for(size_t i = 0; i < pa.GetCount(); i++) - { - pa[i].x = (pa[i].x-topleft.x)<GetHeadPosition(); - while(pos) - { - COutline& o = *ol->GetNext(pos), o2; - - if(fSmooth) - { - int i = 0, iFirst = -1; - - while(1) - { - i = GrabSegment(i, o, o2); - - if(i == iFirst) break; - - if(iFirst < 0) - { - iFirst = i; - pathTypes.Add(PT_MOVETO); - pathPoints.Add(o2.pa[0]); - } - - AddSegment(o2, pathTypes, pathPoints); - } - } - else - { -/* - for(int i = 1, len = o.pa.GetSize(); i < len; i++) - { - if(int dir = o.da[i-1]) - { - CPoint dir2 = o.pa[i] - o.pa[i-1]; - dir2.x /= 2; dir2.y /= 2; - CPoint dir1 = dir > 0 ? CPoint(dir2.y, -dir2.x) : CPoint(-dir2.y, dir2.x); - i = i; - o.pa[i-1] -= dir1; - o.pa.InsertAt(i, o.pa[i-1] + dir2); - o.da.InsertAt(i, -dir); - o.pa.InsertAt(i+1, o.pa[i] + dir1); - o.da.InsertAt(i+1, dir); - i += 2; - len += 2; - } - } -*/ - pathTypes.Add(PT_MOVETO); - pathPoints.Add(o.pa[0]); - - for(int i = 1, len = o.pa.GetCount(); i < len; i++) - { - pathTypes.Add(PT_LINETO); - pathPoints.Add(o.pa[i]); - } - } - } - - return !pathTypes.IsEmpty(); + CPoint topleft; + CAutoPtr> ol(GetOutlineList(topleft)); + if (!ol) { + return false; + } + + POSITION pos; + + pos = ol->GetHeadPosition(); + while (pos) { + CAtlArray& pa = ol->GetNext(pos)->pa; + for (size_t i = 0; i < pa.GetCount(); i++) { + pa[i].x = (pa[i].x - topleft.x) << scale; + pa[i].y = (pa[i].y - topleft.y) << scale; + } + } + + pos = ol->GetHeadPosition(); + while (pos) { + COutline& o = *ol->GetNext(pos), o2; + + if (fSmooth) { + int i = 0, iFirst = -1; + + for (;;) { + i = GrabSegment(i, o, o2); + + if (i == iFirst) { + break; + } + + if (iFirst < 0) { + iFirst = i; + pathTypes.Add(PT_MOVETO); + pathPoints.Add(o2.pa[0]); + } + + AddSegment(o2, pathTypes, pathPoints); + } + } else { + /* + for (ptrdiff_t i = 1, len = o.pa.GetSize(); i < len; i++) + { + if (int dir = o.da[i-1]) + { + CPoint dir2 = o.pa[i] - o.pa[i-1]; + dir2.x /= 2; dir2.y /= 2; + CPoint dir1 = dir > 0 ? CPoint(dir2.y, -dir2.x) : CPoint(-dir2.y, dir2.x); + i = i; + o.pa[i-1] -= dir1; + o.pa.InsertAt(i, o.pa[i-1] + dir2); + o.da.InsertAt(i, -dir); + o.pa.InsertAt(i+1, o.pa[i] + dir1); + o.da.InsertAt(i+1, dir); + i += 2; + len += 2; + } + } + */ + pathTypes.Add(PT_MOVETO); + pathPoints.Add(o.pa[0]); + + for (size_t i = 1, len = o.pa.GetCount(); i < len; i++) { + pathTypes.Add(PT_LINETO); + pathPoints.Add(o.pa[i]); + } + } + } + + return !pathTypes.IsEmpty(); } bool CVobSubImage::Polygonize(CStringW& assstr, bool fSmooth, int scale) { - CAtlArray pathTypes; - CAtlArray pathPoints; - - if(!Polygonize(pathTypes, pathPoints, fSmooth, scale)) - return(false); - - assstr.Format(L"{\\an7\\pos(%d,%d)\\p%d}", rect.left, rect.top, 1+scale); -// assstr.Format(L"{\\p%d}", 1+scale); - - BYTE lastType = 0; - - int nPoints = pathTypes.GetCount(); - - for(int i = 0; i < nPoints; i++) - { - CStringW s; - - switch(pathTypes[i]) - { - case PT_MOVETO: - if(lastType != PT_MOVETO) assstr += L"m "; - s.Format(L"%d %d ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_MOVETONC: - if(lastType != PT_MOVETONC) assstr += L"n "; - s.Format(L"%d %d ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_LINETO: - if(lastType != PT_LINETO) assstr += L"l "; - s.Format(L"%d %d ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_BEZIERTO: - if(i < nPoints-2) - { - if(lastType != PT_BEZIERTO) assstr += L"b "; - s.Format(L"%d %d %d %d %d %d ", pathPoints[i].x, pathPoints[i].y, pathPoints[i+1].x, pathPoints[i+1].y, pathPoints[i+2].x, pathPoints[i+2].y); - i+=2; - } - break; - case PT_BSPLINETO: - if(i < nPoints-2) - { - if(lastType != PT_BSPLINETO) assstr += L"s "; - s.Format(L"%d %d %d %d %d %d ", pathPoints[i].x, pathPoints[i].y, pathPoints[i+1].x, pathPoints[i+1].y, pathPoints[i+2].x, pathPoints[i+2].y); - i+=2; - } - break; - case PT_BSPLINEPATCHTO: - if(lastType != PT_BSPLINEPATCHTO) assstr += L"p "; - s.Format(L"%d %d ", pathPoints[i].x, pathPoints[i].y); - break; - } - - lastType = pathTypes[i]; - - assstr += s; - } - - assstr += L"{\\p0}"; - - return nPoints > 0; + CAtlArray pathTypes; + CAtlArray pathPoints; + + if (!Polygonize(pathTypes, pathPoints, fSmooth, scale)) { + return false; + } + + assstr.Format(L"{\\an7\\pos(%d,%d)\\p%d}", rect.left, rect.top, 1 + scale); + // assstr.Format(L"{\\p%d}", 1+scale); + + BYTE lastType = 0; + + size_t nPoints = pathTypes.GetCount(); + + for (size_t i = 0; i < nPoints; i++) { + CStringW s; + + switch (pathTypes[i]) { + case PT_MOVETO: + if (lastType != PT_MOVETO) { + assstr += L"m "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_MOVETONC: + if (lastType != PT_MOVETONC) { + assstr += L"n "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_LINETO: + if (lastType != PT_LINETO) { + assstr += L"l "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_BEZIERTO: + if (i + 2 < nPoints) { + if (lastType != PT_BEZIERTO) { + assstr += L"b "; + } + s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); + i += 2; + } + break; + case PT_BSPLINETO: + if (i + 2 < nPoints) { + if (lastType != PT_BSPLINETO) { + assstr += L"s "; + } + s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); + i += 2; + } + break; + case PT_BSPLINEPATCHTO: + if (lastType != PT_BSPLINEPATCHTO) { + assstr += L"p "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + } + + lastType = pathTypes[i]; + + assstr += s; + } + + assstr += L"{\\p0}"; + + return nPoints > 0; } void CVobSubImage::Scale2x() { - int w = rect.Width(), h = rect.Height(); + int w = rect.Width(), h = rect.Height(); - DWORD* src = (DWORD*)lpPixels; - DWORD* dst = new DWORD[w*h]; + if (w > 0 && h > 0) { + DWORD* src = (DWORD*)lpPixels; + DWORD* dst = DEBUG_NEW DWORD[w * h]; - for(int y = 0; y < h; y++) - { - for(int x = 0; x < w; x++, src++, dst++) - { - DWORD E = *src; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src++, dst++) { + DWORD E = *src; - DWORD A = x > 0 && y > 0 ? src[-w-1] : E; - DWORD B = y > 0 ? src[-w] : E; - DWORD C = x < w-1 && y > 0 ? src[-w+1] : E; + DWORD A = x > 0 && y > 0 ? src[-w - 1] : E; + DWORD B = y > 0 ? src[-w] : E; + DWORD C = x < w - 1 && y > 0 ? src[-w + 1] : E; + UNREFERENCED_PARAMETER(A); + UNREFERENCED_PARAMETER(C); - DWORD D = x > 0 ? src[-1] : E;; - DWORD F = x < w-1 ? src[+1] : E;; + DWORD D = x > 0 ? src[-1] : E; + DWORD F = x < w - 1 ? src[+1] : E; - DWORD G = x > 0 && y < h-1 ? src[+w-1] : E; - DWORD H = y < h-1 ? src[+w] : E; - DWORD I = x < w-1 && y < h-1 ? src[+w+1] : E; + DWORD G = x > 0 && y < h - 1 ? src[+w - 1] : E; + DWORD H = y < h - 1 ? src[+w] : E; + DWORD I = x < w - 1 && y < h - 1 ? src[+w + 1] : E; + UNREFERENCED_PARAMETER(G); + UNREFERENCED_PARAMETER(I); - DWORD E0 = D == B && B != F && D != H ? D : E; - DWORD E1 = B == F && B != D && F != H ? F : E; - DWORD E2 = D == H && D != B && H != F ? D : E; - DWORD E3 = H == F && D != H && B != F ? F : E; + DWORD E0 = D == B && B != F && D != H ? D : E; + DWORD E1 = B == F && B != D && F != H ? F : E; + DWORD E2 = D == H && D != B && H != F ? D : E; + DWORD E3 = H == F && D != H && B != F ? F : E; - *dst = ((((E0&0x00ff00ff)+(E1&0x00ff00ff)+(E2&0x00ff00ff)+(E3&0x00ff00ff)+2)>>2)&0x00ff00ff) - | (((((E0>>8)&0x00ff00ff)+((E1>>8)&0x00ff00ff)+((E2>>8)&0x00ff00ff)+((E3>>8)&0x00ff00ff)+2)<<6)&0xff00ff00); - } - } + *dst = ((((E0 & 0x00ff00ff) + (E1 & 0x00ff00ff) + (E2 & 0x00ff00ff) + (E3 & 0x00ff00ff) + 2) >> 2) & 0x00ff00ff) + | (((((E0 >> 8) & 0x00ff00ff) + ((E1 >> 8) & 0x00ff00ff) + ((E2 >> 8) & 0x00ff00ff) + ((E3 >> 8) & 0x00ff00ff) + 2) << 6) & 0xff00ff00); + } + } - src -= w*h; - dst -= w*h; + src -= w * h; + dst -= w * h; - memcpy(src, dst, w*h*4); + memcpy(src, dst, w * h * 4); - delete [] dst; + delete [] dst; + } } diff --git a/src/subtitles/VobSubImage.h b/src/subtitles/VobSubImage.h index 13a990c8f..90fa738a0 100644 --- a/src/subtitles/VobSubImage.h +++ b/src/subtitles/VobSubImage.h @@ -1,21 +1,21 @@ -/* - * Copyright (C) 2003-2006 Gabest - * http://www.gabest.org +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 see Authors.txt * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html + * This file is part of MPC-HC. + * + * MPC-HC is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * MPC-HC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * */ @@ -23,68 +23,74 @@ #include -typedef struct -{ - CAtlArray pa; - CAtlArray da; - void RemoveAll() {pa.RemoveAll(); da.RemoveAll();} - void Add(CPoint p, int d) {pa.Add(p); da.Add(d);} -} COutline; +struct COutline { + CAtlArray pa; + CAtlArray da; + void RemoveAll() { + pa.RemoveAll(); + da.RemoveAll(); + } + void Add(CPoint p, int d) { + pa.Add(p); + da.Add(d); + } +}; class CVobSubImage { - friend class CVobSubFile; + friend class CVobSubFile; private: - CSize org; - RGBQUAD* lpTemp1; - RGBQUAD* lpTemp2; + CSize org; + RGBQUAD* lpTemp1; + RGBQUAD* lpTemp2; - WORD nOffset[2], nPlane; - bool fCustomPal; - char fAligned; // we are also using this for calculations, that's why it is char instead of bool... - int tridx; - RGBQUAD* orgpal /*[16]*/,* cuspal /*[4]*/; + size_t nOffset[2], nPlane; + bool fCustomPal; + bool fAligned; + int tridx; + RGBQUAD* orgpal /*[16]*/, * cuspal /*[4]*/; - bool Alloc(int w, int h); - void Free(); + bool Alloc(int w, int h); + void Free(); - BYTE GetNibble(BYTE* lpData); - void DrawPixels(CPoint p, int length, int colorid); - void TrimSubImage(); + BYTE GetNibble(const BYTE* lpData); + void DrawPixels(CPoint p, int length, size_t colorId); + void TrimSubImage(); public: - int iLang, iIdx; - bool fForced; - __int64 start, delay; - CRect rect; - typedef struct {BYTE pal:4, tr:4;} SubPal; - SubPal pal[4]; - RGBQUAD* lpPixels; - - CVobSubImage(); - virtual ~CVobSubImage(); - - void Invalidate() {iLang = iIdx = -1;} - - void GetPacketInfo(BYTE* lpData, int packetsize, int datasize); - bool Decode(BYTE* lpData, int packetsize, int datasize, - bool fCustomPal, - int tridx, - RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, - bool fTrim); - - ///////// + size_t iLang, iIdx; + bool fForced, fAnimated; + int tCurrent; + __int64 start, delay; + CRect rect; + struct SubPal { + BYTE pal: 4, tr: 4; + }; + SubPal pal[4]; + RGBQUAD* lpPixels; + + CVobSubImage(); + virtual ~CVobSubImage(); + + void Invalidate() { iLang = iIdx = -1; } + + void GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t = INT_MAX); + bool Decode(BYTE* lpData, size_t packetSize, size_t dataSize, int t, + bool fCustomPal, + int tridx, + RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, + bool fTrim); private: - CAutoPtrList* GetOutlineList(CPoint& topleft); - int GrabSegment(int start, COutline& o, COutline& ret); - void SplitOutline(COutline& o, COutline& o1, COutline& o2); - void AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints); + CAutoPtrList* GetOutlineList(CPoint& topleft); + int GrabSegment(int start, const COutline& o, COutline& ret); + void SplitOutline(const COutline& o, COutline& o1, COutline& o2); + void AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints); public: - bool Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool fSmooth, int scale); - bool Polygonize(CStringW& assstr, bool fSmooth = true, int scale = 3); + bool Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool fSmooth, int scale); + bool Polygonize(CStringW& assstr, bool fSmooth = true, int scale = 3); void Scale2x(); };