version update
[goodguy/cinelerra.git] / cinelerra-5.1 / libzmpeg3 / ifo.C
1 #include "libzmpeg3.h"
2 // dvd sector size
3 #if defined(__x86_64__)
4 #define DVD_VIDEO_LB_LEN 2048L
5 #else
6 #define DVD_VIDEO_LB_LEN 2048LL
7 #endif
8
9 int zifo_t::
10 ifo_read(long pos, long count, uint8_t *data)
11 {
12   int64_t ret = 0;
13   int retry = 5;
14   while( retry > 0 ) {
15     ret = lseek(fd, pos, SEEK_SET);
16     if( ret >= 0 ) break;
17     perr("ifo_seek");
18     sleep(1);
19     --retry;
20   }
21   while( retry > 0 ) {
22     ret = read(fd, data, count); 
23     if( ret > 0 ) break;
24    if( ret == 0 ) {
25       zerr("unable to read ifo\n");
26       return -1;
27     }
28     if( errno != EAGAIN ) {
29       perr("read error");
30       return -1;
31     }
32     sleep(1);
33     --retry;
34   }
35   if( retry <= 0 ) {
36     perr("timeout");
37     return -1;
38   }
39   return ret;
40 }
41
42 int zifo_t::
43 get_table(int64_t offset, unsigned long tbl_id)
44 {
45   int64_t len = 0;
46   if( !offset ) return -1;
47   uint8_t *zdata = new uint8_t[DVD_VIDEO_LB_LEN];
48   uint64_t ipos = pos + offset*DVD_VIDEO_LB_LEN;
49   int ret = ifo_read(ipos, DVD_VIDEO_LB_LEN, zdata);
50   if( ret < 0 ) return -1;
51
52   switch( tbl_id ) {
53   case id_TITLE_VOBU_ADDR_MAP:
54   case id_MENU_VOBU_ADDR_MAP:
55     len = get4bytes(zdata) + 1;
56     break;
57
58   default: 
59     len = hdr_length(zdata);
60   }
61
62   int ilen = len - DVD_VIDEO_LB_LEN;
63   if( ilen > 0 ) {
64     uint8_t *new_zdata = new uint8_t[len];
65     memcpy(new_zdata,zdata,DVD_VIDEO_LB_LEN);
66     memset(new_zdata+DVD_VIDEO_LB_LEN,0,len-DVD_VIDEO_LB_LEN);
67     delete zdata;
68     zdata = new_zdata;
69     ipos += DVD_VIDEO_LB_LEN;
70     ret = ifo_read(ipos, ilen, zdata+DVD_VIDEO_LB_LEN);
71     if( ret < 0 ) return -1;
72   }
73
74   data[tbl_id] = zdata;
75
76   if( tbl_id == id_TMT ) {
77     uint32_t *ptr = (uint32_t*)zdata;
78     len /= sizeof(*ptr);
79     for( int i=0; i < len; ++i )
80       ptr[i] = bswap_32(ptr[i]);
81   }
82
83   return 0;
84 }
85
86 zifo_t::
87 ifo_t(int zfd, long zpos)
88 {
89   pos = zpos; 
90   fd = zfd;
91   char *cp = getenv("IFO_STREAM_PROBE");
92   if( cp ) empirical = atoi(cp);
93 }
94
95 zifo_t::
96 ~ifo_t()
97 {
98   if( data[id_MAT] )                 delete data[id_MAT];
99   if( data[id_PTT] )                 delete data[id_PTT];
100   if( data[id_TITLE_PGCI] )          delete data[id_TITLE_PGCI];
101   if( data[id_MENU_PGCI] )           delete data[id_MENU_PGCI];
102   if( data[id_TMT] )                 delete data[id_TMT];
103   if( data[id_MENU_CELL_ADDR] )      delete data[id_MENU_CELL_ADDR];
104   if( data[id_MENU_VOBU_ADDR_MAP] )  delete data[id_MENU_VOBU_ADDR_MAP];
105   if( data[id_TITLE_CELL_ADDR] )     delete data[id_TITLE_CELL_ADDR];
106   if( data[id_TITLE_VOBU_ADDR_MAP] ) delete data[id_TITLE_VOBU_ADDR_MAP];
107 }
108
109 int zifo_t::
110 init_tables()
111 {
112   num_menu_vobs  = vtsm_vobs();
113   vob_start = vtstt_vobs();
114 //zmsgs("num of vobs: %x vob_start %x\n", num_menu_vobs, vob_start);
115   if( !type_vts() ) {
116     if( get_table(vts_ptt_srpt(), id_PTT) < 0 ||
117         get_table(vts_pgcit(), id_TITLE_PGCI) < 0 ||
118 //        get_table(vtsm_pgci_ut(), id_MENU_PGCI) < 0 ||
119 //        get_table(vts_tmapt(), id_TMT) < 0 ||
120 //        get_table(vtsm_c_adt(), id_MENU_CELL_ADDR) < 0 ||
121 //        get_table(vtsm_vobu_admap(), id_MENU_VOBU_ADDR_MAP) < 0 ||
122         get_table(vts_c_adt(), id_TITLE_CELL_ADDR) < 0 ||
123         get_table(vts_vobu_admap(), id_TITLE_VOBU_ADDR_MAP) < 0 )
124       return -1;
125   } 
126   else if( !type_vmg() ) {
127     if( get_table(tt_srpt(), id_TSP) < 0 ||
128         get_table(vmgm_pgci_ut(), id_MENU_PGCI) < 0 ||
129         get_table(vts_atrt(), id_TMT) < 0 ||
130         get_table(vmgm_c_adt(), id_TITLE_CELL_ADDR) < 0 ||
131         get_table(vmgm_vobu_admap(), id_TITLE_VOBU_ADDR_MAP) < 0 )
132       return -1;
133   }
134   return 0;
135 }
136
137 int zifo_t::
138 read_mat()
139 {
140   data[id_MAT] = new uint8_t[DVD_VIDEO_LB_LEN];
141   memset(data[id_MAT],0,DVD_VIDEO_LB_LEN);
142   return ifo_read(pos, DVD_VIDEO_LB_LEN, data[id_MAT]) < 0 ? -1 : 0;
143 }
144
145 zifo_t* zmpeg3_t::
146 ifo_open(int fd, long pos)
147 {
148   ifo_t *ifo = new ifo_t(fd,pos); 
149   if( ifo->read_mat() || ifo->init_tables() ) {
150     delete ifo;
151     ifo = NULL;
152   }
153   return ifo;
154 }
155
156 int zifo_t::
157 ifo_close()
158 {
159   delete this;
160   return 0;
161 }
162
163 void zifo_t::
164 get_palette(zmpeg3_t *zsrc)
165 {
166   if( !zsrc->have_palette ) {
167     /* subtitle color palette */
168     int ofs = 0;
169     uint8_t *ptr = palette();
170     for( int i=0; i<16; ++i ) {
171       int y = (int)ptr[ofs+1];
172       int u = (int)ptr[ofs+2];
173       int v = (int)ptr[ofs+3];
174       int k = i*4;
175       zsrc->palette[k+0] = y;
176       zsrc->palette[k+1] = u;
177       zsrc->palette[k+2] = v;
178 //zmsgs("color %02d: 0x%02x 0x%02x 0x%02x\n", i, y, u, v);
179       ofs += 4;
180     }
181     zsrc->have_palette = 1;
182   }
183 }
184
185 void zifo_t::
186 get_playlist(zmpeg3_t *zsrc)
187 {
188   DIR *dirstream;
189   char directory[STRLEN];
190   char filename[STRLEN];
191   char full_path[STRLEN];
192   char title_path[STRLEN];
193   char vob_prefix[STRLEN];
194   struct dirent *new_filename;
195   demuxer_t *demux = zsrc->demuxer;
196
197   /* Get titles matching ifo file */
198   complete_path(full_path, zsrc->fs->path);
199   get_directory(directory, full_path);
200   get_filename(filename, full_path);
201   strncpy(vob_prefix, filename, 6);
202
203   dirstream = opendir(directory);
204   while( (new_filename=readdir(dirstream)) != 0 ) {
205     if( !strncasecmp(new_filename->d_name, vob_prefix, 6) ) {
206       char *ptr = strrchr(new_filename->d_name, '.');
207       if( ptr && !strncasecmp(ptr, ".vob", 4) ) {
208         /* Got a title */
209         if( atol(&new_filename->d_name[7]) > 0 ) {
210           joinpath(title_path, directory, new_filename->d_name);
211           demuxer_t::title_t *title = new demuxer_t::title_t(zsrc, title_path);
212           demux->titles[demux->total_titles++] = title;
213 //zmsgs("title_path=%s\n", title_path);
214         }
215       }
216     }
217   }
218   closedir(dirstream);
219
220   int done = 0;
221   while( !done ) {
222     done = 1;
223     for( int i=1; i<demux->total_titles; ++i ) {
224       char *i0 = demux->titles[i-0]->fs->path;
225       char *i1 = demux->titles[i-1]->fs->path;
226       if( strcmp(i1, i0) > 0 ) {
227         ztitle_t *title = demux->titles[i-0];
228         demux->titles[i-0] = demux->titles[i-1];
229         demux->titles[i-1] = title;
230         done = 0;
231       }
232     }
233   }
234
235   int64_t total_bytes = 0;
236   for( int i=0; i<demux->total_titles; ++i ) {
237     ztitle_t *title = demux->titles[i-0];
238     title->total_bytes = path_total_bytes(title->fs->path);
239     title->start_byte = total_bytes;
240     title->end_byte = total_bytes + title->total_bytes;
241     total_bytes += title->total_bytes;
242   }
243 }
244
245 /* major kludge, but some dvds have very damaged data */
246 #define TEST_START 0x1000000
247 #define TEST_LEN   0x1000000
248
249 void zifo_t::
250 get_header(zdemuxer_t *demux)
251 {
252   int i;
253   /* Video header */
254   demux->vstream_table[0] = 1;
255   demux->open_title(0);
256
257   if( empirical ) {
258     demux->seek_byte(TEST_START);
259     demux->read_all = 1;
260     int result = 0;
261     while( !result && !demux->eof() &&
262            demux->tell_byte() < TEST_START+TEST_LEN ) {
263       result = demux->read_next_packet();
264     }
265     demux->seek_byte(0);
266     demux->read_all = 0;
267   }
268   else {
269     /* Audio header */
270     if( !type_vts() ) {
271       int atracks = nr_of_vts_audio_streams();
272       if( atracks > 0 ) {
273         for( i=0; i<atracks; ++i ) {
274           uint8_t *audio_attr = vts_audio_attr(i);
275           int audio_mode = afmt_IGNORE;
276           switch( aud_audio_format(audio_attr) ) {
277           case 0:  audio_mode = afmt_AC3;   break;
278           case 1:  audio_mode = afmt_MPEG;  break;
279           case 2:  audio_mode = afmt_MPEG;  break;
280           case 3:  audio_mode = afmt_PCM;   break;
281           }
282           if( !demux->astream_table[i+0x80] )
283             demux->astream_table[i+0x80] = audio_mode;
284         }
285       }
286     }
287     else if( !type_vmg() ) {
288       int atracks = nr_of_vmgm_audio_streams();
289       if( atracks > 1 ) zerr("too many atracks for vmgm header\n");
290       if( atracks > 0 ) {
291         uint8_t *audio_attr = vmgm_audio_attr();
292         int audio_mode = afmt_IGNORE;
293         switch( aud_audio_format(audio_attr) ) {
294         case 0:  audio_mode = afmt_AC3;   break;
295         case 1:  audio_mode = afmt_MPEG;  break;
296         case 2:  audio_mode = afmt_MPEG;  break;
297         case 3:  audio_mode = afmt_PCM;   break;
298         }
299         if( !demux->astream_table[0x80] )
300           demux->astream_table[0x80] = audio_mode;
301       }
302     }
303     /* subtitle header */
304     if( !type_vts() ) {
305       int stracks = nr_of_vts_subp_streams();
306       if( stracks > 0 ) {
307         for( i=0; i<stracks; ++i )
308           demux->sstream_table[i] = 1;
309       }
310     }
311     else if( !type_vmg() ) {
312       int stracks = nr_of_vmgm_subp_streams();
313       if( stracks > 1 ) zerr("too many stracks for vmgm header\n");
314       if( stracks > 0 ) {
315         demux->sstream_table[0] = 1;
316       }
317     }
318   }
319 }
320
321 zicell_t* zicell_table_t::
322 append_cell()
323 {
324   if( !cells || total_cells >= cells_allocated ) {
325     int new_allocation = ZMAX(cells_allocated*2, 64);
326     icell_t *new_cells = new icell_t[new_allocation];
327     for( int i=0; i<total_cells; ++i )
328       new_cells[i] = cells[i];
329     delete [] cells;
330     cells = new_cells;
331     cells_allocated = new_allocation;
332   }
333   return &cells[total_cells++];
334 }
335
336 zicell_table_t::
337 ~icell_table_t()
338 {
339   if( cells ) delete [] cells;
340 }
341
342 void zifo_t::
343 get_playinfo(zmpeg3_t *zsrc, icell_table_t *icell_addrs)
344 {
345   icell_table_t *pcells = new icell_table_t();
346   if( zsrc->playinfo ) delete zsrc->playinfo;
347   zsrc->playinfo = pcells;
348   int total_pcells = nr_of_cells();
349   int cur_angle = -1;
350   double cur_time = 0.;
351 //zmsgs("total_pcells %d\n", total_pcells);
352
353   for( int pcell_no=0; pcell_no<total_pcells; ++pcell_no ) {
354     use_playback(pcell_no);
355     int phr = bcd(cell_playback_time()[0]);
356     int pmn = bcd(cell_playback_time()[1]);
357     int psc = bcd(cell_playback_time()[2]);
358     int pfm = bcd(cell_playback_time()[3] & 0x3f);
359     int prt = cell_playback_time()[3] >> 6;
360 #if 0
361 zmsgs(" cell: %d\n"
362   "   blk_ty %u, seemless %u, interlv %u, discon %u, angle %u @secs %f\n"
363   "   mode %u, restrict %u, still %u, cmd_nr %u, ptime %02u:%02u:%02u.%02u %5.5s\n"
364   "   1st sect %jx, end sect %jx, start sect %jx, last sect %jx\n",
365   pcell_no+1,
366   cell_block_type(), cell_seamless_play(), cell_interleaved(),
367   cell_stc_discontinuity(), cell_seamless_angle(), cur_time,
368   cell_playback_mode(), cell_restricted(), cell_still_time(),
369   cell_cmd_nr(), phr, pmn, psc, pfm, &"0.0  25.00     29.97"[5*prt],
370   cell_first_sector()*DVD_VIDEO_LB_LEN,
371   cell_first_ilvu_end_sector()*DVD_VIDEO_LB_LEN,
372   cell_last_vobu_start_sector()*DVD_VIDEO_LB_LEN,
373   cell_last_sector()*DVD_VIDEO_LB_LEN);
374 #endif
375     icell_t *pcell = pcells->append_cell();
376     pcell->start_byte = cell_first_sector()*DVD_VIDEO_LB_LEN;
377     pcell->end_byte = (cell_last_sector()+1)*DVD_VIDEO_LB_LEN;
378     pcell->discon = cell_stc_discontinuity();
379     pcell->inlv = cell_interleaved();
380     if( cell_block_type() == BTY_ANGLE ) {
381       switch( cell_block_mode() ) {
382       case BMD_FIRST_CELL: cur_angle=0; break;
383       case BMD_IN_BLOCK:
384       case BMD_LAST_CELL:  ++cur_angle; break;
385       }
386     }
387     else
388       cur_angle = -1;
389     pcell->angle = cur_angle;
390     if( !pcell->inlv || cur_angle == 0 )
391       cur_time += phr*3600 + pmn*60 + psc + pfm/(prt==1 ? 25.0 : 29.97);
392     use_position(pcell_no);
393     pcell->vob_id = vob_id_nr();
394     pcell->cell_id = cell_id_nr();
395 //zmsgs(" %3d vob/cell %d/%d  start: %jx end: %jx discon %d inlv/ang %d/%d\n",
396 //  pcell_no+1, pcell->vob_id, pcell->cell_id,
397 //  pcell->start_byte, pcell->end_byte, pcell->discon, pcell->inlv,pcell->angle);
398   }
399 }
400
401 void zifo_t::
402 icell_addresses(zicell_table_t *icell_addrs)
403 {
404   int i, j;
405 //zmsg("icell_addresses\n");
406   int length = cadr_length();
407 //zmsgs("icells length %d\n",length);
408
409   for( i=0; i<length; ++i ) {
410     use_cell(i);
411     icell_t *cell = icell_addrs->append_cell();
412     cell->start_byte = cadr_start_sector() * DVD_VIDEO_LB_LEN;
413     cell->end_byte = (cadr_last_sector()+1) * DVD_VIDEO_LB_LEN;
414     cell->vob_id = cadr_vob_id();
415     cell->cell_id = cadr_cell_id();
416     cell->discon = i;
417     cell->inlv = 0;
418     cell->angle = 0;
419 //zmsgs("cell %d, vob_id %u, cell_id %u, start %lu/%lx, last %lu/%lx\n",
420 //  i, cell->vob_id, cell->cell_id, cell->start_byte, cell->start_byte,
421 //  cell->end_byte, cell->end_byte);
422   }
423
424   int total_icells = icell_addrs->total_cells;
425   icell_t *icells[total_icells];
426   for( i=total_icells; --i>=0; ) icells[i] = &icell_addrs->cells[i];
427
428 // Sort addresses by addr/vob_id/cell_id instead of vob id
429   int done = 0;
430   while( !done ) {
431     done = 1;
432     for( i=1; i<total_icells; ++i ) {
433       icell_t *icell0 = icells[i-0];
434       icell_t *icell1 = icells[i-1];
435       // key addr/vob_no/cell_id
436       if( icell1->start_byte > icell0->start_byte ||
437          (icell1->start_byte == icell0->start_byte &&
438           (icell1->vob_id > icell0->vob_id ||
439            (icell1->vob_id == icell0->vob_id &&
440             icell1->cell_id > icell0->cell_id))) ) {
441         icells[i-0] = icell1;
442         icells[i-1] = icell0;
443         done = 0;
444       }
445     }
446   }
447
448 #if 0
449   int cur_vobid = 0x10000;
450   /* label interleave */
451   for( i=total_icells; --i>=0; ) {
452     icell_t *icell = icells[i];
453     int cur_inlv = icell->vob_id - cur_vobid;
454     /* Reduce current vobid */
455     if( cur_inlv < 0 ) {
456       cur_vobid = icell->vob_id;
457       cur_inlv = 0;
458     }
459     icell->inlv = cur_inlv;
460     if( max_inlv < cur_inlv )
461       max_inlv = cur_inlv;
462     if( cur_inlv > 0 ) {
463       int cell_id = icell->cell_id;
464       /* Get the last interleave by brute force */
465       for( j=i+1; j<total_icells && cell_id==icells[j]->cell_id; ++j ) {
466         int inlv = icells[j]->vob_id - cur_vobid;
467         if( inlv > cur_inlv ) continue;
468         icells[j]->inlv = inlv;
469       }
470     }
471     else if( cur_inlv == 0 ) {
472       int64_t start_byte = icells[i]->start_byte;
473       for( j=i+1; j<total_icells && start_byte==icells[j]->start_byte; ++j )
474         icells[j]->inlv = j-i;
475     }
476   }
477
478   /* convert int labels to bit vector */
479   i = 0;
480   while( i < total_icells ) {
481     j = i;
482     int64_t start_byte = icells[j]->start_byte;
483     uint32_t inlv = 1 << icells[j]->inlv;
484     while( ++j<total_icells && start_byte==icells[j]->start_byte )
485       inlv |= 1 << icells[j]->inlv;
486     while( i < j ) icells[i++]->inlv = inlv;
487   }
488
489 #else
490   int istart = -1, istop = -1;
491 // Assign interleave:
492 //  there are 2 cases,
493 //    interleave is known, using vob_id offset,
494 //    interleave is unknown, cell may be in any program
495 //  unsorted vob_ids:   1111122233
496 //    sorted vob_ids:   1112121233
497 //  equal start_byte:   ***xxxx***
498 //        interleave:   xx010101xx
499   i = 0;
500   while( i < total_icells ) {
501     istart = i;
502     int cur_vob_id = icells[istart]->vob_id;
503     while( ++i < total_icells ) {
504       if( icells[i]->vob_id > cur_vob_id ) {
505         if( icells[i]->start_byte == icell_addrs->cells[i].start_byte ) break;
506         cur_vob_id = icells[i]->vob_id;
507       }
508     }
509     istop = i;
510     if( istop == istart+1 ) {
511       icells[istart]->inlv = ~0;
512       continue;
513     }
514     int min_vob_id = icells[istart]->vob_id;
515     int cur_inlv = cur_vob_id - min_vob_id;
516     if( cur_inlv > max_inlv ) max_inlv = cur_inlv;
517     int inlv = 0;
518     j = istart;
519     while( j < istop ) {
520       int64_t start_byte = icells[j]->start_byte;
521       if( j+1 < istop && icells[j+1]->start_byte == start_byte ) {
522         inlv = -1;
523         while( j < istop && icells[j]->start_byte == start_byte )
524           icells[j++]->inlv = ~0;
525       }
526       else {
527         int k = icells[j]->vob_id - min_vob_id;
528         if( inlv >= 0 && k != inlv )
529           zerrs("bolixed: j %d, inlv %d, k %d\n", j, inlv, k);
530         icells[j++]->inlv = 1 << k;
531         inlv = k;
532         if( ++inlv > cur_inlv ) inlv = 0;
533       }
534     }
535     if( inlv > 0 ) {
536       zerrs("bungled: istart %d, istop %d, cur_inlv %d\n",
537         istart, istop, cur_inlv);
538     }
539   }
540 #endif
541
542 #if 0
543 zmsgs("sorted labeled icells %d\n",total_icells);
544   for( i=0; i<total_icells; ++i ) {
545     icell_t *cell = icells[i];
546     zmsgs("cell %d, vob_id %u, cell_id %u, start %jx, last %jx inlv %04x\n",
547       i, cell->vob_id, cell->cell_id, cell->start_byte, cell->end_byte, cell->inlv);
548   }
549 #endif
550 }
551
552 static int pcmpr(const void *ap, const void *bp)
553 {
554   zicell_t *a = *(zicell_t**)ap, *b = *(zicell_t**)bp;
555   int v = a->vob_id - b->vob_id;
556   if( !v ) v = a->cell_id - b->cell_id;
557   return v;
558 }
559
560 void zifo_t::
561 icell_map(zmpeg3_t *zsrc, icell_table_t *icell_addrs)
562 {
563   int inlv = zsrc->interleave;
564   int angle = zsrc->angle;
565   demuxer_t *demuxer = zsrc->demuxer;
566   int64_t program_start = 0;
567   int discon = 0;
568   int total_icells = icell_addrs->total_cells;
569   icell_t *icells = &icell_addrs->cells[0];
570   int total_pcells = zsrc->playinfo->total_cells;
571   icell_t *pcells[total_pcells];
572   for( int i=0; i<total_pcells; ++i ) pcells[i] = &zsrc->playinfo->cells[i];
573   qsort(pcells, total_pcells, sizeof(pcells[0]), pcmpr);
574
575   for( int i=0; i<total_pcells; ++i ) {
576     icell_t *pcell = pcells[i];
577     int pcell_no = pcell - zsrc->playinfo->cells;
578     if( pcell->angle >= 0 && pcell->angle != angle ) continue;
579     int icell_no, pgm = pcell->angle >= 0 ? angle : inlv;
580     icell_t *cell = 0;
581     for( icell_no=0; icell_no<total_icells; ++icell_no ) {
582       cell = &icells[icell_no];
583       if( pcell->inlv && !cell->has_inlv(pgm) ) continue;
584       if( cell->vob_id != pcell->vob_id ) continue;
585       if( cell->cell_id == pcell->cell_id ) break;
586     }
587     if( !cell || icell_no >= total_icells ) {
588       zerrs("vob/cell %d/%d missed in icells\n", pcell->vob_id, pcell->cell_id);
589       continue;
590     }
591
592     if( current_vob_id != cell->vob_id ) {
593       current_vob_id = cell->vob_id;
594       // -1 resets pts to 0, 1 is just discontinuity
595       // discon = cell->cell_id == 1 ? -1 : 1;
596       discon = 1;
597     }
598     else if( pcell->discon )
599       discon = 1;
600
601     while( icell_no < total_icells ) {
602       cell = &icells[icell_no++];
603       if( pcell->inlv && !cell->has_inlv(pgm) ) continue;
604       if( cell->vob_id != pcell->vob_id ) break;
605       if( cell->cell_id != pcell->cell_id ) break;
606       if( cell->start_byte >= pcell->end_byte ) continue;
607       if( cell->end_byte <= pcell->start_byte ) continue;
608       int64_t start_byte = cell->start_byte;
609       if( start_byte < pcell->start_byte )
610         start_byte = pcell->start_byte;
611       int64_t end_byte = cell->end_byte;
612       if( end_byte > pcell->end_byte )
613         end_byte = pcell->end_byte;
614
615       int64_t length = end_byte - start_byte;
616       while( length > 0 ) {
617         /* Cell may be split by a title so handle in fragments. */
618         int title_no;
619         for( title_no=0; title_no<demuxer->total_titles; ++title_no )
620           if( demuxer->titles[title_no]->end_byte > start_byte ) break;
621         if( title_no >= demuxer->total_titles ) {
622           zerrs("cell map past titles %jx\n", start_byte);
623           break;
624         }
625         ztitle_t *title = demuxer->titles[title_no];
626         int64_t cell_size = length;
627         /* Clamp length to current title */
628         if( start_byte+length > title->end_byte )
629           cell_size = title->end_byte - start_byte;
630         int64_t title_start = start_byte - title->start_byte;
631         int64_t title_end = title_start + cell_size;
632         int64_t program_end = program_start + cell_size;
633 //zmsgs("  %d/%d. title/cell: %d/%-2d, vob/cell: %2d/%-2d,  title 0x%012lx-0x%012lx, "
634 //      " program 0x%012lx-0x%012lx discon %d\n",
635 //  pcell_no+1, icell_no, title_no, title->cell_table_size, cell->vob_id, cell->cell_id,
636 //  title_start, title_end, program_start, program_end, discon);
637         title->new_cell(pcell_no, title_start, title_end,
638                         program_start, program_end, discon);
639         discon = 0;
640         start_byte += cell_size;
641         program_start += cell_size;
642         length -= cell_size;
643       }
644
645       current_byte = end_byte;
646     }
647   }
648 }
649
650 void zifo_t::
651 get_ititle(zmpeg3_t *zsrc, int chapter)
652 {
653   int title = zsrc->vts_title;
654   use_ptt_info(title);
655   int program_chain = ptt_pgcn(chapter);
656   use_program_chain(program_chain-1);
657 }
658
659 /* Read the title information from an ifo */
660 int zmpeg3_t::
661 read_ifo()
662 {
663   ifo_t *ifo;
664   icell_table_t icell_addrs;
665   int result = 0;
666
667   int fd = fs->get_fd();
668   if( (ifo = ifo_open(fd, 0)) == 0 ) {
669     zerr("Error opening ifo.\n");
670     result = 1;
671   }
672   if( !result ) {
673     ifo->get_playlist(this);
674     if( !demuxer->total_titles ) {
675       zerr("Error no titles in ifo.\n");
676       result = 1;
677     }
678   }
679   if( !result ) {
680     total_vts_titles = ifo->nr_of_titles();
681     if( vts_title >= total_vts_titles ) {
682       zerrs("Error only %d titles in ifo, req %d\n",
683         total_vts_titles, vts_title);
684       result = 1;
685     }
686   }
687   if( !result ) {
688     ifo->get_header(demuxer);
689     ifo->get_ititle(this);
690     ifo->get_palette(this);
691     ifo->icell_addresses(&icell_addrs);
692     total_interleaves = ifo->max_inlv + 1;
693     if( interleave >= total_interleaves ) {
694       zerrs("Error only %d interleaves in ifo, req %d\n",
695         total_interleaves, interleave);
696       result = 1;
697     }
698   }
699   if( !result ) {
700     ifo->get_playinfo(this, &icell_addrs);
701     ifo->icell_map(this, &icell_addrs);
702   }
703
704   if( ifo ) ifo->ifo_close();
705   return result;
706 }
707
708 /* This is not useful, since title is based on the vgm tt_srpt table */
709 /*   and that table is not normally read.  written for testing purposes. */
710 /*   the orignal plan was to be able to put keyframe markers at chapters */
711 int64_t zifo_t::ifo_chapter_cell_time(zmpeg3_t *zsrc, int chapter)
712 {
713   double result = -1;
714   int title = zsrc->vts_title;
715   if( chapter >= 0 && chapter < (int)nr_of_chapters(title) ) {
716     get_ititle(zsrc, chapter);
717     int pgn = ptt_pgn(chapter);
718     uint8_t *pmap = pgc_program_map();
719     int cell_id = pmap[pgn-1] - 1;
720     int n = zsrc->playinfo->total_cells;
721     int i = 0;
722     while( i < n ) {
723       if( zsrc->playinfo->cells[i].cell_id == cell_id ) break;
724       ++i;
725     }
726     if( i < n ) {
727       use_playback(i);
728       result = cell_first_sector() * DVD_VIDEO_LB_LEN;
729     }
730   }
731   return result;
732 }
733
734 /* check playcells */
735 int zifo_t::
736 chk(int vts_title, int chapter, int inlv, int angle,
737     icell_table_t *icell_addrs, int &sectors, int &pcells, int &max_angle)
738 {
739   if( type_vts() ) return -1;
740   if( vts_title >= (int)nr_of_titles() ) return -1;
741   if( chapter >= (int)nr_of_chapters(vts_title) ) return 0;
742   use_ptt_info(vts_title);
743   int program_chain = ptt_pgcn(chapter);
744   use_program_chain(program_chain-1);
745   int total_pcells = nr_of_cells();
746   if( total_pcells <= 0 ) return 0;
747   int pgn = ptt_pgn(chapter);
748   uint8_t *pmap = pgc_program_map();
749   int pcell_no = pmap[pgn-1] - 1;
750   use_playback(pcell_no);
751   uint32_t current_sector = cell_first_sector();
752   int count = 0;
753
754   int total_icells = icell_addrs->total_cells;
755   icell_t *icells = &icell_addrs->cells[0];
756   int last_vob_id = 0;
757   int last_cell_id = 0;
758   max_angle = -1;
759   int cur_angle = -1;
760
761   for( int pcell_no=0; pcell_no<total_pcells; ++pcell_no ) {
762     // vob/cell id keys, must be increasing
763     use_position(pcell_no);
764     int vob_id = vob_id_nr();
765     int cell_id = cell_id_nr();
766     if( vob_id != last_vob_id )
767       last_vob_id = vob_id;
768     else if( cell_id < last_cell_id )
769       return 0;
770     last_cell_id = cell_id;
771
772     use_playback(pcell_no);
773     int interleaved = cell_interleaved();
774     int pgm = inlv;
775     if( cell_block_type() == BTY_ANGLE ) {
776       switch( cell_block_mode() ) {
777       case BMD_FIRST_CELL: cur_angle=0;  break;
778       case BMD_IN_BLOCK:
779       case BMD_LAST_CELL:  ++cur_angle;  break;
780       }
781       if( cur_angle > max_angle ) max_angle = cur_angle;
782       if( cur_angle != angle ) continue;
783       pgm = cur_angle;
784     }
785     else
786       cur_angle = -1;
787     // vob/cell/interleave must be in map
788     icell_t *cell = 0;
789     int icell_no;
790     for( icell_no=0; icell_no<total_icells; ++icell_no ) {
791       cell = &icells[icell_no];
792       if( interleaved && !cell->has_inlv(pgm) ) continue;
793       if( cell->vob_id != vob_id ) continue;
794       if( cell->cell_id == cell_id ) break;
795     }
796     if( !cell || icell_no >= total_icells ) return 0;
797
798     // check sectors, must be increasing
799     uint32_t first_sector = cell_first_sector();
800     if( first_sector && current_sector > first_sector ) return 0;
801     uint32_t last_sector1 = cell_last_sector()+1;
802     count += last_sector1 - first_sector;
803     current_sector = last_sector1;
804
805     // pcell must overlap cell
806     if( first_sector*DVD_VIDEO_LB_LEN >= cell->end_byte ) return 0;
807     if( cell->start_byte >= last_sector1*DVD_VIDEO_LB_LEN ) return 0;
808   }
809
810   sectors = count;
811   pcells = total_pcells;
812
813   return 1;
814 }
815