Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 129 additions & 70 deletions lsdvd-0.16/lsdvd.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* -*- c-basic-offset:8; indent-tabs-mode:t -*- vi: set sw=8: */
/*
* lsdvd.c
*
Expand Down Expand Up @@ -47,7 +48,7 @@ language[] = {
{ "pt", "Portugues" }, { "qu", "Quechua" }, { "rm", "Rhaeto-Romance" }, { "rn", "Kirundi" }, { "ro", "Romanian" },
{ "ru", "Russian" }, { "rw", "Kinyarwanda" }, { "sa", "Sanskrit" }, { "sd", "Sindhi" }, { "sg", "Sangho" },
{ "sh", "Serbo-Croatian" }, { "si", "Sinhalese" }, { "sk", "Slovak" }, { "sl", "Slovenian" }, { "sm", "Samoan" },
{ "sn", "Shona" }, { "so", "Somali" }, { "sq", "Albanian" }, { "sr", "Serbian" }, { "ss", "Siswati" },
{ "sn", "Shona" }, { "so", "Somali" }, { "sq", "Albanian" }, { "sr", "Serbian" }, { "ss", "Siswati" },
{ "st", "Sesotho" }, { "su", "Sundanese" }, { "sv", "Svenska" }, { "sw", "Swahili" }, { "ta", "Tamil" },
{ "te", "Telugu" }, { "tg", "Tajik" }, { "th", "Thai" }, { "ti", "Tigrinya" }, { "tk", "Turkmen" }, { "tl", "Tagalog" },
{ "tn", "Setswana" }, { "to", "Tonga" }, { "tr", "Turkish" }, { "ts", "Tsonga" }, { "tt", "Tatar" }, { "tw", "Twi" },
Expand Down Expand Up @@ -75,8 +76,8 @@ char *sample_freq[2] = {"48000", "48000"};
char *audio_type[5] = {"Undefined", "Normal", "Impaired", "Comments1", "Comments2"};
char *subp_type[16] = {"Undefined", "Normal", "Large", "Children", "reserved", "Normal_CC", "Large_CC", "Children_CC",
"reserved", "Forced", "reserved", "reserved", "reserved", "Director", "Large_Director", "Children_Director"};
int subp_id_shift[4] = {24, 8, 8, 8};
double frames_per_s[4] = {-1.0, 25.00, -1.0, 29.97};
int subp_id_shift[4] = {24, 8, 8, 8};

char* program_name;

Expand All @@ -85,38 +86,79 @@ char* program_name;
//extern void oruby_print(struct dvd_info *dvd_info);
//extern void ohuman_print(struct dvd_info *dvd_info);

int dvdtime2msec(dvd_time_t *dt)
{
double fps = frames_per_s[(dt->frame_u & 0xc0) >> 6];
long ms;
ms = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000;
ms += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000;
ms += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000;
/* Ticks
*
* Compute durations using rational arithmetic to avoid loss of precision
* when summing. The result of the sum will be exact prior to converting
* the sum.
*/
#define TICK_SCALE 1001

typedef struct {
unsigned ticks;
unsigned scale;
} dvd_ticks_t;

dvd_ticks_t dvdtime2ticks(const dvd_time_t *dt)
{
unsigned scale = 0;
unsigned secs = 0;
unsigned ticks = 0;

if (dt) {
static const unsigned tick_scale[4] = {
0, 25 * TICK_SCALE, 0, 30 * (TICK_SCALE-1) };

scale = tick_scale[(dt->frame_u & 0xc0) >> 6];

if(fps > 0)
ms += (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 1000.0 / fps;
secs += (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600;
secs += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60;
secs += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1;

return ms;
ticks += ((dt->frame_u & 0x30)>> 3) * 5 + (dt->frame_u & 0x0f);
ticks *= TICK_SCALE;
}

return (dvd_ticks_t) {
.scale = scale,
.ticks = secs * scale + ticks,
};
}

dvd_ticks_t addticks(dvd_ticks_t lhs, dvd_ticks_t rhs)
{
if (lhs.ticks == 0)
return rhs;
if (rhs.ticks == 0)
return lhs;
return (dvd_ticks_t) {
.ticks = lhs.ticks + rhs.ticks,
.scale = lhs.scale == rhs.scale ? lhs.scale : 0,
};
}

/*
* This is used to add up sets of times in the struct. it's not elegant at all
* but a quick way to easily add up 4 times at once. tracking the times in usec's
* constantly is easier, but without using math.h, it sucks to actually DO anything with it
* also it ***has*** to be better to return the playback_time, not just mess with it like this
*/
void converttime(playback_time_t *pt, dvd_time_t *dt)
playback_time_t ticks2playbacktime(dvd_ticks_t dt)
{
double fps = frames_per_s[(dt->frame_u & 0xc0) >> 6];

pt->usec = pt->usec + (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 1000.0 / fps;
pt->second = pt->second + ((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f);
pt->minute = pt->minute + ((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f);
pt->hour = pt->hour + ((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f);
unsigned secs = dt.ticks / dt.scale;
unsigned frac = dt.ticks % dt.scale;

return (playback_time_t) {
.hour = (secs / 3600),
.minute = (secs % 3600) / 60,
.second = (secs % 60),
.usec = (frac * (1000000 / dt.scale) +
frac * (1000000 % dt.scale) / dt.scale),
.ticks = (dt.ticks),
.scale = (dt.scale),
};
}

if ( pt->usec >= 1000 ) { pt->usec -= 1000; pt->second++; }
if ( pt->second >= 60 ) { pt->second -= 60; pt->minute++; }
if ( pt->minute > 59 ) { pt->minute -= 60; pt->hour++; }
double playbacktime(playback_time_t pt)
{
return pt.hour * 3600 +
pt.minute * 60 +
pt.second * 1 +
pt.usec / 1e6;
}

/*
Expand Down Expand Up @@ -221,7 +263,7 @@ char output_option(char *arg)
return '\0';
}
}


int main(int argc, char *argv[])
{
Expand All @@ -235,8 +277,8 @@ int main(int argc, char *argv[])
video_attr_t *video_attr;
subp_attr_t *subp_attr;
pgc_t *pgc;
int i, j, k, c, titles, cell, vts_ttn, title_set_nr;
char lang_code[3];
int i, j, k, c, titles, vts_ttn, title_set_nr;
char lang_code[3];
char *dvd_device = "/dev/dvd";
int has_title = 0, ret = 0;
int max_length = 0, max_track = 0;
Expand Down Expand Up @@ -272,13 +314,13 @@ int main(int argc, char *argv[])
}

if (argv[optind]) { dvd_device = argv[optind]; }

ret = stat(dvd_device, &dvd_stat);
if ( ret < 0 ) {
fprintf(stderr, "Can't find device %s\n", dvd_device);
return 1;
}

dvd = DVDOpen(dvd_device);
if( !dvd ) {
fprintf( stderr, "Can't open disc %s!\n", dvd_device);
Expand Down Expand Up @@ -312,12 +354,12 @@ int main(int argc, char *argv[])
vmgi_mat = ifo_zero->vmgi_mat;

struct dvd_info dvd_info;

dvd_info.discinfo.device = dvd_device;
dvd_info.discinfo.disc_title = has_title ? "unknown" : title;
dvd_info.discinfo.vmg_id = vmgi_mat->vmg_identifier;
dvd_info.discinfo.provider_id = vmgi_mat->provider_identifier;

dvd_info.title_count = titles;
dvd_info.titles = calloc(titles, sizeof(*dvd_info.titles));

Expand All @@ -338,13 +380,16 @@ int main(int argc, char *argv[])
vmgi_mat = ifo_zero->vmgi_mat;
title_set_nr = ifo_zero->tt_srpt->title[j].title_set_nr;
pgc = vts_pgcit->pgci_srp[ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;

dvd_info.titles[j].general.length = dvdtime2msec(&pgc->playback_time)/1000.0;
converttime(&dvd_info.titles[j].general.playback_time, &pgc->playback_time);
dvd_info.titles[j].general.length =
playbacktime(
ticks2playbacktime(
dvdtime2ticks(&pgc->playback_time)));
dvd_info.titles[j].general.playback_time =
ticks2playbacktime(dvdtime2ticks(&pgc->playback_time));
dvd_info.titles[j].general.vts_id = vtsi_mat->vts_identifier;
if (dvdtime2msec(&pgc->playback_time) > max_length) {
max_length = dvdtime2msec(&pgc->playback_time);

if (dvd_info.titles[j].general.length > max_length) {
max_length = dvd_info.titles[j].general.length;
max_track = j+1;
}

Expand All @@ -353,12 +398,12 @@ int main(int argc, char *argv[])

dvd_info.titles[j].audiostream_count = 0;
for (k=0; k < 8; k++)
if (pgc->audio_control[k] & 0x8000)
if (pgc->audio_control[k] & 0x8000)
dvd_info.titles[j].audiostream_count++;

dvd_info.titles[j].subtitle_count = 0;
for (k=0; k < 32; k++)
if (pgc->subp_control[k] & 0x80000000)
if (pgc->subp_control[k] & 0x80000000)
dvd_info.titles[j].subtitle_count++;

if(opt_v) {
Expand All @@ -376,7 +421,7 @@ int main(int argc, char *argv[])
// PALETTE
if (opt_P) {
dvd_info.titles[j].palette = malloc(16 * sizeof(int));
for (i=0; i < 16; i++) { dvd_info.titles[j].palette[i] = pgc->palette[i]; }
for (i=0; i < 16; i++) { dvd_info.titles[j].palette[i] = pgc->palette[i]; }
} else {
dvd_info.titles[j].palette = NULL;
}
Expand Down Expand Up @@ -420,32 +465,38 @@ int main(int argc, char *argv[])

// CHAPTERS

cell = 0;
if (opt_c) {
int cell = pgc->program_map[0] - 1;
int end = cell + pgc->nr_of_cells;

dvd_info.titles[j].chapter_count = pgc->nr_of_programs;
dvd_info.titles[j].chapters = calloc(dvd_info.titles[j].chapter_count, sizeof(*dvd_info.titles[j].chapters));

int ms;
for (i=0; i<pgc->nr_of_programs; i++)
{
ms=0;
int next = pgc->program_map[i+1];
if (i == pgc->nr_of_programs - 1) next = pgc->nr_of_cells + 1;

while (cell < next - 1)
{
dvd_ticks_t ticks = dvdtime2ticks(NULL);
int next =
(i == pgc->nr_of_programs - 1)
? end
: pgc->program_map[i+1] - 1;
while (cell < next)
{
// Only use first cell of multi-angle cells
if (pgc->cell_playback[cell].block_mode <= 1)
{
ms = ms + dvdtime2msec(&pgc->cell_playback[cell].playback_time);
converttime(&dvd_info.titles[j].chapters[i].playback_time, &pgc->cell_playback[cell].playback_time);
dvd_ticks_t dt = dvdtime2ticks(
&pgc->cell_playback[cell].playback_time);
ticks = addticks(ticks, dt);
dvd_info.titles[j].chapters[i].playback_time =
ticks2playbacktime(dt);
}
cell++;
}
dvd_info.titles[j].chapters[i].startcell = pgc->program_map[i];
dvd_info.titles[j].chapters[i].length = ms * 0.001;


dvd_info.titles[j].chapters[i].lastcell = cell;
dvd_info.titles[j].chapters[i].length =
playbacktime(
ticks2playbacktime(ticks));
}
}

Expand All @@ -457,10 +508,18 @@ int main(int argc, char *argv[])
if (opt_d) {
for (i=0; i<pgc->nr_of_cells; i++)
{
dvd_info.titles[j].cells[i].length = dvdtime2msec(&pgc->cell_playback[i].playback_time)/1000.0;
dvd_ticks_t dt = dvdtime2ticks(
&pgc->cell_playback[i].playback_time);
playback_time_t pt = ticks2playbacktime(dt);

dvd_info.titles[j].cells[i].playback_time = pt;
dvd_info.titles[j].cells[i].length =
playbacktime(pt);

dvd_info.titles[j].cells[i].block_mode = pgc->cell_playback[i].block_mode;
dvd_info.titles[j].cells[i].block_type = pgc->cell_playback[i].block_type;
converttime(&dvd_info.titles[j].cells[i].playback_time, &pgc->cell_playback[i].playback_time);
dvd_info.titles[j].cells[i].first_sector = pgc->cell_playback[i].first_sector;
dvd_info.titles[j].cells[i].last_sector = pgc->cell_playback[i].last_sector;
}
} else {
dvd_info.titles[j].cells = NULL;
Expand All @@ -474,11 +533,11 @@ int main(int argc, char *argv[])
for (i=0, k=0; i<32; i++)
{
if ((pgc->subp_control[i] & 0x80000000) == 0) continue;

subp_attr = &vtsi_mat->vts_subp_attr[i];
sprintf(lang_code, "%c%c", subp_attr->lang_code>>8, subp_attr->lang_code & 0xff);
if (!isalpha(lang_code[0]) || !isalpha(lang_code[1])) { lang_code[0] = 'x'; lang_code[1] = 'x'; }

dvd_info.titles[j].subtitles[k].langcode = strdup(lang_code);
dvd_info.titles[j].subtitles[k].language = lang_name(lang_code);
dvd_info.titles[j].subtitles[k].content = subp_type[subp_attr->lang_extension];
Expand All @@ -489,33 +548,33 @@ int main(int argc, char *argv[])
dvd_info.titles[j].subtitles = NULL;
}

} // if vtsi_mat
} // if vtsi_mat
} // if not -t
} // for each title

if (! opt_t) { dvd_info.longest_track = max_track; }

if (opt_p) {
ocode_print(&perl_syntax, &dvd_info);
} else {
switch(opt_O) {
case 'p':
ocode_print(&perl_syntax, &dvd_info);
case 'p':
ocode_print(&perl_syntax, &dvd_info);
break;
case 'y':
ocode_print(&python_syntax, &dvd_info);
ocode_print(&python_syntax, &dvd_info);
break;
case 'x':
oxml_print(&dvd_info);
oxml_print(&dvd_info);
break;
case 'r':
ocode_print(&ruby_syntax, &dvd_info);
ocode_print(&ruby_syntax, &dvd_info);
break;
case 'd':
ocode_print(&debug_syntax, &dvd_info);
ocode_print(&debug_syntax, &dvd_info);
break;
default :
ohuman_print(&dvd_info);
ohuman_print(&dvd_info);
break;
}
}
Expand Down
9 changes: 8 additions & 1 deletion lsdvd-0.16/lsdvd.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

/* -*- c-basic-offset:8; indent-tabs-mode:t -*- vi: set sw=8: */
#ifndef _LSDVD_H_
#define _LSDVD_H_

#include <stdint.h>

extern int opt_a, opt_c, opt_n, opt_p, opt_q;
extern int opt_s, opt_t, opt_v, opt_x, opt_d;

Expand All @@ -10,6 +12,8 @@ typedef struct {
int minute;
int second;
int usec;
int ticks;
int scale;
} playback_time_t;

struct dvd_info {
Expand Down Expand Up @@ -56,11 +60,14 @@ struct dvd_info {
float length;
playback_time_t playback_time;
int startcell;
int lastcell;
} *chapters;
int cell_count;
struct {
float length;
playback_time_t playback_time;
uint32_t first_sector;
uint32_t last_sector;
int block_mode;
int block_type;
} *cells;
Expand Down
Loading