VobSubFileRipper.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
00019  *
00020  */
00021 
00022 #include "StdAfx.h"
00023 #include "vobsubfileripper.h"
00024 #include "..\decss\VobDec.h"
00025 #include "..\subtitles\CCDecoder.h"
00026 
00027 //
00028 // CVobSubFileRipper
00029 //
00030 
00031 CVobSubFileRipper::CVobSubFileRipper()
00032         : CVobSubFile(NULL)
00033         , m_fThreadActive(false)
00034         , m_fBreakThread(false)
00035         , m_fIndexing(false)
00036 {
00037         m_rd.Reset();
00038         CAMThread::Create();
00039 }
00040 
00041 CVobSubFileRipper::~CVobSubFileRipper()
00042 {
00043         CAMThread::CallWorker(CMD_EXIT);
00044         CAMThread::Close();
00045 }
00046 
00047 STDMETHODIMP CVobSubFileRipper::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00048 {
00049         return 
00050                 QI(IVSFRipper)
00051                 __super::NonDelegatingQueryInterface(riid, ppv);
00052 }
00053 
00054 void CVobSubFileRipper::Log(log_t type, LPCTSTR lpszFormat, ...)
00055 {
00056         CAutoLock cAutoLock(&m_csCallback);
00057         if(!m_pCallback) return;
00058 
00059         TCHAR buff[1024];
00060 
00061         va_list args;
00062         va_start(args, lpszFormat);
00063         _vstprintf(buff, lpszFormat, args);
00064         va_end(args);
00065 
00066         CString msg;
00067         switch(type)
00068         {
00069         default:
00070         case LOG_INFO: msg = _T(""); break;
00071         case LOG_WARNING: msg = _T("WARNING: "); break;
00072         case LOG_ERROR: msg = _T("ERROR: "); break;
00073         }
00074 
00075         msg += buff;
00076 
00077         m_pCallback->OnMessage(msg);
00078 }
00079 
00080 void CVobSubFileRipper::Progress(double progress)
00081 {
00082         CAutoLock cAutoLock(&m_csCallback);
00083         if(!m_pCallback) return;
00084 
00085         m_pCallback->OnProgress(progress);
00086 }
00087 
00088 void CVobSubFileRipper::Finished(bool fSucceeded)
00089 {
00090         CAutoLock cAutoLock(&m_csCallback);
00091         if(!m_pCallback) return;
00092 
00093         m_pCallback->OnFinished(fSucceeded);
00094 }
00095 
00096 #define ReadBEb(var) \
00097         f.Read(&((BYTE*)&var)[0], 1); \
00098 
00099 #define ReadBEw(var) \
00100         f.Read(&((BYTE*)&var)[1], 1); \
00101         f.Read(&((BYTE*)&var)[0], 1); \
00102 
00103 #define ReadBEdw(var) \
00104     f.Read(&((BYTE*)&var)[3], 1); \
00105         f.Read(&((BYTE*)&var)[2], 1); \
00106         f.Read(&((BYTE*)&var)[1], 1); \
00107         f.Read(&((BYTE*)&var)[0], 1); \
00108 
00109 bool CVobSubFileRipper::LoadIfo(CString fn)
00110 {
00111         CString str;
00112 
00113         CFileStatus status;
00114         if(!CFileGetStatus(fn, status) || !status.m_size)
00115         {
00116                 Log(LOG_ERROR, _T("Invalid ifo"));
00117                 return(false);
00118         }
00119 
00120         CFile f;
00121         if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
00122         {
00123                 Log(LOG_ERROR, _T("Cannot open ifo"));
00124                 return(false);
00125         }
00126 
00127         Log(LOG_INFO, _T("Opening ifo OK"));
00128 
00129         char hdr[13];
00130         f.Read(hdr, 12);
00131         hdr[12] = 0;
00132         if(strcmp(hdr, "DVDVIDEO-VTS"))
00133         {
00134                 Log(LOG_ERROR, _T("Not a Video Title Set IFO file!"));
00135                 return(false);
00136         }
00137 
00138         // lang ids
00139 
00140         f.Seek(0x254, CFile::begin);
00141 
00142         WORD ids[32];
00143         memset(ids, 0, sizeof(ids));
00144 
00145         int len = 0;
00146         ReadBEw(len);
00147 
00148         for(int i = 0; i < len; i++)
00149         {
00150                 f.Seek(2, CFile::current); // 01 00 ?
00151                 ReadBEw(ids[i]);
00152                 if(ids[i] == 0) ids[i] = '--';
00153                 f.Seek(2, CFile::current); // 00 00 ?
00154         }
00155 
00156         /* Video info */
00157 
00158         f.Seek(0x200, CFile::begin);
00159         f.Read(&m_rd.vidinfo, 2);
00160 
00161         SIZE res[4][2] =
00162         {
00163                 {{720,480},{720,576}},
00164                 {{704,480},{704,576}},
00165                 {{352,480},{352,576}},
00166                 {{352,240},{352,288}}
00167         };
00168 
00169         m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system&1];
00170 
00171         double rate = (m_rd.vidinfo.system == 0) ? 30.0/29.97 : 1.0;
00172 
00173         /* PGCs */
00174 
00175         {
00176                 DWORD offset;
00177 
00178                 DWORD pgcpos;
00179                 f.Seek(0xc0+0x0c, CFile::begin);
00180                 ReadBEdw(pgcpos);
00181                 pgcpos *= 0x800;
00182 
00183                 WORD nPGC;
00184                 f.Seek(pgcpos, CFile::begin);
00185                 ReadBEw(nPGC);
00186 
00187                 m_rd.pgcs.RemoveAll();
00188                 m_rd.pgcs.SetSize(nPGC);
00189 
00190                 for(int i = 0; i < nPGC; i++)
00191                 {
00192                         PGC& pgc = m_rd.pgcs[i];
00193 
00194                         f.Seek(pgcpos + 8 + i*8 + 4, CFile::begin);
00195                         ReadBEdw(offset);
00196                         offset += pgcpos;
00197 
00198                         BYTE nProgs, nCells;
00199                         f.Seek(offset + 2, CFile::begin);
00200                         ReadBEb(nProgs);
00201                         ReadBEb(nCells);
00202 
00203                         //
00204 
00205                         memcpy(pgc.ids, ids, sizeof(ids));
00206 
00207                         struct splanginfo {BYTE res1, id1, id2, res2;};
00208                         splanginfo splinfo[32];
00209 
00210                         f.Seek(offset + 0x1c, CFile::begin);
00211                         f.Read(splinfo, 32*4);
00212 
00213                         for(int j = 0; j < 32; j++) 
00214                         {
00215                                 if(splinfo[j].id1 || splinfo[i].id2) 
00216                                 {
00217                                         WORD tmpids[32];
00218                                         memset(tmpids, 0, sizeof(tmpids));
00219 
00220                                         for(j = 0; j < 32; j++) 
00221                                         {
00222                                                 if(!(splinfo[j].res1 & 0x80)) break;
00223 
00224                                                 pgc.ids[splinfo[j].id1] = ids[j];
00225                                                 pgc.ids[splinfo[j].id2] = ids[j];
00226                                         }
00227 
00228                                         break;
00229                                 }
00230                         }
00231 
00232                         //
00233 
00234                         f.Seek(offset + 0xa4, CFile::begin);
00235 
00236                         for(int j = 0; j < 16; j++) 
00237                         {
00238                                 BYTE y, u, v, tmp;
00239 
00240                                 f.Read(&tmp, 1);
00241                                 f.Read(&y, 1);
00242                                 f.Read(&u, 1);
00243                                 f.Read(&v, 1);
00244 
00245                                 y = (y-16)*255/219;
00246 
00247                                 pgc.pal[j].rgbRed = (BYTE)min(max(1.0*y + 1.4022*(u-128), 0), 255);
00248                                 pgc.pal[j].rgbGreen = (BYTE)min(max(1.0*y - 0.3456*(u-128) - 0.7145*(v-128), 0), 255);
00249                                 pgc.pal[j].rgbBlue = (BYTE)min(max(1.0*y + 1.7710*(v-128), 0) , 255);
00250                         }
00251 
00252                         //
00253 
00254                         WORD progoff, celladdroff, vobcelloff;
00255                         f.Seek(offset + 0xe6, CFile::begin);
00256                         ReadBEw(progoff);
00257                         f.Seek(offset + 0xe8, CFile::begin);
00258                         ReadBEw(celladdroff);
00259                         f.Seek(offset + 0xea, CFile::begin);
00260                         ReadBEw(vobcelloff);
00261 
00262                         //
00263 
00264             CByteArray progs;
00265                         progs.SetSize(nProgs);
00266                         f.Seek(offset + progoff, CFile::begin);
00267                         f.Read(progs.GetData(), nProgs);
00268 
00269                         //
00270 
00271                         pgc.angles[0].SetSize(nCells);
00272                         pgc.iSelAngle = 0;
00273 
00274                         //
00275 
00276                         f.Seek(offset + vobcelloff, CFile::begin);
00277                         for(int j = 0; j < nCells; j++)
00278                         {
00279                                 ReadBEw(pgc.angles[0][j].vob);
00280                                 ReadBEw(pgc.angles[0][j].cell);
00281                         }
00282 
00283                         //
00284 
00285                         DWORD tOffset = 0, tTotal = 0;
00286 
00287                         int iAngle = 0;
00288 
00289                         pgc.nAngles = 0;
00290 
00291                         f.Seek(offset + celladdroff, CFile::begin);
00292                         for(int j = 0; j < nCells; j++)
00293                         {
00294                                 BYTE b;
00295                                 ReadBEb(b);
00296                                 switch(b>>6)
00297                                 {
00298                                 case 0: iAngle = 0; break; // normal
00299                                 case 1: iAngle = 1; break; // first angle block
00300                                 case 2: iAngle++; break; // middle angle block
00301                                 case 3: iAngle++; break; // last angle block (no more should follow)
00302                                 }
00303                                 pgc.angles[0][j].iAngle = iAngle;
00304                                 pgc.nAngles = max(pgc.nAngles, iAngle);
00305 
00306                                 f.Seek(3, CFile::current);
00307                                 ReadBEdw(pgc.angles[0][j].tTime);
00308                                 ReadBEdw(pgc.angles[0][j].start);
00309                                 f.Seek(8, CFile::current);
00310                                 ReadBEdw(pgc.angles[0][j].end);
00311 
00312                                 float fps;
00313                                 switch((pgc.angles[0][j].tTime>>6)&0x3)
00314                                 {
00315                                 default:
00316                                 case 3: fps = 30; break;
00317                                 case 1: fps = 25; break;
00318                                 }
00319 
00320                                 int t = pgc.angles[0][j].tTime;
00321                                 int hh = ((t>>28)&0xf)*10+((t>>24)&0xf);
00322                                 int mm = ((t>>20)&0xf)*10+((t>>16)&0xf);
00323                                 int ss = ((t>>12)&0xf)*10+((t>>8)&0xf);
00324                                 int ms = (int)(1000.0 * (((t>>4)&0x3)*10+((t>>0)&0xf)) / fps);
00325                                 pgc.angles[0][j].tTime = (DWORD)((((hh*60+mm)*60+ss)*1000+ms)*rate);
00326 
00327                                 // time discontinuity
00328                                 if(b&0x02) tOffset = tTotal;
00329                                 pgc.angles[0][j].fDiscontinuity = !!(b&0x02);
00330 
00331                                 pgc.angles[0][j].tTotal = tTotal;
00332                                 pgc.angles[0][j].tOffset = tOffset;
00333 
00334                                 tTotal += pgc.angles[0][j].tTime;
00335                         }
00336 
00337                         for(iAngle = 1; iAngle <= 9; iAngle++)
00338                         {
00339                                 tOffset = tTotal = 0;
00340 
00341                                 for(int j = 0, k = 0; j < nCells; j++)
00342                                 {
00343                                         if(pgc.angles[0][j].iAngle != 0
00344                                         && pgc.angles[0][j].iAngle != iAngle)
00345                                                 continue;
00346 
00347                                         pgc.angles[iAngle].Add(pgc.angles[0][j]);
00348 
00349                                         if(pgc.angles[iAngle][k].fDiscontinuity) tOffset = tTotal;
00350 
00351                                         pgc.angles[iAngle][k].tTotal = tTotal;
00352                                         pgc.angles[iAngle][k].tOffset = tOffset;
00353 
00354                                         tTotal += pgc.angles[iAngle][k].tTime;
00355 
00356                                         k++;
00357                                 }
00358                         }
00359                 }
00360         }
00361 
00362     Log(LOG_INFO, _T("Parsing ifo OK"));
00363 
00364         return(true);
00365 }
00366 
00367 bool CVobSubFileRipper::LoadVob(CString fn)
00368 {
00369         Log(LOG_INFO, _T("Searching vobs..."));
00370 /*
00371         CList<CString> m_vobs;
00372 
00373         fn = fn.Left(fn.ReverseFind('.')+1);
00374         fn.TrimRight(_T(".0123456789"));
00375         for(int i = 0; i < 100; i++)
00376         {
00377                 CString vob;
00378                 vob.Format(_T("%s%d.vob"), fn, i);
00379 
00380                 CFileStatus status;
00381                 if(!(CFileGetStatus(vob, status) && status.m_size))
00382                 {
00383                         if(i > 0) break;
00384                         else continue;
00385                 }
00386 
00387                 if(status.m_size&0x7ff)
00388                 {
00389                         Log(LOG_ERROR, _T("Length of %s is not n*2048!"), vob);
00390                         m_vobs.RemoveAll();
00391                         break;
00392                 }
00393 
00394                 CString str = _T("Found ") + vob;
00395 
00396                 if(i == 0) 
00397                 {
00398                         str += _T(" (skipping, if not a menu vob rename it)");
00399                 }
00400                 else
00401                 {
00402                         m_vobs.AddTail(vob);
00403                 }
00404 
00405                 Log(LOG_INFO, str);
00406         }
00407 
00408         if(m_vobs.GetCount() <= 0)
00409         {
00410                 Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn);
00411                 return(false);
00412         }
00413 */
00414         CList<CString> vobs;
00415         if(!m_vob.Open(fn, vobs/*m_vobs*/))
00416         {
00417                 Log(LOG_ERROR, _T("Cannot open vob sequence"));
00418                 return(false);
00419         }
00420 
00421         if(vobs.GetCount() <= 0)
00422         {
00423                 Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn);
00424                 return(false);
00425         }
00426 
00427         POSITION pos = vobs.GetHeadPosition();
00428         while(pos) Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos));
00429 
00430         if(m_vob.IsDVD())
00431         {
00432                 Log(LOG_INFO, _T("DVD detected..."));
00433 
00434                 BYTE key[5];
00435 
00436                 if(m_vob.HasDiscKey(key))
00437                         Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]);
00438                 else
00439                         Log(LOG_WARNING, _T("Couldn't get the disc key"));
00440 
00441                 if(m_vob.HasTitleKey(key))
00442                         Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]);
00443                 else
00444                         Log(LOG_WARNING, _T("Couldn't get the title key"));
00445 
00446                 BYTE buff[2048];
00447 
00448                 m_vob.Seek(0);
00449                 if(!m_vob.Read(buff))
00450                 {
00451                         Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!"));
00452                         return(false);
00453                 }
00454                 m_vob.Seek(0);
00455         }
00456 
00457         return(true);
00458 }
00459 
00460 DWORD CVobSubFileRipper::ThreadProc()
00461 {       
00462         SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL);
00463 
00464     while(1)
00465         {
00466                 DWORD cmd = GetRequest();
00467 
00468                 m_fThreadActive = true;
00469 
00470                 switch(cmd)
00471                 {
00472                 case CMD_EXIT:
00473                     Reply(S_OK);
00474                         return 0;
00475 
00476                 case CMD_INDEX:
00477                         Reply(S_OK);
00478                         {
00479                         m_fIndexing = true;
00480                         bool fSucceeded = Create();
00481                         m_fIndexing = false;
00482                         Finished(fSucceeded);
00483                         }
00484                         break;
00485 
00486                 default:
00487                     Reply(E_FAIL);
00488                         return -1;
00489                 }
00490 
00491                 m_fBreakThread = false;
00492                 m_fThreadActive = false;
00493         }
00494 
00495         return 1;
00496 }
00497 
00498 static int SubPosSortProc(const void* e1, const void* e2)
00499 {
00500         return((int)(((CVobSubFile::SubPos*)e1)->start - ((CVobSubFile::SubPos*)e2)->start));
00501 }
00502 
00503 bool CVobSubFileRipper::Create()
00504 {
00505         CAutoLock cAutoLock(&m_csAccessLock);
00506 
00507         if(m_rd.iSelPGC < 0 || m_rd.iSelPGC >= m_rd.pgcs.GetCount())
00508         {
00509                 Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC);
00510                 return(false);
00511         }
00512 
00513         PGC& pgc = m_rd.pgcs[m_rd.iSelPGC];
00514 
00515         if(pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].GetCount() == 0)
00516         {
00517                 Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle);
00518                 return(false);
00519         }
00520 
00521         CArray<vc_t>& angle = pgc.angles[pgc.iSelAngle];
00522 
00523         if(m_rd.selids.GetCount() == 0 && !m_rd.fClosedCaption)
00524         {
00525                 Log(LOG_ERROR, _T("No valid stream set to be extacted!"));
00526                 return(false);
00527         }
00528 
00529         if(m_rd.selvcs.GetCount() == 0)
00530         {
00531                 Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!"));
00532                 return(false);
00533         }
00534 
00535         Log(LOG_INFO, _T("Indexing..."));
00536 
00537         // initalize CVobSubFile
00538         CVobSubFile::Close();
00539         InitSettings();
00540         m_title = m_outfn;
00541         m_size = m_rd.vidsize;
00542         TrimExtension(m_title);
00543         memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal));
00544         m_sub.SetLength(0);
00545 
00546         CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw"));
00547 
00548         CVobDec vd;
00549 
00550         __int64 SCR, PTS, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0;
00551         int vob = 0, cell = 0;
00552         bool fDiscontinuity = false, fDiscontinuityFixApplied = false, fNavpackFound = false;
00553 
00554         int PTSframeoffset = 0, minPTSframeoffset = 0;
00555 
00556         if(m_rd.fResetTime)
00557         {
00558                 for(int i = 0; i < angle.GetCount() && ((angle[i].vob<<16)|angle[i].cell) != m_rd.selvcs[0]; i++)
00559                         tStart += angle[i].tTime;
00560 
00561                 Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), 
00562                         tStart, m_rd.selvcs[0]>>16, m_rd.selvcs[0]&0xffff);
00563         }
00564 
00565         CMap<DWORD, DWORD, int, int> selvcmap;
00566         selvcmap.RemoveAll();
00567         for(int i = 0; i < m_rd.selvcs.GetCount(); i++)
00568                 selvcmap[m_rd.selvcs[i]] = 90000;
00569 
00570         CArray<vcchunk> chunks, foundchunks, loadedchunks;
00571 
00572         if(m_vob.IsDVD())
00573         {
00574                 Log(LOG_INFO, _T("Indexing mode: DVD"));
00575 
00576                 for(int i = 0; i < angle.GetCount(); i++)
00577                 {
00578                         UINT vc = (angle[i].vob<<16)|angle[i].cell;
00579                         if(selvcmap.PLookup(vc) == NULL)
00580                                 continue;
00581 
00582                         vcchunk c = {2048i64*angle[i].start, 2048i64*angle[i].end+2048, vc};
00583                         chunks.Add(c);
00584 
00585                         Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), 
00586                                 angle[i].start, angle[i].end, angle[i].vob, angle[i].cell);
00587                 }
00588         }
00589         else if(LoadChunks(loadedchunks))
00590         {
00591                 Log(LOG_INFO, _T("Indexing mode: File"));
00592 
00593                 for(int i = 0; i < loadedchunks.GetCount(); i++)
00594                 {
00595                         UINT vcid = loadedchunks[i].vc;
00596                         if(selvcmap.PLookup(vcid) == NULL)
00597                                 continue;
00598 
00599                         chunks.Add(loadedchunks[i]);
00600                 }
00601 
00602                 Log(LOG_INFO, _T(".chunk file loaded"));
00603         }
00604         else
00605         {
00606                 Log(LOG_INFO, _T("Indexing mode: File"));
00607 
00608                 chunks.RemoveAll();
00609                 vcchunk c = {0, 2048i64*m_vob.GetLength(), 0};
00610                 chunks.Add(c);
00611         }
00612 
00613         __int64 sizedone = 0, sizetotal = 0;
00614         for(int i = 0; i < chunks.GetCount(); i++)
00615                 sizetotal += chunks[i].end - chunks[i].start;
00616 
00617         for(int i = 0; !m_fBreakThread && i < chunks.GetCount(); i++)
00618         {
00619                 __int64 curpos = chunks[i].start, endpos = chunks[i].end;
00620 
00621                 vcchunk curchunk = {curpos, curpos, chunks[i].vc};
00622 
00623                 for(m_vob.Seek((int)(curpos/2048)); !m_fBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048)
00624                 {
00625                         if(!(curpos&0x7ffff))
00626                                 Progress(1.0 * sizedone / sizetotal);
00627 
00628                         static BYTE buff[2048];
00629 
00630                         if(!m_vob.Read(buff))
00631                         {
00632                                 Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!"));
00633                                 return(false);
00634                         }
00635 
00636                         curchunk.end = curpos;
00637 
00638                         if(buff[0x14] & 0x30)
00639                         {
00640                                 if(!vd.m_fFoundKey)
00641                                 {
00642                                         Log(LOG_INFO, _T("Encrypted sector found, searching key..."));
00643 
00644                                         __int64 savepos = curpos;
00645 
00646                                         m_vob.Seek(0);
00647                                         for(__int64 pos = 0; !m_fBreakThread && pos < endpos; pos += 2048)
00648                                         {
00649                                                 if(!m_vob.Read(buff))
00650                                                 {
00651                                                         Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!"));
00652                                                         return(false);
00653                                                 }
00654 
00655                                                 if(vd.FindKey(buff))
00656                                                         break;
00657                                         }
00658 
00659                                         if(m_fBreakThread)
00660                                                 break;
00661 
00662                                         if(!vd.m_fFoundKey)
00663                                         {
00664                                                 Log(LOG_ERROR, _T("Key not found, can't decrypt!"));
00665                                                 return(false);
00666                                         }
00667 
00668                                         Log(LOG_INFO, _T("Key found, continuing extraction..."));
00669 
00670                                         m_vob.Seek((int)((curpos = savepos)/2048));
00671                                         m_vob.Read(buff);
00672                                 }
00673 
00674                                 vd.Decrypt(buff);
00675                         }
00676 
00677                         if(*((DWORD*)&buff[0]) != 0xba010000)
00678                         {
00679                                 Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos/2048));
00680 
00681                                 if(AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO)
00682                                 {
00683                                         Log(LOG_ERROR, _T("Terminated!"));
00684                                         return(false);
00685                                 }
00686                         }
00687                         
00688                         SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30
00689                                 | __int64(buff[0x04] & 0x03) << 28
00690                                 | __int64(buff[0x05]) << 20
00691                                 | (__int64(buff[0x06] & 0xf8) >> 3) << 15
00692                                 | __int64(buff[0x06] & 0x03) << 13
00693                                 | __int64(buff[0x07]) << 5
00694                                 | (__int64(buff[0x08] & 0xf8) >> 3) << 0;
00695 
00696                         bool hasPTS = false;
00697                                 
00698                         if((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000)
00699                                 && buff[0x15] & 0x80)
00700                         {
00701                                 PTS = (__int64)(buff[0x17] & 0x0e) << 29                // 32-30 (+marker)
00702                                         | ((__int64)(buff[0x18]) << 22)                         // 29-22
00703                                         | ((__int64)(buff[0x19] & 0xfe) << 14)          // 21-15 (+marker)
00704                                         | ((__int64)(buff[0x1a]) << 7)                          // 14-07
00705                                         | ((__int64)(buff[0x1b]) >> 1);                         // 06-00 (+marker)
00706                                 
00707                                 hasPTS = true;
00708                         }
00709 
00710                         if(*((DWORD*)&buff[0x0e]) == 0xbb010000)
00711                         {
00712                                 fNavpackFound = true;
00713 
00714                                 if(vob == buff[0x420] && cell == buff[0x422])
00715                                         continue;
00716 
00717                                 vob = buff[0x420];
00718                                 cell = buff[0x422];
00719 
00720                                 tOffset = tTotal = 0;
00721 
00722                                 for(int i = 0; i < angle.GetSize(); i++)
00723                                 {
00724                                         if(angle[i].vob == vob && angle[i].cell == cell)
00725                                         {
00726                                                 tPrevOffset = tOffset;
00727                                                 tOffset = (__int64)angle[i].tOffset;
00728                                                 tTotal = (__int64)angle[i].tTotal;
00729                                                 fDiscontinuity = angle[i].fDiscontinuity;
00730                                                 fDiscontinuityFixApplied = false;
00731                                                 break;
00732                                         }
00733                                 }
00734 
00735                                 if(curchunk.vc != ((vob<<16)|cell))
00736                                 {
00737                                         if(curchunk.vc != 0) foundchunks.Add(curchunk);
00738                                         curchunk.start = curchunk.end = curpos;
00739                                         curchunk.vc = (vob<<16)|cell;
00740                                 }
00741 
00742                                 CString str, str2;
00743                                 str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos/2048));
00744                                 UINT vcid = (vob<<16)|cell;
00745                                 if(!selvcmap.Lookup(vcid, minPTSframeoffset)) str2 = _T(", skipping");
00746                                 else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), 
00747                                         tTotal, tOffset, -tStart, (int)fDiscontinuity);
00748                                 Log(LOG_INFO, str + str2);
00749                         }
00750 
00751                         UINT vcid = (vob<<16)|cell;
00752                         if(!selvcmap.Lookup(vcid, minPTSframeoffset))
00753                                 continue;
00754 
00755                         if(hasPTS && fDiscontinuity && !fDiscontinuityFixApplied)
00756                         {
00757                                 __int64 tDiff = tOffset - tPrevOffset;
00758                                 if(tDiff > 0 && tDiff < (PTS/90+1000))
00759                                 {
00760                                         CString str;
00761                                         str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff);
00762                                         Log(LOG_INFO, str);
00763 
00764                                         tStart += tDiff;
00765                                 }
00766                                 fDiscontinuityFixApplied = true;
00767                         }
00768 
00769                         if(*(DWORD*)&buff[0x0e] == 0xe0010000)
00770                         {
00771                                 if(fDiscontinuity)
00772                                 {
00773                                         if(PTS < minPTSframeoffset)
00774                                         {
00775                                                 selvcmap[vcid] = PTSframeoffset = PTS;
00776                                         }
00777 
00778                                         fDiscontinuity = false;
00779                                 }
00780 
00781                                 if(m_rd.fClosedCaption)
00782                                         ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart);
00783                         }
00784                         else if(*(DWORD*)&buff[0x0e] == 0xbd010000)
00785                         {
00786                                 BYTE id = buff[0x17 + buff[0x16]], iLang = id&0x1f;
00787 
00788                                 if((id & 0xe0) == 0x20 && m_rd.selids.PLookup(iLang))
00789                                 {
00790                                         if(hasPTS)
00791                                         {
00792                                                 SubPos sb;
00793                                                 sb.filepos = m_sub.GetPosition();
00794                                                 sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart;
00795                                                 sb.vobid = (char)vob;
00796                                                 sb.cellid = (char)cell;
00797                                                 sb.celltimestamp = tTotal;
00798                                                 sb.fValid = true;
00799                                                 m_langs[iLang].subpos.Add(sb);
00800                                         }
00801 
00802                                         m_sub.Write(buff, 2048);
00803                                 }
00804                         }
00805                 }
00806 
00807                 if(curchunk.vc != ((vob<<16)|cell))
00808                 {
00809                         if(curchunk.vc != 0) foundchunks.Add(curchunk);
00810                         curchunk.start = curchunk.end = curpos;
00811                         curchunk.vc = (vob<<16)|cell;
00812                 }
00813         }
00814 
00815         if(sizedone < sizetotal)
00816         {
00817                 Log(LOG_ERROR, _T("Indexing terminated before reaching the end!"));
00818                 Progress(0);
00819                 return(false);
00820         }
00821 
00822         if(!fNavpackFound)
00823         {
00824                 Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)"));
00825                 if(!m_vob.IsDVD()) Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets."));
00826                 Progress(0);
00827                 return(false);
00828         }
00829 
00830         Log(LOG_INFO, _T("Indexing finished"));
00831         Progress(1);
00832 
00833         for(int i = 0; i < 32; i++)
00834         {
00835                 if(m_iLang == -1 && m_langs[i].subpos.GetSize() > 0) m_iLang = i;
00836                 m_langs[i].id = pgc.ids[i];
00837                 m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id);
00838 
00839                 CArray<SubPos>& sp = m_langs[i].subpos;
00840                 qsort(sp.GetData(), sp.GetSize(), sizeof(SubPos), SubPosSortProc);
00841 
00842                 if(m_rd.fForcedOnly)
00843                 {
00844                         Log(LOG_INFO, _T("Searching for forced subs..."));
00845                         Progress(0);
00846 
00847                         for(int j = 0, len = sp.GetCount(); j < len; j++)
00848                         {
00849                                 Progress(1.0 * j / len);
00850 
00851                                 sp[j].fValid = false;
00852                                 int packetsize = 0, datasize = 0;
00853                                 if(BYTE* buff = GetPacket(j, packetsize, datasize, i))
00854                                 {
00855                                         m_img.GetPacketInfo(buff, packetsize, datasize);
00856                                         sp[j].fValid = m_img.fForced;
00857                                         delete [] buff;
00858                                 }
00859                         }
00860 
00861                         Progress(1);
00862                 }
00863         }
00864 
00865         Log(LOG_INFO, _T("Saving files..."));
00866 
00867         if(m_iLang != -1)
00868         {
00869                 if(!Save(m_title))
00870                 {
00871                         Log(LOG_ERROR, _T("Could not save output files!"));
00872                         return(false);
00873                 }
00874         }
00875 
00876         Log(LOG_INFO, _T("Subtitles saved"));
00877 
00878         if(!m_vob.IsDVD() && loadedchunks.GetCount() == 0)
00879         {
00880                 if(SaveChunks(foundchunks))
00881                 {
00882                         Log(LOG_INFO, _T(".chunk file saved"));
00883                 }
00884         }
00885 
00886         Log(LOG_INFO, _T("Done!"));
00887 
00888         return(true);
00889 }
00890 
00891 static const DWORD s_version = 1;
00892 
00893 bool CVobSubFileRipper::LoadChunks(CArray<vcchunk>& chunks)
00894 {
00895         CFile f;
00896 
00897         CString fn = m_infn;
00898         TrimExtension(fn);
00899         fn += _T(".chunks");
00900 
00901         DWORD chksum = 0, chunklen, version;
00902         __int64 voblen;
00903 
00904         if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
00905                 return(false);
00906         f.Read(&version, sizeof(version));
00907         if(version == 1)
00908         {
00909                 f.Read(&chksum, sizeof(chksum));
00910                 f.Read(&voblen, sizeof(voblen));
00911                 f.Read(&chunklen, sizeof(chunklen));
00912                 chunks.SetSize(chunklen);
00913                 f.Read(chunks.GetData(), sizeof(vcchunk)*chunks.GetCount());
00914         }
00915         f.Close();
00916 
00917         if(voblen != m_vob.GetLength())
00918         {
00919                 chunks.RemoveAll();
00920                 return(false);
00921         }
00922 
00923         if(!f.Open(m_infn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
00924                 return(false);
00925         DWORD dw, chksum2 = 0;
00926         while(f.Read(&dw, sizeof(dw)) == sizeof(dw)) chksum2 += dw;
00927         f.Close();
00928 
00929         if(chksum != chksum2)
00930         {
00931                 chunks.RemoveAll();
00932                 return(false);
00933         }
00934 
00935         return(true);
00936 }
00937 
00938 bool CVobSubFileRipper::SaveChunks(CArray<vcchunk>& chunks)
00939 {
00940         CFile f;
00941 
00942         CString fn = m_infn;
00943         TrimExtension(fn);
00944         fn += _T(".chunks");
00945 
00946         DWORD chksum = 0, chunklen = chunks.GetCount();
00947         __int64 voblen = m_vob.GetLength();
00948 
00949         if(!f.Open(m_infn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
00950                 return(false);
00951         DWORD dw;
00952         while(f.Read(&dw, sizeof(dw)) == sizeof(dw)) chksum += dw;
00953         f.Close();
00954 
00955         if(!f.Open(fn, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyWrite))
00956                 return(false);
00957         f.Write(&s_version, sizeof(s_version));
00958         f.Write(&chksum, sizeof(chksum));
00959         f.Write(&voblen, sizeof(voblen));
00960         f.Write(&chunklen, sizeof(chunklen));
00961         f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen);
00962         f.Close();
00963 
00964         return(true);
00965 }
00966 
00967 // IVSFRipper
00968 
00969 STDMETHODIMP CVobSubFileRipper::SetCallBack(IVSFRipperCallback* pCallback)
00970 {
00971         CAutoLock cAutoLock(&m_csCallback);
00972         m_pCallback = pCallback;
00973         return S_OK;
00974 }
00975 
00976 STDMETHODIMP CVobSubFileRipper::LoadParamFile(CString fn)
00977 {
00978         CAutoLock cAutoLock(&m_csAccessLock);
00979 
00980         m_rd.Reset();
00981 
00982         CStdioFile f;
00983         if(!f.Open(fn, CFile::modeRead|CFile::typeText))
00984                 return E_FAIL;
00985 
00986         TCHAR langid[256];
00987 
00988         enum {P_INPUT, P_OUTPUT, P_PGC, P_ANGLE, P_LANGS, P_OPTIONS};
00989         int phase = P_INPUT;
00990 
00991         CString line;
00992         while(f.ReadString(line))
00993         {
00994                 if(line.Trim().IsEmpty() || line[0] == '#') continue;
00995 
00996                 if(phase == P_INPUT)
00997                 {
00998                         if(S_OK != SetInput(line)) break;
00999                         phase = P_OUTPUT;
01000                 }
01001                 else if(phase == P_OUTPUT)
01002                 {
01003                         if(S_OK != SetOutput(line)) break;
01004                         phase = P_PGC;
01005                 }
01006                 else if(phase == P_PGC)
01007                 {
01008                         m_rd.iSelPGC = _tcstol(line, NULL, 10)-1;
01009                         if(m_rd.iSelPGC < 0 || m_rd.iSelPGC >= m_rd.pgcs.GetCount()) break;
01010                         phase = P_ANGLE;
01011                 }
01012                 else if(phase == 3)
01013                 {
01014                         PGC& pgc = m_rd.pgcs[m_rd.iSelPGC];
01015 
01016                         pgc.iSelAngle = _tcstol(line, NULL, 10);
01017                         if(pgc.iSelAngle < 0 || pgc.iSelAngle > max(1, pgc.nAngles) || pgc.iSelAngle > 9) break;
01018 
01019                         CArray<vc_t>& angle = pgc.angles[pgc.iSelAngle];
01020 
01021                         if(line.Find('v') >= 0)
01022                         {
01023                                 int vob = 0, cell = 0;
01024 
01025                                 line += ' ';
01026 
01027                                 TCHAR* s = (LPTSTR)(LPCTSTR)line;
01028                                 TCHAR* e = s + line.GetLength();
01029                                 while(s < e)
01030                                 {
01031                                         if(*s == 'v' || s == e-1)
01032                                         {
01033                                                 s++;
01034                                                 if(vob != 0 && cell == 0)
01035                                                 {
01036                                                         for(int i = 0; i < angle.GetCount(); i++)
01037                                                         {
01038                                                                 if(angle[i].vob == vob)
01039                                                                         m_rd.selvcs.Add((angle[i].vob<<16)|angle[i].cell);
01040                                                         }
01041                                                 }
01042 
01043                                                 vob = _tcstol(s, &s, 10);
01044                                                 cell = 0;
01045                                         }
01046                                         else if(*s == 'c' && vob > 0)
01047                                         {
01048                                                 s++;
01049                                                 cell = _tcstol(s, &s, 10);
01050 
01051                                                 for(int i = 0; i < angle.GetCount(); i++)
01052                                                 {
01053                                                         if(angle[i].vob == vob && angle[i].cell == cell)
01054                                                         {
01055                                                                 m_rd.selvcs.Add((vob<<16)|cell);
01056                                                                 break;
01057                                                         }
01058                                                 }
01059                                         }
01060                                         else
01061                                         {
01062                                                 s++;
01063                                         }
01064                                 }
01065                         }
01066                         else
01067                         {
01068                                 for(int i = 0; i < angle.GetCount(); i++)
01069                                         m_rd.selvcs.Add((angle[i].vob<<16)|angle[i].cell);
01070                         }
01071 
01072                         phase = P_LANGS;
01073                 }
01074                 else if(phase == 4)
01075                 {
01076                         if(!line.CompareNoCase(_T("ALL")))
01077                         {
01078                                 for(int i = 0; i < 32; i++) m_rd.selids[i] = true;
01079                                 m_rd.fClosedCaption = true;
01080                                 phase = P_OPTIONS;
01081                         }
01082                         else
01083                         {
01084                                 line += ' ';
01085 
01086                                 while(line.GetLength() > 0)
01087                                 {
01088                                         int n = line.Find(_T(" "));
01089 
01090                                         CString lang = line.Left(n);
01091 
01092                                         line = line.Mid(n);
01093                                         line.TrimLeft();
01094 
01095                                         n = 0;
01096 
01097                                         int langnum;
01098 
01099                                         if(_istdigit(lang[0])) 
01100                                         {
01101                                                 n = _stscanf(lang, _T("%d"), &langnum);
01102                                                 if(n != 1) break;
01103 
01104                                                 m_rd.selids[langnum] = true;
01105                                         }
01106                                         else if(_istalpha(lang[0])) 
01107                                         {
01108                                                 n = _stscanf(lang, _T("%s"), langid);
01109                                                 if(n != 1) break;
01110 
01111                                                 int id = (langid[0] << 8) + langid[1];
01112 
01113                                                 if(id == 'cc')
01114                                                 {
01115                                                         m_rd.fClosedCaption = true;
01116                                                 }
01117                                                 else
01118                                                 {
01119                                                         m_rd.selids[id] = true;
01120                                                 }
01121                                         }
01122                                         else break;
01123 
01124                                         if(n != 1) break;
01125                                 }
01126 
01127                                 if((m_rd.selids.GetSize() > 0 || m_rd.fClosedCaption) && line.IsEmpty())
01128                                         phase = P_OPTIONS;
01129                         }
01130                 }
01131                 else if(phase == 5 && !line.CompareNoCase(_T("CLOSE")))
01132                         m_rd.fClose = true;
01133                 else if(phase == 5 && !line.CompareNoCase(_T("BEEP")))
01134                         m_rd.fBeep = true;
01135                 else if(phase == 5 && !line.CompareNoCase(_T("RESETTIME")))
01136                         m_rd.fResetTime = true;
01137                 else if(phase == 5 && !line.CompareNoCase(_T("FORCEDONLY")))
01138                         m_rd.fForcedOnly = true;
01139                 else if(phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS")))
01140                         m_rd.fCloseIgnoreError = true;
01141                 
01142         }
01143 
01144         m_rd.fAuto = true;
01145 
01146         return phase == P_OPTIONS ? S_OK : E_FAIL;
01147 }
01148 
01149 STDMETHODIMP CVobSubFileRipper::SetInput(CString infn)
01150 {
01151         CAutoLock cAutoLock(&m_csAccessLock);
01152 
01153         m_rd.Reset();
01154 
01155         if(!LoadIfo(infn) || !LoadVob(infn))
01156                 return E_INVALIDARG;
01157 
01158         m_infn = infn;
01159 
01160         return S_OK;
01161 }
01162 
01163 STDMETHODIMP CVobSubFileRipper::SetOutput(CString outfn)
01164 {
01165         CAutoLock cAutoLock(&m_csAccessLock);
01166         m_outfn = outfn;
01167         return S_OK;
01168 }
01169 
01170 STDMETHODIMP CVobSubFileRipper::GetRipperData(VSFRipperData& rd)
01171 {
01172         CAutoLock cAutoLock(&m_csAccessLock);
01173         rd.Copy(m_rd);
01174         return S_OK;
01175 }
01176 
01177 STDMETHODIMP CVobSubFileRipper::UpdateRipperData(VSFRipperData& rd)
01178 {
01179         CAutoLock cAutoLock(&m_csAccessLock);
01180         m_rd.Copy(rd);
01181         return S_OK;
01182 }
01183 
01184 STDMETHODIMP CVobSubFileRipper::Index()
01185 {
01186         if(m_fIndexing) return E_FAIL;
01187         CAMThread::CallWorker(CMD_INDEX);
01188         return S_OK;
01189 }
01190 
01191 
01192 STDMETHODIMP CVobSubFileRipper::IsIndexing()
01193 {
01194         return m_fIndexing ? S_OK : S_FALSE;
01195 }
01196 
01197 STDMETHODIMP CVobSubFileRipper::Abort(bool fSavePartial)
01198 {
01199         m_fBreakThread = true;
01200         return S_OK;
01201 }
01202 
01203 //
01204 
01205 void VSFRipperData::Reset()
01206 {
01207         vidsize.SetSize(0,0);
01208         memset(&vidinfo, 0, sizeof(vidinfo));
01209         pgcs.RemoveAll();
01210         iSelPGC = -1;
01211         fResetTime = fClosedCaption = true;
01212         fForcedOnly = false;
01213         fClose = fBeep = fAuto = false;
01214         fCloseIgnoreError = false;
01215 
01216         selvcs.RemoveAll();
01217         selids.RemoveAll();
01218 }
01219 
01220 void VSFRipperData::Copy(VSFRipperData& rd)
01221 {
01222         Reset();
01223 
01224         vidsize = rd.vidsize;
01225         vidinfo = rd.vidinfo;
01226         if(int len = rd.pgcs.GetCount())
01227         {
01228                 pgcs.SetSize(len);
01229                 for(int i = 0; i < len; i++)
01230                 {
01231                         PGC& src = rd.pgcs[i];
01232                         PGC& dst = pgcs[i];
01233                         dst.nAngles = src.nAngles;
01234                         for(int i = 0; i < countof(dst.angles); i++)
01235                                 dst.angles[i].Copy(src.angles[i]);
01236                         dst.iSelAngle = src.iSelAngle;
01237                         memcpy(dst.pal, src.pal, sizeof(src.pal));
01238                         memcpy(dst.ids, src.ids, sizeof(src.ids));
01239                 }
01240         }
01241         iSelPGC = rd.iSelPGC;
01242         fResetTime = rd.fResetTime;
01243         fClosedCaption = rd.fClosedCaption;
01244         fForcedOnly = rd.fForcedOnly;
01245         fClose = rd.fClose;
01246         fBeep = rd.fBeep;
01247         fAuto = rd.fAuto;
01248         fCloseIgnoreError = rd.fCloseIgnoreError;
01249         selvcs.Copy(rd.selvcs);
01250         POSITION pos = rd.selids.GetStartPosition();
01251         while(pos)
01252         {
01253                 BYTE key;
01254                 bool val;
01255                 rd.selids.GetNextAssoc(pos, key, val);
01256                 selids[key] = val;
01257         }
01258 }
01259 

Generated on Tue Dec 13 14:47:56 2005 for guliverkli by  doxygen 1.4.5