📄 dvdsubber_kernel.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.h"
#include "../include/dvdsynth-device.h"
#include <stdio.h>
template<class T> static inline T Min(T a, T b) { return a<b?a:b; }
template<class T> static inline T Max(T a, T b) { return a<b?b:a; }
DvsDockingBayKernelGlobal* g_callbacks;
unsigned Get4(const unsigned char* p) {
return p[0]*16777216 + p[1]*65536 + p[2]*256 + p[3];
}
void Put4(unsigned char* dst, unsigned val) {
dst[0] = val>>24;
dst[1] = val>>16;
dst[2] = val>>8;
dst[3] = val;
}
unsigned crc_ccitt(const unsigned char *buf, unsigned len) {
const unsigned poly = 0x11021;
static unsigned short lookup[256];
unsigned int r;
unsigned int i;
if (lookup[1] == 0) {
unsigned int j,k;
for (j = 0; j < 256; ++j) {
unsigned int temp = j << 8;
for (k = 0; k < 8; ++k) {
unsigned int hibit = temp & 32768;
temp <<= 1;
if (hibit)
temp ^= poly;
}
lookup[j] = temp;
}
}
r = 0;
for (i = 0; i < len; ++i) {
r = (r << 8) ^ lookup[((r >> 8) ^ buf[i]) & 255];
}
return r & 65535;
}
int check_udf_descriptor(const unsigned char* buf, int type) {
if (buf[0]+buf[1]*256 != type) {
return -1;
}
int checksum = 0;
for (int i=0; i<16; ++i) {
checksum += buf[i];
}
if ((checksum - buf[4]*2) & 255) {
return -3;
}
int crc = crc_ccitt(buf+16, buf[10]+buf[11]*256);
if (buf[8]+buf[9]*256 != crc) {
return -4;
}
return 0;
}
unsigned DVDSubberKernel::Hard2Soft(unsigned sector) {
unsigned increase = 0;
SubpictureInfo* si = subpic_inf;
for (int i=0; i<num_subpics; ++i) {
if (si->hard_lba > sector)
break;
increase += si->num_sectors;
si = si->next;
}
return sector+increase;
}
unsigned DVDSubberKernel::Soft2Hard(unsigned sector) {
SubpictureInfo* si = subpic_inf;
for (int i=0; i<num_subpics; ++i) {
if (sector < si->hard_lba) {
break;
} else if (sector < si->hard_lba + si->num_sectors) {
return si->hard_lba;
} else {
sector -= si->num_sectors;
}
}
return sector;
}
void DVDSubberKernel::GenerateSubpictureSector(SubpictureInfo* si, unsigned subpic_rba, unsigned char* buffer) {
g_callbacks->MemCpy(&buffer[4], saved_scr, 6);
if (saved_scr_lba != si->hard_lba - 1) {
SenseData sense;
if (SCSIRESULT_SUCCESS == ReadHardSectors(si->hard_lba - 1, 1, buffer, &sense)) {
g_callbacks->MemCpy(saved_scr, &buffer[4], 6);
} else {
g_callbacks->MemCpy(&buffer[4], saved_scr, 6);
}
saved_scr_lba = si->hard_lba - 1;
}
Put4(&buffer[0], 0x000001BA);
Put4(&buffer[10], 0x0189C3F8);
Put4(&buffer[14], 0x000001BD);
Put4(&buffer[18], 0x07EC8180);
size_t filled_in;
if (subpic_rba == 0) {
buffer[22] = 5;
unsigned ptm = si->ptm;
buffer[23] = ((ptm >> 29) & 0x0E) | 0x21;
buffer[24] = ptm >> 22;
buffer[25] = (ptm >> 14) | 1;
buffer[26] = ptm >> 7;
buffer[27] = ptm * 2 + 1;
buffer[28] = 0x20 + disc_info->titlesets[title].number_of_existing_subpicture_tracks;
filled_in = 29 + g_callbacks->ReadFile(data_file_handle, si->file_offset, 0, Min(2019U, unsigned(si->data_len)), buffer + 29);
} else {
Put4(&buffer[20], 0x81000020 + disc_info->titlesets[title].number_of_existing_subpicture_tracks);
unsigned subpic_data_offset = subpic_rba * 2024 - 5;
unsigned subpic_data_len = Min(2024U, unsigned(si->data_len - subpic_data_offset));
filled_in = 24 + g_callbacks->ReadFile(data_file_handle, si->file_offset + subpic_data_offset, 0, subpic_data_len, buffer + 24);
}
if (filled_in < 2048) {
buffer[18] = (filled_in - 20) >> 8;
buffer[19] = (filled_in - 20);
if (filled_in < 2048-6) {
Put4(&buffer[filled_in+2], (2048-6)-filled_in);
Put4(&buffer[filled_in], 0x000001BE);
g_callbacks->MemSet(buffer+filled_in+6, -1, (2048-6)-filled_in);
} else {
int stuffing = 2048-filled_in;
buffer[13] += stuffing;
for (int i=filled_in-1; i>=14; --i) {
buffer[i+stuffing] = buffer[i];
buffer[i] = 255;
}
}
}
}
unsigned GetICBStartLBA(const unsigned char* buffer, unsigned buf_lba) {
// x86-specific!
unsigned partition_begin = buf_lba - *(unsigned*)(buffer+12);
unsigned l_ea = *(unsigned*)(buffer+168);
if (l_ea > 2048-176-8) {
return 0;
}
return partition_begin + *(unsigned*)(buffer+176+l_ea+4);
}
void SetICBLengthInBlocks(const unsigned char* buffer, unsigned length) {
// x86-specific!
*(unsigned*)(buffer+56) = length << 11;
*(unsigned*)(buffer+60) = length >> 21;
*(unsigned*)(buffer+64) = length;
*(unsigned*)(buffer+68) = 0;
unsigned l_ea = *(unsigned*)(buffer+168);
*(unsigned*)(buffer+176+l_ea) = length << 11;
}
void RecalcCRC(unsigned char* buffer) {
buffer[4] -= buffer[8]+buffer[9];
*(unsigned short*)(buffer+8) = crc_ccitt(buffer+16, *(unsigned short*)(buffer+10));
buffer[4] += buffer[8]+buffer[9];
}
void SetICBStartLBA(unsigned char* buffer, unsigned buf_lba, unsigned new_lba) {
// x86-specific!
unsigned partition_begin = buf_lba - *(unsigned*)(buffer+12);
unsigned l_ea = *(unsigned*)(buffer+168);
*(unsigned*)(buffer+176+l_ea+4) = new_lba - partition_begin;
}
void DVDSubberKernel::PatchHardSector(unsigned hard_lba, unsigned char* buffer) {
for (int ts = disc_info->num_title_sets-1; ts >= 0; --ts) {
TitleSetInfo& tsi = disc_info->titlesets[ts];
if (hard_lba >= tsi.vts_ifo_sector) {
if (hard_lba >= tsi.vts_bup_sector) {
PatchVTSIFO(ts, tsi, hard_lba - tsi.vts_bup_sector, buffer);
} else if (hard_lba >= tsi.vts_vobs_sector) {
if (Get4(buffer) == 0x000001BA) {
g_callbacks->MemCpy(saved_scr, &buffer[4], 6);
saved_scr_lba = hard_lba;
// FIXME: should I check for pack header stuffing?
switch (Get4(buffer+14)) {
case 0x000001BB:
{
TranslateRelativeSector(&buffer[0x02D], tsi.vts_vobs_sector, false);
TranslateRelativeSector(&buffer[0x40B], tsi.vts_vobs_sector, false);
TranslateRelativeSector(&buffer[0x42D], hard_lba, true);
for (int refframe=0; refframe<4; ++refframe) {
TranslateRelativeSector(&buffer[0x40F+refframe*4], hard_lba, false);
}
for (int angle=0; angle<9; ++angle) {
TranslateRelativeSector(&buffer[0x069+angle*4], hard_lba, false);
TranslateRelativeSector(&buffer[0x4BB+angle*4], hard_lba, true);
}
for (int various=0; various<42; ++various) {
TranslateRelativeSector(&buffer[0x4F1+various*4], hard_lba, false);
}
Put4(&buffer[0x5A9 + 4 * tsi.number_of_existing_subpicture_tracks], 0x7FFFFFFF);
break;
}
case 0x000001BD:
{
// The R2 Cagliostro DVD has four subtitle tracks, but
// only two are mentioned in the INF file. (The other
// two seem to be copies of the first two.) To prevent
// added subtitles from mixing with existing undocumented
// subtitles, I convert them into padding blocks here.
unsigned char substream_id = buffer[23 + buffer[22]];
if (substream_id == 0x20 + tsi.number_of_existing_subpicture_tracks) {
Put4(buffer+14, 0x000001BE);
g_callbacks->MemSet(buffer+20, 0xFF, 2048-20);
}
break;
}
}
}
} else if (hard_lba >= tsi.vtsm_vobs_sector) {
// no action
} else {
PatchVTSIFO(ts, tsi, hard_lba - tsi.vts_ifo_sector, buffer);
}
return;
}
}
if (hard_lba >= disc_info->vmg_bup_sector) {
PatchVMGIFO(hard_lba - disc_info->vmg_bup_sector, buffer);
} else if (hard_lba >= disc_info->vmg_vobs_sector) {
// no action
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -