📄 dvdsubber-vobscan.cpp
字号:
/***********************************************************************
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 <http://www.gnu.org/copyleft/gpl.html>.
***********************************************************************/
#include "DVDSubber-vobscan.h"
#include <string.h>
#include <stdio.h>
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; s<vobu_admap_sectors; ++s) {
if (!scanner_callbacks->ReadSector(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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -