/*********************************************************************** Copyright 2002 Ben Rudiak-Gould. 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 of the License, 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, or visit . ***********************************************************************/ #include "DVDSubber-vobscan.h" #include #include static unsigned get4(unsigned char* p) { unsigned result = 0; for (int i=0; i<4; ++i) result = result*256 + p[i]; return result; } bool Scan(unsigned vobu_admap_lba, unsigned num_vobus, unsigned vts_vobs_lba, IScannerCallbacks* scanner_callbacks) { scanner_callbacks->Note("Scanning the DVD (this may take a while)..."); unsigned vobu_admap_sectors = (num_vobus >> 9) + 1; unsigned char* vobu_lbas = new unsigned char[vobu_admap_sectors * 2048]; for (unsigned s=0; sReadSector(vobu_admap_lba+s, vobu_lbas + s*2048)) { scanner_callbacks->ErrorAtLBA("Could not read the DVD disc", vobu_admap_lba+s); return false; } } int old_angle = 0, max_angle = 0; unsigned last_saved_ptm = 0; unsigned ptm_by_angle[10]; memset(ptm_by_angle, 0, sizeof(ptm_by_angle)); for (unsigned vobu_number = 1; vobu_number <= num_vobus; ++vobu_number) { if (scanner_callbacks->UserAborted()) { return false; } unsigned lba = vts_vobs_lba + get4(vobu_lbas + vobu_number * 4); unsigned char buf[2048]; if (!scanner_callbacks->ReadSector(lba, buf)) { scanner_callbacks->ErrorAtLBA("Could not read the DVD disc", lba); return false; } if (get4(buf) != 0x000001BA) { scanner_callbacks->ErrorAtLBA("Not an MPEG-2 pack!", lba); return false; } unsigned char* p = buf + 14 + (buf[13] & 7); if (get4(p) != 0x000001BB) { scanner_callbacks->ErrorAtLBA("Not a NAV pack!", lba); return false; } unsigned flags = buf[0x427] >> 4; int angle = 0; if (flags & 4) { for (angle = 1; angle <= 9; ++angle) { if (get4(buf + 0x65 + angle*4) == 0x80000000) { break; } } if (angle > 9) { scanner_callbacks->Warning("Warning: passed angle 9 (this is probably a bug)"); angle = 0; } } if (angle != old_angle) { scanner_callbacks->ChangeAngle(angle); if (angle > 0) { if (old_angle == 0) { for (int a=1; a<=9; ++a) { ptm_by_angle[a] = ptm_by_angle[0]; } } if (max_angle < angle) max_angle = angle; } else { ptm_by_angle[0] = ptm_by_angle[1]; for (int a=2; a<=max_angle; ++a) { if (ptm_by_angle[0] != ptm_by_angle[a]) { scanner_callbacks->Warning("Warning: bad PTM on angle merge (this is probably a bug)"); } } max_angle = 0; } old_angle = angle; } unsigned skip_blocks = get4(buf+0x40f); unsigned s_ptm = get4(buf+0x39); if (ptm_by_angle[angle] != s_ptm) { last_saved_ptm = s_ptm; scanner_callbacks->ChangePTM(s_ptm); } unsigned e_ptm = get4(buf+0x3D); ptm_by_angle[angle] = e_ptm; unsigned ptm_delta = e_ptm - s_ptm; bool ntsc = (buf[0x48] >> 7) & 1; unsigned fields; if (ntsc) { fields = (ptm_delta / 3003) * 2; switch (ptm_delta % 3003) { case 0: break; case 1501: case 1502: ++fields; break; default: scanner_callbacks->Warning("Warning: unexpected PTM delta"); } unsigned foo = (e_ptm - last_saved_ptm) % 3003; if (foo != 0 && foo != 1501) { printf("foo = %d\n", foo); } } else { fields = ptm_delta / 1800; if (ptm_delta % 1800 != 0) { scanner_callbacks->Warning("Warning: unexpected PTM delta"); } } scanner_callbacks->AddVOBU(lba, vobu_number, fields, skip_blocks); } return true; }