📄 dvdsubber.cpp
字号:
++numerator;
if ((numerator & 31) == (denominator & 31))
compile_dialog->SetProgress(numerator, denominator);
}
inline int ScaledPixelClip(int x) {
x = (x + 0x8000) >> 16;
return (x<=0 ? 0 : x>=255 ? 255 : x);
}
int RGB2YVU(int rgb) {
const int cyb = int(0.114*219/255*65536+0.5);
const int cyg = int(0.587*219/255*65536+0.5);
const int cyr = int(0.299*219/255*65536+0.5);
// y can't overflow
int y = (cyb*(rgb&255) + cyg*((rgb>>8)&255) + cyr*((rgb>>16)&255) + 0x108000) >> 16;
int scaled_y = (y - 16) * int(255.0/219.0*65536+0.5);
int b_y = ((rgb&255) << 16) - scaled_y;
int u = ScaledPixelClip((b_y >> 10) * int(1/2.018*1024+0.5) + 0x800000);
int r_y = (rgb & 0xFF0000) - scaled_y;
int v = ScaledPixelClip((r_y >> 10) * int(1/1.596*1024+0.5) + 0x800000);
return (y*256+v)*256+u;
}
int SubpictureReceiver::ColorLookup(unsigned rgb) {
unsigned yvu = RGB2YVU(rgb);
int i;
for (i = 0; i < k->palette_size; ++i) {
if (k->palette[i] == yvu)
break;
}
if (i >= k->palette_size) {
if (i >= 16) {
return -1;
}
k->palette[k->palette_size++] = yvu;
}
return 15 - i;
}
void SubpictureReceiver::SetVTSNumber(int vts_number) {
if (got_title)
throw "Only one <vts> command allowed";
got_title = true;
if (vts_number < 1 || vts_number > int(k->disc_info->num_title_sets))
throw "VTS number out of range";
k->title = vts_number - 1;
}
void SubpictureReceiver::SetAngle(int _angle) {
if (got_angle)
throw "Only one <angle> command allowed";
got_angle = true;
angle = _angle;
}
bool SubpictureReceiver::ReadSector(unsigned lba, unsigned char* buf) {
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] = lba >> (i*8);
}
unsigned long buflen = 2048;
SenseData sense;
return SCSIRESULT_SUCCESS == g_bays->KernelScsiCommand(k->child, cdb, 10, buf, &buflen, 1, &sense);
}
void SubpictureReceiver::GrowMap() {
map_len *= 2;
unsigned char* new_map = new unsigned char[map_len];
memcpy(new_map, map_data, map_pos);
delete[] map_data;
map_data = new_map;
}
void SubpictureReceiver::AddVOBU(unsigned lba, unsigned vobu_number, unsigned num_fields, unsigned num_data_blocks) {
if (num_fields < 60 && num_data_blocks < 0x400) {
if (map_pos > map_len - 2) {
GrowMap();
}
map_data[map_pos] = (num_fields<<2) + (num_data_blocks>>8);
map_data[map_pos+1] = num_data_blocks;
map_pos += 2;
} else {
if (num_fields >= 0x10000 || num_data_blocks >= 0x10000) {
ErrorAtLBA("Unexpectedly long VOBU", lba);
throw 0;
}
if (map_pos > map_len - 5) {
GrowMap();
}
map_data[map_pos] = 0xFE;
map_data[map_pos+1] = num_fields >> 8;
map_data[map_pos+2] = num_fields;
map_data[map_pos+3] = num_data_blocks >> 8;
map_data[map_pos+4] = num_data_blocks;
map_pos += 5;
}
compile_dialog->SetProgress(vobu_number, num_vobus);
}
void SubpictureReceiver::ChangePTM(unsigned new_ptm) {
if (map_pos > map_len - 5) {
GrowMap();
}
map_data[map_pos] = 0xFF;
for (int i=0; i<4; ++i) {
map_data[map_pos+i+1] = new_ptm >> (24-i*8);
}
map_pos += 5;
}
void SubpictureReceiver::ChangeAngle(unsigned new_angle) {
if (map_pos >= map_len) {
GrowMap();
}
map_data[map_pos++] = 0xF0 + new_angle;
}
void SubpictureReceiver::Note(const char* msg) {
compile_dialog->AddMessage(msg);
}
void SubpictureReceiver::Warning(const char* msg) {
compile_dialog->AddMessage(msg);
got_warning = true;
}
void SubpictureReceiver::Error(const char* msg, const char* fmt, int value) {
compile_dialog->AddMessage("*** ERROR:");
compile_dialog->AddMessage(msg);
char buf[1024];
sprintf(buf, fmt, value);
compile_dialog->AddMessage(buf);
}
void SubpictureReceiver::ErrorAtLBA(const char* msg, unsigned lba) {
Error(msg, "(at logical block address %X)", lba);
}
void SubpictureReceiver::ErrorAtLine(const char* msg, int line) {
Error(msg, "(at script file line %d)", line);
}
void SubpictureReceiver::ErrorAtTime(const char* msg, unsigned field) {
Error(msg, "(at video field %d)", field);
}
bool ChooseFile(char* filename, const char* title, const char* filters) {
OPENFILENAME ofn;
ofn.lStructSize = 76;
ofn.hwndOwner = NULL;
ofn.hInstance = g_hinstance;
ofn.lpstrFilter = filters;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 2;
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = title;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = NULL;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
return !!GetOpenFileName(&ofn);
}
bool CreateTempFile(HANDLE* puserhandle, dvs_file_handle* pkernelhandle) {
char temp_path[MAX_PATH];
if (!GetTempPath(MAX_PATH, temp_path)) {
MessageBox(NULL, "Could not get temporary directory.", "DVDSubber", MB_OK);
return false;
}
char temp_name[MAX_PATH];
if (!GetTempFileName(temp_path, "DVS", 0, temp_name)) {
MessageBox(NULL, "Could not get temporary file name.", "DVDSubber", MB_OK);
return false;
}
HANDLE htemp = CreateFile(temp_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, TRUNCATE_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (htemp == INVALID_HANDLE_VALUE) {
MessageBox(NULL, "Could not create temporary file.", "DVDSubber", MB_OK);
return false;
}
dvs_file_handle temphandle;
if (0 != g_bays->OpenFileRO(&temphandle, temp_name)) {
MessageBox(NULL, "Could not create temporary file (in kernel mode).", "DVDSubber", MB_OK);
CloseHandle(htemp);
return false;
}
*puserhandle = htemp;
*pkernelhandle = temphandle;
return true;
}
class FileLRU {
enum { max_files = 12 };
char* ptrs[max_files];
int num_files;
char buf[max_files][MAX_PATH];
public:
FileLRU() {
for (int i=0; i<max_files; ++i) {
ptrs[i] = buf[i];
}
num_files = 0;
}
const char* Get(int index) {
return index >= 0 && index < num_files ? ptrs[index] : 0;
}
void Promote(const char* entry) {
int i;
for (i=0; i<num_files-1; ++i) {
if (ptrs[i] == entry) {
break;
}
}
char* t = ptrs[i];
while (i>0) {
ptrs[i] = ptrs[i-1];
--i;
}
ptrs[0] = t;
if (ptrs[0] != entry) {
lstrcpy(ptrs[0], entry);
}
}
void Demote(const char* entry) {
int i;
for (i=0; i<num_files; ++i) {
if (ptrs[i] == entry) {
char* t = ptrs[i];
while (i<num_files-1) {
ptrs[i] = ptrs[i+1];
++i;
}
ptrs[num_files-1] = t;
break;
}
}
}
};
FileLRU file_lru;
bool CompileSubtitlesCatch(FILE* out, ICompilerCallbacks* compiler_callbacks) {
try {
return CompileSubtitles(out, compiler_callbacks);
}
catch (...) {
return false;
}
}
void ApplySubtitles(void* _self, int _subtitle_filename) {
// put subtitle filename at top of LRU
const char* subtitle_filename = (char*)_subtitle_filename;
file_lru.Promote(subtitle_filename);
DVDSubberUser* self = (DVDSubberUser*)_self;
DVDSubberKernel* k = self->k;
// make temp. file for compiled subtitles
if (k->data_file_handle == 0) {
if (!CreateTempFile(&self->data_file_handle, &k->data_file_handle))
return;
}
// make drive appear empty while we update the disc
g_bays->Driver_Call(self->driver_handle, "SetState", "pi", k, int(stateUpdating));
// remove old subtitles
k->num_subpics = 0;
// remove old subpicture data
SetFilePointer(self->data_file_handle, 0, NULL, FILE_BEGIN);
SetEndOfFile(self->data_file_handle);
if (subtitle_filename) {
FILE* fsub = fopen(subtitle_filename, "r");
if (!fsub) {
MessageBox(NULL, "Could not open the subtitle file.", "DVDSubber", MB_OK);
} else {
scsi_result_t scsi_error = 0;
try {
k->disc_info = GetDiscInfo(k->child, self->bay);
}
catch (scsi_result_t result) {
scsi_error = result;
k->disc_info = 0;
}
if (scsi_error) {
char buf[128];
wsprintf(buf, "Failed to get disc info: SCSI error %X.", scsi_error);
MessageBox(NULL, buf, "DVDSubber", MB_OK);
} else if (!k->disc_info) {
MessageBox(NULL, "Failed to get disc info. (Maybe there is not a DVD-Video disc in the drive?)", "DVDSubber", MB_OK);
} else {
PrintDiscInfo(k->disc_info);
CompileDialog* compile_dialog = new CompileDialog;
SubpictureReceiver subpic_receiver(compile_dialog, k, self->bay, self->data_file_handle);
if (CompileSubtitlesCatch(fsub, &subpic_receiver)) {
if (subpic_receiver.GotWarning()) {
subpic_receiver.Note("Compilation was successful, but there were warnings.");
compile_dialog->SetButtonAutoclose("OK");
} else {
compile_dialog->Destroy();
}
} else {
if (subpic_receiver.UserAborted()) {
compile_dialog->Destroy();
} else {
subpic_receiver.Note("Compilation was not successful.");
compile_dialog->SetButtonAutoclose("OK");
}
k->num_subpics = 0;
}
k->saved_scr_lba = 0xFFFFFFF0;
}
fclose(fsub);
}
}
g_bays->Driver_Call(self->driver_handle, "SetState", "pi", k, int(stateUpdated));
}
void OpenSubtitles(void* _self, int) {
static char subtitle_filename[MAX_PATH];
if (ChooseFile(subtitle_filename, "Choose subtitle file", "DVD subber scripts (*.dvdsub)\0*.dvdsub\0")) {
ApplySubtitles(_self, (int)subtitle_filename);
}
}
void AddDeviceMenuItems(DvsDeviceUser* _self, DvsMenu* menu) {
menu->vtable->BeginSubmenu(menu, "DVD subber", false);
menu->vtable->AddItem(menu, "&Open...", false, OpenSubtitles, _self, 0);
DVDSubberUser* self = (DVDSubberUser*)_self;
if (self->k->num_subpics != 0) {
menu->vtable->AddItem(menu, "&Remove current subtitles", false, ApplySubtitles, _self, 0);
}
// menu->vtable->AddItem(menu, "Scan disc", false, ScanDisc, _self, 0);
menu->vtable->AddSeparator(menu);
for (int i = 0; ; ++i) {
const char* name = file_lru.Get(i);
if (name==0) break;
menu->vtable->AddItem(menu, name, false, ApplySubtitles, _self, int(name));
}
menu->vtable->EndSubmenu(menu);
}
void Delete(DvsDeviceUser* _self) {
DVDSubberUser* self = (DVDSubberUser*)_self;
if (self->k->data_file_handle != 0) {
g_bays->CloseFile(self->k->data_file_handle);
}
if (self->data_file_handle) {
CloseHandle(self->data_file_handle);
}
g_bays->Driver_Unload(self->driver_handle);
delete self;
}
DvsDeviceUser_vtable DVDSubberUser_vtable = {
AddDeviceMenuItems,
0,
Delete
};
DvsDeviceUser* HookDevice(DvsDeviceKernel** pkernel, DvsDockingBay* bay) {
DVDSubberUser* u = new DVDSubberUser;
u->vtable = &DVDSubberUser_vtable;
u->bay = bay;
u->driver_handle = g_bays->Driver_Load("DVDSubber.kll");
if (!u->driver_handle)
return 0;
u->data_file_handle = NULL;
DVDSubberKernel* k = u->k = (DVDSubberKernel*)bay->vtable->SharedPool_Alloc(bay, sizeof(DVDSubberKernel));
k->ScsiCommand = (dvs_scsi_func*)g_bays->Driver_Call(u->driver_handle, "GetDispatchFunc", "");
k->child = *pkernel;
k->state = stateActive;
k->subpic_inf = 0;
k->num_subpics = 0;
k->data_file_handle = 0;
*pkernel = k;
return u;
}
DvsFilterGlobal filter_global = {
0,
"DVD Subtitler",
DVDSYNTH_FILTER_ONLY_ONE,
HookDevice,
0
};
extern "C"
DvsFilterGlobal* __cdecl DvdsynthFilterPluginEntry(DvsDockingBayGlobal* bays) {
g_bays = bays;
return &filter_global;
}
extern "C"
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID) {
g_hinstance = hinst;
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -