3 #if defined(__x86_64__)
4 #define DVD_VIDEO_LB_LEN 2048L
6 #define DVD_VIDEO_LB_LEN 2048LL
10 ifo_read(long pos, long count, uint8_t *data)
15 ret = lseek(fd, pos, SEEK_SET);
22 ret = read(fd, data, count);
25 zerr("unable to read ifo\n");
28 if( errno != EAGAIN ) {
43 get_table(int64_t offset, unsigned long tbl_id)
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;
53 case id_TITLE_VOBU_ADDR_MAP:
54 case id_MENU_VOBU_ADDR_MAP:
55 len = get4bytes(zdata) + 1;
59 len = hdr_length(zdata);
62 int ilen = len - DVD_VIDEO_LB_LEN;
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);
69 ipos += DVD_VIDEO_LB_LEN;
70 ret = ifo_read(ipos, ilen, zdata+DVD_VIDEO_LB_LEN);
71 if( ret < 0 ) return -1;
76 if( tbl_id == id_TMT ) {
77 uint32_t *ptr = (uint32_t*)zdata;
79 for( int i=0; i < len; ++i )
80 ptr[i] = bswap_32(ptr[i]);
87 ifo_t(int zfd, long zpos)
91 char *cp = getenv("IFO_STREAM_PROBE");
92 if( cp ) empirical = atoi(cp);
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];
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);
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 )
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 )
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;
146 ifo_open(int fd, long pos)
148 ifo_t *ifo = new ifo_t(fd,pos);
149 if( ifo->read_mat() || ifo->init_tables() ) {
164 get_palette(zmpeg3_t *zsrc)
166 if( !zsrc->have_palette ) {
167 /* subtitle color palette */
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];
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);
181 zsrc->have_palette = 1;
186 get_playlist(zmpeg3_t *zsrc)
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;
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);
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) ) {
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);
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;
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;
245 /* major kludge, but some dvds have very damaged data */
246 #define TEST_START 0x1000000
247 #define TEST_LEN 0x1000000
250 get_header(zdemuxer_t *demux)
254 demux->vstream_table[0] = 1;
255 demux->open_title(0);
258 demux->seek_byte(TEST_START);
261 while( !result && !demux->eof() &&
262 demux->tell_byte() < TEST_START+TEST_LEN ) {
263 result = demux->read_next_packet();
271 int atracks = nr_of_vts_audio_streams();
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;
282 if( !demux->astream_table[i+0x80] )
283 demux->astream_table[i+0x80] = audio_mode;
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");
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;
299 if( !demux->astream_table[0x80] )
300 demux->astream_table[0x80] = audio_mode;
303 /* subtitle header */
305 int stracks = nr_of_vts_subp_streams();
307 for( i=0; i<stracks; ++i )
308 demux->sstream_table[i] = 1;
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");
315 demux->sstream_table[0] = 1;
321 zicell_t* zicell_table_t::
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];
331 cells_allocated = new_allocation;
333 return &cells[total_cells++];
339 if( cells ) delete [] cells;
343 get_playinfo(zmpeg3_t *zsrc, icell_table_t *icell_addrs)
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();
350 double cur_time = 0.;
351 //zmsgs("total_pcells %d\n", total_pcells);
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;
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",
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);
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;
384 case BMD_LAST_CELL: ++cur_angle; break;
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);
402 icell_addresses(zicell_table_t *icell_addrs)
405 //zmsg("icell_addresses\n");
406 int length = cadr_length();
407 //zmsgs("icells length %d\n",length);
409 for( i=0; i<length; ++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();
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);
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];
428 // Sort addresses by addr/vob_id/cell_id instead of vob id
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;
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 */
456 cur_vobid = icell->vob_id;
459 icell->inlv = cur_inlv;
460 if( max_inlv < cur_inlv )
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;
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;
478 /* convert int labels to bit vector */
480 while( i < total_icells ) {
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;
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
500 while( i < total_icells ) {
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;
510 if( istop == istart+1 ) {
511 icells[istart]->inlv = ~0;
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;
520 int64_t start_byte = icells[j]->start_byte;
521 if( j+1 < istop && icells[j+1]->start_byte == start_byte ) {
523 while( j < istop && icells[j]->start_byte == start_byte )
524 icells[j++]->inlv = ~0;
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;
532 if( ++inlv > cur_inlv ) inlv = 0;
536 zerrs("bungled: istart %d, istop %d, cur_inlv %d\n",
537 istart, istop, cur_inlv);
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);
552 static int pcmpr(const void *ap, const void *bp)
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;
561 icell_map(zmpeg3_t *zsrc, icell_table_t *icell_addrs)
563 int inlv = zsrc->interleave;
564 int angle = zsrc->angle;
565 demuxer_t *demuxer = zsrc->demuxer;
566 int64_t program_start = 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);
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;
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;
587 if( !cell || icell_no >= total_icells ) {
588 zerrs("vob/cell %d/%d missed in icells\n", pcell->vob_id, pcell->cell_id);
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;
598 else if( pcell->discon )
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;
615 int64_t length = end_byte - start_byte;
616 while( length > 0 ) {
617 /* Cell may be split by a title so handle in fragments. */
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);
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);
640 start_byte += cell_size;
641 program_start += cell_size;
645 current_byte = end_byte;
651 get_ititle(zmpeg3_t *zsrc, int chapter)
653 int title = zsrc->vts_title;
655 int program_chain = ptt_pgcn(chapter);
656 use_program_chain(program_chain-1);
659 /* Read the title information from an ifo */
664 icell_table_t icell_addrs;
667 int fd = fs->get_fd();
668 if( (ifo = ifo_open(fd, 0)) == 0 ) {
669 zerr("Error opening ifo.\n");
673 ifo->get_playlist(this);
674 if( !demuxer->total_titles ) {
675 zerr("Error no titles in ifo.\n");
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);
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);
700 ifo->get_playinfo(this, &icell_addrs);
701 ifo->icell_map(this, &icell_addrs);
704 if( ifo ) ifo->ifo_close();
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)
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;
723 if( zsrc->playinfo->cells[i].cell_id == cell_id ) break;
728 result = cell_first_sector() * DVD_VIDEO_LB_LEN;
734 /* check playcells */
736 chk(int vts_title, int chapter, int inlv, int angle,
737 icell_table_t *icell_addrs, int §ors, int &pcells, int &max_angle)
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();
754 int total_icells = icell_addrs->total_cells;
755 icell_t *icells = &icell_addrs->cells[0];
757 int last_cell_id = 0;
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 )
770 last_cell_id = cell_id;
772 use_playback(pcell_no);
773 int interleaved = cell_interleaved();
775 if( cell_block_type() == BTY_ANGLE ) {
776 switch( cell_block_mode() ) {
777 case BMD_FIRST_CELL: cur_angle=0; break;
779 case BMD_LAST_CELL: ++cur_angle; break;
781 if( cur_angle > max_angle ) max_angle = cur_angle;
782 if( cur_angle != angle ) continue;
787 // vob/cell/interleave must be in map
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;
796 if( !cell || icell_no >= total_icells ) return 0;
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;
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;
811 pcells = total_pcells;