📄 dvdsubber.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>.
***********************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commdlg.h>
#include "DVDSubber.h"
#include "DVDSubber-dialog.h"
#include "DVDSubber-vobscan.h"
#include "DVDSubber-compile.h"
#include "../include/dvdsynth-filter.h"
#include <stdio.h>
HINSTANCE g_hinstance;
DvsDockingBayGlobal* g_bays;
//scsi_result_t ScsiCommand(DvsDeviceKernel* self, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense);
/********************************************************************
********************************************************************/
struct DVDSubberUser : DvsDeviceUser {
DVDSubberKernel* k;
dvs_driver_handle driver_handle;
DvsDockingBay* bay;
HANDLE data_file_handle;
};
/********************************************************************
********************************************************************/
unsigned updcrc32(unsigned crc, unsigned char *buf, int len) {
static unsigned table[256];
const unsigned poly = 0xEDB88320;
if (table[255] == 0) {
for (unsigned n = 0; n < 256; n++) {
unsigned c = n;
for (int k = 0; k < 8; k++) {
if (c & 1) {
c = poly ^ (c >> 1);
} else {
c = c >> 1;
}
}
table[n] = c;
}
}
crc = ~crc;
for (int n = 0; n < len; n++) {
crc = table[(crc ^ buf[n]) & 0xff] ^ (crc >> 8);
}
return ~crc;
}
class SlidingBuffer {
DvsDeviceKernel* k;
unsigned cur_sector;
unsigned crc;
unsigned char buf[2048];
public:
SlidingBuffer(DvsDeviceKernel* _k) {
k = _k;
cur_sector = ~0U;
crc = 0;
}
unsigned GetDword(unsigned base_sector, unsigned offset);
unsigned GetDword(unsigned offset);
unsigned GetCumulativeCRC() { return crc; }
};
unsigned SlidingBuffer::GetDword(unsigned base_sector, unsigned offset) {
base_sector += (offset>>11);
offset &= 2047;
if (base_sector != cur_sector) {
static unsigned char cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
for (int i=0; i<4; ++i) {
cdb[5-i] = base_sector >> (i*8);
}
unsigned long buflen = 2048;
SenseData sense;
scsi_result_t result = g_bays->KernelScsiCommand(k, cdb, 10, buf, &buflen, 1, &sense);
if (result != SCSIRESULT_SUCCESS) {
throw result;
}
cur_sector = base_sector;
crc = updcrc32(crc, buf, 2048);
}
return GetDword(offset);
}
unsigned SlidingBuffer::GetDword(unsigned offset) {
return buf[offset]*16777216 + buf[offset+1]*65536 + buf[offset+2]*256 + buf[offset+3];
}
DiscInfo* GetDiscInfo(DvsDeviceKernel* dev, DvsDockingBay* bay) {
DvdVideoInfo dvd_video_info;
int result = g_bays->GetDvdVideoInfo(dev, &dvd_video_info);
if (result < 0) {
return 0;
}
DiscInfo di;
SlidingBuffer disc(dev);
di.vmg_ifo_sector = dvd_video_info.vmg_ifo_sector;
di.vmg_vobs_sector = di.vmg_ifo_sector + disc.GetDword(di.vmg_ifo_sector, 0xC0);
di.vmg_bup_sector = di.vmg_ifo_sector + disc.GetDword(0x0C) - disc.GetDword(0x1C);
unsigned tt_srpt_sector = disc.GetDword(0xC4);
di.vmg_tt_srpt_offset = tt_srpt_sector * 2048 + 8;
tt_srpt_sector += di.vmg_ifo_sector;
di.num_title_sets = disc.GetDword(tt_srpt_sector, 0) >> 16;
di.vmg_tt_srpt_end_offset = di.vmg_tt_srpt_offset + disc.GetDword(4) - 7;
di.titlesets = (TitleSetInfo*)bay->vtable->SharedPool_Alloc(bay, di.num_title_sets * sizeof(TitleSetInfo));
di.num_title_sets = 0;
memset(di.titlesets, 0, di.num_title_sets * sizeof(TitleSetInfo));
for (unsigned ofs = di.vmg_tt_srpt_offset; ofs < di.vmg_tt_srpt_end_offset; ofs += 12) {
unsigned title_set = ((disc.GetDword(di.vmg_ifo_sector, ofs+4) >> 8) & 255) - 1;
if (title_set < 99) {
di.titlesets[title_set].vts_ifo_sector = di.vmg_ifo_sector + disc.GetDword(di.vmg_ifo_sector, ofs+8);
if (title_set >= di.num_title_sets) {
di.num_title_sets = title_set+1;
}
}
}
for (unsigned ts = 0; ts < di.num_title_sets; ++ts) {
TitleSetInfo& tsi = di.titlesets[ts];
if (tsi.vts_ifo_sector == 0) continue;
tsi.vtsm_vobs_sector = tsi.vts_ifo_sector + disc.GetDword(tsi.vts_ifo_sector, 0xC0);
tsi.vts_vobs_sector = tsi.vts_ifo_sector + disc.GetDword(0xC4);
tsi.vts_bup_sector = tsi.vts_ifo_sector + disc.GetDword(0x0C) - disc.GetDword(0x1C);
tsi.number_of_existing_subpicture_tracks = disc.GetDword(0x254) >> 16;
unsigned flags = disc.GetDword(0x200);
tsi.ntsc = ~(flags >> 28) & 1;
tsi.wide_aspect = (flags >> 27) & 1;
unsigned pgci_sector = disc.GetDword(0xCC);
unsigned tmapti_sector = disc.GetDword(0xD4);
unsigned c_adt_sector = disc.GetDword(0xE0);
unsigned vobu_admap_sector = disc.GetDword(0xE4);
if (pgci_sector) {
tsi.num_pgcs = disc.GetDword(tsi.vts_ifo_sector + pgci_sector, 0) >> 16;
tsi.pgcs = (TitlePGCInfo*)bay->vtable->SharedPool_Alloc(bay, tsi.num_pgcs * sizeof(TitlePGCInfo));
unsigned pgc;
for (pgc = 0; pgc < tsi.num_pgcs; ++pgc) {
tsi.pgcs[pgc].subpicture_status_offset = pgci_sector*2048 + disc.GetDword(tsi.vts_ifo_sector + pgci_sector, pgc*8+12) + 0x1C;
}
for (pgc = 0; pgc < tsi.num_pgcs; ++pgc) {
unsigned pgc_offset = tsi.pgcs[pgc].subpicture_status_offset - 0x1C;
unsigned num_cells = disc.GetDword(tsi.vts_ifo_sector, pgc_offset) & 255;
tsi.pgcs[pgc].cell_playback_info_table_offset = pgc_offset + (disc.GetDword(tsi.vts_ifo_sector, pgc_offset+0xE8) >> 16);
tsi.pgcs[pgc].cell_playback_info_table_end_offset = tsi.pgcs[pgc].cell_playback_info_table_offset + 24 * num_cells;
}
}
if (tmapti_sector) {
tsi.num_tmaps = disc.GetDword(tsi.vts_ifo_sector+tmapti_sector, 0) >> 16;
tsi.tmaps = (TitleTmapInfo*)bay->vtable->SharedPool_Alloc(bay, tsi.num_tmaps * sizeof(TitleTmapInfo));
unsigned tmap;
for (tmap = 0; tmap < tsi.num_tmaps; ++tmap) {
tsi.tmaps[tmap].offset = tmapti_sector * 2048 + disc.GetDword(tsi.vts_ifo_sector+tmapti_sector, 8 + tmap*4) + 4;
}
for (tmap = 0; tmap < tsi.num_tmaps; ++tmap) {
tsi.tmaps[tmap].end_offset = tsi.tmaps[tmap].offset + (disc.GetDword(tsi.vts_ifo_sector, tsi.tmaps[tmap].offset - 4) & 65535) * 4;
}
}
if (c_adt_sector) {
tsi.vts_c_adt_offset = c_adt_sector*2048 + 8;
tsi.vts_c_adt_end_offset = tsi.vts_c_adt_offset - 7 + disc.GetDword(tsi.vts_ifo_sector, tsi.vts_c_adt_offset - 4);
}
if (vobu_admap_sector) {
tsi.vts_vobu_admap_offset = vobu_admap_sector*2048 + 4;
tsi.vts_vobu_admap_end_offset = tsi.vts_vobu_admap_offset - 3 + disc.GetDword(tsi.vts_ifo_sector, tsi.vts_vobu_admap_offset - 4);
}
}
di.disc_id = disc.GetCumulativeCRC();
DiscInfo* pdi = (DiscInfo*)bay->vtable->SharedPool_Alloc(bay, sizeof(DiscInfo));
*pdi = di;
return pdi;
}
void PrintDiscInfo(DiscInfo* di) {
printf("di->vmg_ifo_sector = %X\n", di->vmg_ifo_sector);
printf("di->vmg_vobs_sector = %X\n", di->vmg_vobs_sector);
printf("di->vmg_bup_sector = %X\n", di->vmg_bup_sector);
printf("di->vmg_tt_srpt_offset = %X\n", di->vmg_tt_srpt_offset);
printf("di->vmg_tt_srpt_end_offset = %X\n", di->vmg_tt_srpt_end_offset);
printf("di->num_title_sets = %X\n", di->num_title_sets);
for (unsigned i=0; i<di->num_title_sets; ++i) {
printf("di->titlesets[%d].vts_ifo_sector = %X\n", i, di->titlesets[i].vts_ifo_sector);
printf("di->titlesets[%d].vtsm_vobs_sector = %X\n", i, di->titlesets[i].vtsm_vobs_sector);
printf("di->titlesets[%d].vts_vobs_sector = %X\n", i, di->titlesets[i].vts_vobs_sector);
printf("di->titlesets[%d].vts_bup_sector = %X\n", i, di->titlesets[i].vts_bup_sector);
printf("di->titlesets[%d].number_of_existing_subpicture_tracks = %X\n", i, di->titlesets[i].number_of_existing_subpicture_tracks);
printf("di->titlesets[%d].vts_c_adt_offset = %X\n", i, di->titlesets[i].vts_c_adt_offset);
printf("di->titlesets[%d].vts_c_adt_end_offset = %X\n", i, di->titlesets[i].vts_c_adt_end_offset);
printf("di->titlesets[%d].vts_vobu_admap_offset = %X\n", i, di->titlesets[i].vts_vobu_admap_offset);
printf("di->titlesets[%d].vts_vobu_admap_end_offset = %X\n", i, di->titlesets[i].vts_vobu_admap_end_offset);
printf("di->titlesets[%d].num_pgcs = %X\n", i, di->titlesets[i].num_pgcs);
printf("di->titlesets[%d].num_tmaps = %X\n", i, di->titlesets[i].num_tmaps);
unsigned j;
for (j=0; j<di->titlesets[i].num_pgcs; ++j) {
printf("di->titlesets[%d].pgcs[%d].subpicture_status_offset = %X\n", i, j, di->titlesets[i].pgcs[j].subpicture_status_offset);
printf("di->titlesets[%d].pgcs[%d].cell_playback_info_table_offset = %X\n", i, j, di->titlesets[i].pgcs[j].cell_playback_info_table_offset);
printf("di->titlesets[%d].pgcs[%d].cell_playback_info_table_end_offset = %X\n", i, j, di->titlesets[i].pgcs[j].cell_playback_info_table_end_offset);
}
for (j=0; j<di->titlesets[i].num_tmaps; ++j) {
printf("di->titlesets[%d].tmaps[%d].offset = %X\n", i, j, di->titlesets[i].tmaps[j].offset);
printf("di->titlesets[%d].tmaps[%d].end_offset = %X\n", i, j, di->titlesets[i].tmaps[j].end_offset);
}
}
};
/********************************************************************
********************************************************************/
class SubpictureReceiver : public ICompilerCallbacks, public IScannerCallbacks {
CompileDialog* const compile_dialog;
DVDSubberKernel* const k;
DvsDockingBay* const bay;
// const unsigned char* const map_data;
// unsigned const map_len;
HANDLE const hdatafile;
unsigned datafilepos;
SubpictureInfo** psi;
int angle;
bool got_title, got_angle;
unsigned numerator, denominator;
bool got_warning;
unsigned char* map_data;
unsigned map_pos, map_len;
unsigned num_vobus;
void LookupField(unsigned field, unsigned angle, bool ntsc, unsigned* plba, unsigned* pptm);
void Error(const char* msg, const char* fmt, int value);
void SubpictureReceiver::GrowMap();
public:
SubpictureReceiver(CompileDialog* _compile_dialog, DVDSubberKernel* _k, DvsDockingBay* _bay, HANDLE _hdatafile)
: compile_dialog(_compile_dialog), k(_k), bay(_bay), hdatafile(_hdatafile)
{
datafilepos = 0;
psi = &k->subpic_inf;
k->title = 0; angle = 1;
got_title = false; got_angle = false;
numerator = 0; denominator = 1;
got_warning = false;
map_data = 0;
k->num_subpics = 0;
k->palette_size = 0;
}
bool UserAborted();
bool GotWarning() { return got_warning; }
void NotifySubpictureCount(unsigned num_subpictures);
void NotifyDoneParsing();
bool IsNTSC();
void AddSubpicture(unsigned base_field, const unsigned char* data);
int ColorLookup(unsigned rgb);
void SetVTSNumber(int vts_number);
void SetAngle(int angle);
bool ReadSector(unsigned lba, unsigned char* buf);
void AddVOBU(unsigned lba, unsigned vobu_number, unsigned num_fields, unsigned num_data_blocks);
void ChangePTM(unsigned new_ptm);
void ChangeAngle(unsigned new_angle);
void Note(const char* msg);
void Warning(const char* msg);
void ErrorAtLine(const char* msg, int line);
void ErrorAtTime(const char* msg, unsigned field);
void ErrorAtLBA(const char* msg, unsigned lba);
};
void SubpictureReceiver::LookupField(unsigned field, unsigned angle, bool ntsc, unsigned* plba, unsigned* pptm) {
const unsigned char* p = map_data;
const unsigned char* end = map_data + map_len;
unsigned base_ptm = 0, base_field = 0, cur_field = 0, cur_sector = 0, cur_angle = 0;
while (p < end) {
unsigned char ch = *p++;
if (ch < 0xF0 || ch == 0xFE) {
unsigned fields, intervening_sectors;
if (ch < 0xF0) {
fields = ch >> 2;
intervening_sectors = (ch&3) * 256 + (*p++);
} else {
fields = p[0]*256 + p[1];
intervening_sectors = p[2]*256 + p[3];
p += 4;
}
if (cur_angle==0 || cur_angle==angle) {
cur_field += fields;
if (cur_field > field) {
*plba = cur_sector + 2;
*pptm = base_ptm + (field-base_field) * (ntsc?3003:3600) / 2;
return;
}
}
cur_sector += intervening_sectors+1;
} else if (ch == 0xFF) {
if (cur_angle==0 || cur_angle==angle) {
base_field = cur_field;
base_ptm = 0;
for (int i=0; i<4; ++i) base_ptm = base_ptm*256 + (*p++);
} else {
p += 4;
}
} else {
cur_angle = ch & 15;
}
}
// this is caught in DVDSubber-compile.cpp; not really kosher
throw "Field number too large";
}
void SubpictureReceiver::NotifySubpictureCount(unsigned num_subpictures) {
denominator = num_subpictures;
}
void SubpictureReceiver::NotifyDoneParsing() {
char map_file[MAX_PATH+32];
wsprintf(map_file, "%sdvdsub_%08x_%x.map",
g_bays->GetDvdsynthDirectory(),
k->disc_info->disc_id, k->title);
HANDLE hmapfile = CreateFile(map_file, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hmapfile != INVALID_HANDLE_VALUE) {
map_len = GetFileSize(hmapfile, NULL);
map_data = new unsigned char[map_len];
DWORD read;
ReadFile(hmapfile, map_data, map_len, &read, NULL);
CloseHandle(hmapfile);
} else {
hmapfile = CreateFile(map_file, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hmapfile != INVALID_HANDLE_VALUE) {
map_len = 10000;
map_pos = 0;
map_data = new unsigned char[map_len];
const TitleSetInfo& tsi = k->disc_info->titlesets[k->title];
unsigned vts_vobs_lba = tsi.vts_vobs_sector;
unsigned vobu_admap_lba = tsi.vts_ifo_sector + (tsi.vts_vobu_admap_offset >> 11);
num_vobus = (tsi.vts_vobu_admap_end_offset - tsi.vts_vobu_admap_offset) >> 2;
if (Scan(vobu_admap_lba, num_vobus, vts_vobs_lba, this)) {
map_len = map_pos;
DWORD written;
WriteFile(hmapfile, map_data, map_pos, &written, NULL);
CloseHandle(hmapfile);
} else {
CloseHandle(hmapfile);
DeleteFile(map_file);
throw 0;
}
} else {
Error("Could not open the cache file", " (\"%s\")", (int)map_file);
throw 0;
}
}
}
bool SubpictureReceiver::UserAborted() {
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, TRUE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return compile_dialog->ButtonPressed();
}
bool SubpictureReceiver::IsNTSC() {
return k->disc_info->titlesets[k->title].ntsc;
}
void SubpictureReceiver::AddSubpicture(unsigned base_field, const unsigned char* data) {
if (*psi == 0) {
*psi = (SubpictureInfo*)bay->vtable->SharedPool_Alloc(bay, sizeof(SubpictureInfo));
(*psi)->next = 0;
}
SubpictureInfo* si = *psi;
psi = &si->next;
unsigned sector;
LookupField(base_field, angle, true, §or, &si->ptm);
si->hard_lba = sector + k->disc_info->titlesets[k->title].vts_vobs_sector;
si->file_offset = datafilepos;
unsigned data_len = data[0]*256+data[1];
si->data_len = data_len;
si->num_sectors = (data_len + (rest_data_packet_len-first_data_packet_len) + (rest_data_packet_len-1)) / rest_data_packet_len;
DWORD written;
if (!WriteFile(hdatafile, data, data_len, &written, NULL) || written != data_len)
throw "Unable to write temporary file -- the disk may be full";
datafilepos += data_len;
++k->num_subpics;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -