00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 #include <inttypes.h>
00033 #include <limits.h>
00034 #include <assert.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <sys/time.h>
00038 #include <fcntl.h>
00039
00040 #include <dvdread/nav_types.h>
00041 #include <dvdread/ifo_types.h>
00042 #include <dvdread/ifo_read.h>
00043 #include "dvdnav/dvdnav.h"
00044
00045 #include "decoder.h"
00046 #include "remap.h"
00047 #include "vm.h"
00048 #include "dvdnav_internal.h"
00049
00050 #ifdef _MSC_VER
00051 #include <io.h>
00052 #endif
00053
00054 #ifdef __OS2__
00055 #define INCL_DOS
00056 #include <os2.h>
00057 #include <io.h>
00058 #include <fcntl.h>
00059 #endif
00060
00061 #include "mythiowrapper.h"
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 static link_t play_PGC(vm_t *vm);
00076 static link_t play_PGC_PG(vm_t *vm, int pgN);
00077 static link_t play_PGC_post(vm_t *vm);
00078 static link_t play_PG(vm_t *vm);
00079 static link_t play_Cell(vm_t *vm);
00080 static link_t play_Cell_post(vm_t *vm);
00081
00082
00083 static int process_command(vm_t *vm,link_t link_values);
00084
00085
00086 static int set_TT(vm_t *vm, int tt);
00087 static int set_PTT(vm_t *vm, int tt, int ptt);
00088 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn);
00089 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part);
00090 static int set_PROG(vm_t *vm, int tt, int pgcn, int pgn);
00091 static int set_VTS_PROG(vm_t *vm, int vtsN, int vts_ttn, int pgcn, int pgn);
00092 static int set_FP_PGC(vm_t *vm);
00093 static int set_MENU(vm_t *vm, int menu);
00094 static int set_PGCN(vm_t *vm, int pgcN);
00095 static int set_PGN(vm_t *vm);
00096 static void set_RSMinfo(vm_t *vm, int cellN, int blockN);
00097
00098
00099 static int get_TT(vm_t *vm, int vtsN, int vts_ttn);
00100 static int get_ID(vm_t *vm, int id);
00101 static int get_PGCN(vm_t *vm);
00102
00103 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang);
00104 static pgcit_t* get_PGCIT(vm_t *vm);
00105
00106
00107
00108
00109 #ifdef TRACE
00110 static void vm_print_current_domain_state(vm_t *vm) {
00111 switch((vm->state).domain) {
00112 case VTS_DOMAIN:
00113 fprintf(MSG_OUT, "libdvdnav: Video Title Domain: -\n");
00114 break;
00115
00116 case VTSM_DOMAIN:
00117 fprintf(MSG_OUT, "libdvdnav: Video Title Menu Domain: -\n");
00118 break;
00119
00120 case VMGM_DOMAIN:
00121 fprintf(MSG_OUT, "libdvdnav: Video Manager Menu Domain: -\n");
00122 break;
00123
00124 case FP_DOMAIN:
00125 fprintf(MSG_OUT, "libdvdnav: First Play Domain: -\n");
00126 break;
00127
00128 default:
00129 fprintf(MSG_OUT, "libdvdnav: Unknown Domain: -\n");
00130 break;
00131 }
00132 fprintf(MSG_OUT, "libdvdnav: VTS:%d PGC:%d PG:%u CELL:%u BLOCK:%u VTS_TTN:%u TTN:%u TT_PGCN:%u\n",
00133 (vm->state).vtsN,
00134 get_PGCN(vm),
00135 (vm->state).pgN,
00136 (vm->state).cellN,
00137 (vm->state).blockN,
00138 (vm->state).VTS_TTN_REG,
00139 (vm->state).TTN_REG,
00140 (vm->state).TT_PGCN_REG);
00141 }
00142 #endif
00143
00144 #ifdef __OS2__
00145 #define open os2_open
00146
00147 static int os2_open(const char *name, int oflag)
00148 {
00149 HFILE hfile;
00150 ULONG ulAction;
00151 ULONG rc;
00152
00153 rc = DosOpenL(name, &hfile, &ulAction, 0, FILE_NORMAL,
00154 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
00155 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_DASD,
00156 NULL);
00157
00158 if(rc)
00159 return -1;
00160
00161 setmode(hfile, O_BINARY);
00162
00163 return (int)hfile;
00164 }
00165 #endif
00166
00167 static void dvd_read_name(char *name, char *serial, const char *device) {
00168
00169
00170
00171 off_t off;
00172 int fd, i;
00173 uint8_t data[DVD_VIDEO_LB_LEN];
00174
00175
00176 fd = mythfile_open(device, O_RDONLY);
00177 if (fd > 0) {
00178 off = mythfile_seek( fd, 32 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET );
00179 if( off == ( 32 * (off_t) DVD_VIDEO_LB_LEN ) ) {
00180 off = mythfile_read( fd, data, DVD_VIDEO_LB_LEN );
00181 if (off == ( (off_t) DVD_VIDEO_LB_LEN )) {
00182 fprintf(MSG_OUT, "libdvdnav: DVD Title: ");
00183 for(i=25; i < 73; i++ ) {
00184 if((data[i] == 0)) break;
00185 if((data[i] > 32) && (data[i] < 127)) {
00186 fprintf(MSG_OUT, "%c", data[i]);
00187 } else {
00188 fprintf(MSG_OUT, " ");
00189 }
00190 }
00191 strncpy(name, (char*) &data[25], 48);
00192 name[48] = 0;
00193 fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: ");
00194 for(i=73; i < 89; i++ ) {
00195 if((data[i] == 0)) break;
00196 if((data[i] > 32) && (data[i] < 127)) {
00197 fprintf(MSG_OUT, "%c", data[i]);
00198 } else {
00199 fprintf(MSG_OUT, " ");
00200 }
00201 }
00202 strncpy(serial, (char*) &data[73], (i-73));
00203 serial[14] = 0;
00204 fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): ");
00205 for(i=89; i < 128; i++ ) {
00206 if((data[i] == 0)) break;
00207 if((data[i] > 32) && (data[i] < 127)) {
00208 fprintf(MSG_OUT, "%c", data[i]);
00209 } else {
00210 fprintf(MSG_OUT, " ");
00211 }
00212 }
00213 fprintf(MSG_OUT, "\n");
00214 } else {
00215 fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a DVD-ROM device.\n");
00216 }
00217 } else {
00218 fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 );
00219 }
00220 mythfile_close(fd);
00221 } else {
00222 fprintf(MSG_OUT, "NAME OPEN FAILED\n");
00223 }
00224 }
00225
00226 static int ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) {
00227 if((vm->state).vtsN == vtsN) {
00228 return 1;
00229 }
00230
00231 if(vm->vtsi != NULL)
00232 ifoClose(vm->vtsi);
00233
00234 vm->vtsi = ifoOpenVTSI(dvd, vtsN);
00235 if(vm->vtsi == NULL) {
00236 fprintf(MSG_OUT, "libdvdnav: ifoOpenVTSI failed\n");
00237 return 0;
00238 }
00239 if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) {
00240 fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed\n");
00241 return 0;
00242 }
00243 if(!ifoRead_PGCIT(vm->vtsi)) {
00244 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed\n");
00245 return 0;
00246 }
00247 if(!ifoRead_PGCI_UT(vm->vtsi)) {
00248 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed\n");
00249 return 0;
00250 }
00251 if(!ifoRead_VOBU_ADMAP(vm->vtsi)) {
00252 fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed\n");
00253 return 0;
00254 }
00255 if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) {
00256 fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed\n");
00257 return 0;
00258 }
00259 (vm->state).vtsN = vtsN;
00260
00261 return 1;
00262 }
00263
00264
00265
00266
00267 vm_t* vm_new_vm() {
00268 return (vm_t*)calloc(sizeof(vm_t), sizeof(char));
00269 }
00270
00271 void vm_free_vm(vm_t *vm) {
00272 vm_stop(vm);
00273 free(vm);
00274 }
00275
00276
00277
00278
00279 ifo_handle_t *vm_get_vmgi(vm_t *vm) {
00280 return vm->vmgi;
00281 }
00282
00283 ifo_handle_t *vm_get_vtsi(vm_t *vm) {
00284 return vm->vtsi;
00285 }
00286
00287
00288
00289
00290 dvd_reader_t *vm_get_dvd_reader(vm_t *vm) {
00291 return vm->dvd;
00292 }
00293
00294
00295
00296
00297 int vm_start(vm_t *vm) {
00298
00299 set_FP_PGC(vm);
00300 process_command(vm, play_PGC(vm));
00301 return !vm->stopped;
00302 }
00303
00304 void vm_stop(vm_t *vm) {
00305 if(vm->vmgi) {
00306 ifoClose(vm->vmgi);
00307 vm->vmgi=NULL;
00308 }
00309 if(vm->vtsi) {
00310 ifoClose(vm->vtsi);
00311 vm->vtsi=NULL;
00312 }
00313 if(vm->dvd) {
00314 DVDClose(vm->dvd);
00315 vm->dvd=NULL;
00316 }
00317 vm->stopped = 1;
00318 }
00319
00320 int vm_reset(vm_t *vm, const char *dvdroot) {
00321
00322 memset((vm->state).registers.SPRM, 0, sizeof((vm->state).registers.SPRM));
00323 memset((vm->state).registers.GPRM, 0, sizeof((vm->state).registers.GPRM));
00324 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
00325 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
00326 memset((vm->state).registers.GPRM_time, 0, sizeof((vm->state).registers.GPRM_time));
00327 (vm->state).registers.SPRM[0] = ('e'<<8)|'n';
00328 (vm->state).AST_REG = 15;
00329 (vm->state).SPST_REG = 62;
00330 (vm->state).AGL_REG = 1;
00331 (vm->state).TTN_REG = 1;
00332 (vm->state).VTS_TTN_REG = 1;
00333
00334 (vm->state).PTTN_REG = 1;
00335 (vm->state).HL_BTNN_REG = 1 << 10;
00336 (vm->state).PTL_REG = 15;
00337 (vm->state).registers.SPRM[12] = ('U'<<8)|'S';
00338 (vm->state).registers.SPRM[16] = ('e'<<8)|'n';
00339 (vm->state).registers.SPRM[18] = ('e'<<8)|'n';
00340 (vm->state).registers.SPRM[20] = 0x1;
00341 (vm->state).registers.SPRM[14] = 0x100;
00342
00343 (vm->state).pgN = 0;
00344 (vm->state).cellN = 0;
00345 (vm->state).cell_restart = 0;
00346
00347 (vm->state).domain = FP_DOMAIN;
00348 (vm->state).rsm_vtsN = 0;
00349 (vm->state).rsm_cellN = 0;
00350 (vm->state).rsm_blockN = 0;
00351
00352 (vm->state).vtsN = -1;
00353
00354 if (vm->dvd && dvdroot) {
00355
00356 vm_stop(vm);
00357 }
00358 if (!vm->dvd) {
00359 vm->dvd = DVDOpen(dvdroot);
00360 if(!vm->dvd) {
00361 fprintf(MSG_OUT, "libdvdnav: vm: failed to open/read the DVD\n");
00362 return 0;
00363 }
00364 vm->vmgi = ifoOpenVMGI(vm->dvd);
00365 if(!vm->vmgi) {
00366 fprintf(MSG_OUT, "libdvdnav: vm: failed to read VIDEO_TS.IFO\n");
00367 return 0;
00368 }
00369 if(!ifoRead_FP_PGC(vm->vmgi)) {
00370 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_FP_PGC failed\n");
00371 return 0;
00372 }
00373 if(!ifoRead_TT_SRPT(vm->vmgi)) {
00374 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_TT_SRPT failed\n");
00375 return 0;
00376 }
00377 if(!ifoRead_PGCI_UT(vm->vmgi)) {
00378 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PGCI_UT failed\n");
00379 return 0;
00380 }
00381 if(!ifoRead_PTL_MAIT(vm->vmgi)) {
00382 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PTL_MAIT failed\n");
00383
00384 }
00385 if(!ifoRead_VTS_ATRT(vm->vmgi)) {
00386 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VTS_ATRT failed\n");
00387
00388 }
00389 if(!ifoRead_VOBU_ADMAP(vm->vmgi)) {
00390 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VOBU_ADMAP vgmi failed\n");
00391
00392 }
00393
00394 dvd_read_name(vm->dvd_name, vm->dvd_serial, dvdroot);
00395 vm->map = remap_loadmap(vm->dvd_name);
00396 }
00397 if (vm->vmgi) {
00398 int i, mask;
00399 fprintf(MSG_OUT, "libdvdnav: DVD disk reports itself with Region mask 0x%08x. Regions:",
00400 vm->vmgi->vmgi_mat->vmg_category);
00401 for (i = 1, mask = 1; i <= 8; i++, mask <<= 1)
00402 if (((vm->vmgi->vmgi_mat->vmg_category >> 16) & mask) == 0)
00403 fprintf(MSG_OUT, " %d", i);
00404 fprintf(MSG_OUT, "\n");
00405 }
00406 return 1;
00407 }
00408
00409
00410
00411
00412 vm_t *vm_new_copy(vm_t *source) {
00413 vm_t *target = vm_new_vm();
00414 int vtsN;
00415 int pgcN = get_PGCN(source);
00416 int pgN = (source->state).pgN;
00417
00418 assert(pgcN);
00419
00420 memcpy(target, source, sizeof(vm_t));
00421
00422
00423 target->vtsi = NULL;
00424 vtsN = (target->state).vtsN;
00425 if (vtsN > 0) {
00426 (target->state).vtsN = 0;
00427 if (!ifoOpenNewVTSI(target, target->dvd, vtsN))
00428 assert(0);
00429
00430
00431 if (!set_PGCN(target, pgcN))
00432 assert(0);
00433 (target->state).pgN = pgN;
00434 }
00435
00436 return target;
00437 }
00438
00439 void vm_merge(vm_t *target, vm_t *source) {
00440 if(target->vtsi)
00441 ifoClose(target->vtsi);
00442 memcpy(target, source, sizeof(vm_t));
00443 memset(source, 0, sizeof(vm_t));
00444 }
00445
00446 void vm_free_copy(vm_t *vm) {
00447 if(vm->vtsi)
00448 ifoClose(vm->vtsi);
00449 free(vm);
00450 }
00451
00452
00453
00454
00455 void vm_position_get(vm_t *vm, vm_position_t *position) {
00456 position->button = (vm->state).HL_BTNN_REG >> 10;
00457 position->vts = (vm->state).vtsN;
00458 position->domain = (vm->state).domain;
00459 position->spu_channel = (vm->state).SPST_REG;
00460 position->audio_channel = (vm->state).AST_REG;
00461 position->angle_channel = (vm->state).AGL_REG;
00462 position->hop_channel = vm->hop_channel;
00463 position->cell = (vm->state).cellN;
00464 position->cell_restart = (vm->state).cell_restart;
00465 position->cell_start = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector;
00466 position->still = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].still_time;
00467 position->block = (vm->state).blockN;
00468
00469
00470 if ((vm->state).cellN == (vm->state).pgc->nr_of_cells)
00471 position->still += (vm->state).pgc->still_time;
00472
00473 if (position->still)
00474 return;
00475
00476
00477
00478
00479
00480
00481
00482
00483 if (((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector ==
00484 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_vobu_start_sector) &&
00485 ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector -
00486 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector < 1024)) {
00487 int time;
00488 int size = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector -
00489 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector;
00490 time = ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour >> 4 ) * 36000;
00491 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour & 0x0f) * 3600;
00492 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute >> 4 ) * 600;
00493 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute & 0x0f) * 60;
00494 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second >> 4 ) * 10;
00495 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0x0f) * 1;
00496 if (!time || size / time > 30)
00497
00498 return;
00499 if (time > 0xff) time = 0xff;
00500 position->still = time;
00501 }
00502 }
00503
00504 void vm_get_next_cell(vm_t *vm) {
00505 process_command(vm, play_Cell_post(vm));
00506 }
00507
00508
00509
00510
00511 int vm_jump_pg(vm_t *vm, int pg) {
00512 (vm->state).pgN = pg;
00513 process_command(vm, play_PG(vm));
00514 return 1;
00515 }
00516
00517 int vm_jump_cell_block(vm_t *vm, int cell, int block) {
00518 (vm->state).cellN = cell;
00519 process_command(vm, play_Cell(vm));
00520
00521 if ((vm->state).cellN == cell)
00522 (vm->state).blockN = block;
00523 return 1;
00524 }
00525
00526 int vm_jump_title_program(vm_t *vm, int title, int pgcn, int pgn) {
00527 link_t link;
00528
00529 if(!set_PROG(vm, title, pgcn, pgn))
00530 return 0;
00531
00532
00533
00534
00535 link = play_PGC_PG(vm, (vm->state).pgN);
00536 if (link.command != PlayThis)
00537
00538 process_command(vm, play_PG(vm));
00539 else
00540 process_command(vm, link);
00541 return 1;
00542 }
00543
00544 int vm_jump_title_part(vm_t *vm, int title, int part) {
00545 link_t link;
00546
00547 if(!set_PTT(vm, title, part))
00548 return 0;
00549
00550
00551
00552
00553 link = play_PGC_PG(vm, (vm->state).pgN);
00554 if (link.command != PlayThis)
00555
00556 process_command(vm, play_PG(vm));
00557 else
00558 process_command(vm, link);
00559 return 1;
00560 }
00561
00562 int vm_jump_top_pg(vm_t *vm) {
00563 process_command(vm, play_PG(vm));
00564 return 1;
00565 }
00566
00567 int vm_jump_next_pg(vm_t *vm) {
00568 if((vm->state).pgN >= (vm->state).pgc->nr_of_programs) {
00569
00570 process_command(vm, play_PGC_post(vm));
00571 return 1;
00572 } else {
00573 vm_jump_pg(vm, (vm->state).pgN + 1);
00574 return 1;
00575 }
00576 }
00577
00578 int vm_jump_prev_pg(vm_t *vm) {
00579 if ((vm->state).pgN <= 1) {
00580
00581 if ((vm->state).pgc->prev_pgc_nr && set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) {
00582 process_command(vm, play_PGC(vm));
00583 vm_jump_pg(vm, (vm->state).pgc->nr_of_programs);
00584 return 1;
00585 }
00586 return 0;
00587 } else {
00588 vm_jump_pg(vm, (vm->state).pgN - 1);
00589 return 1;
00590 }
00591 }
00592
00593 int vm_jump_up(vm_t *vm) {
00594 if((vm->state).pgc->goup_pgc_nr && set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) {
00595 process_command(vm, play_PGC(vm));
00596 return 1;
00597 }
00598 return 0;
00599 }
00600
00601 int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid) {
00602 domain_t old_domain = (vm->state).domain;
00603
00604 switch ((vm->state).domain) {
00605 case VTS_DOMAIN:
00606 set_RSMinfo(vm, 0, (vm->state).blockN);
00607
00608 case VTSM_DOMAIN:
00609 case VMGM_DOMAIN:
00610 switch(menuid) {
00611 case DVD_MENU_Title:
00612 case DVD_MENU_Escape:
00613 if(vm->vmgi == NULL || vm->vmgi->pgci_ut == NULL) {
00614 return 0;
00615 }
00616 (vm->state).domain = VMGM_DOMAIN;
00617 break;
00618 case DVD_MENU_Root:
00619 case DVD_MENU_Subpicture:
00620 case DVD_MENU_Audio:
00621 case DVD_MENU_Angle:
00622 case DVD_MENU_Part:
00623 if(vm->vtsi == NULL || vm->vtsi->pgci_ut == NULL) {
00624 return 0;
00625 }
00626 (vm->state).domain = VTSM_DOMAIN;
00627 break;
00628 }
00629 if(get_PGCIT(vm) && set_MENU(vm, menuid)) {
00630 process_command(vm, play_PGC(vm));
00631 return 1;
00632 } else {
00633 (vm->state).domain = old_domain;
00634 }
00635 break;
00636 case FP_DOMAIN:
00637 break;
00638 }
00639
00640 return 0;
00641 }
00642
00643 int vm_jump_resume(vm_t *vm) {
00644 link_t link_values = { LinkRSM, 0, 0, 0 };
00645
00646 if (!(vm->state).rsm_vtsN)
00647 return 0;
00648 if (!process_command(vm, link_values))
00649 return 0;
00650 return 1;
00651 }
00652
00653 int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd) {
00654 link_t link_values;
00655
00656 if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values))
00657 return process_command(vm, link_values);
00658 else
00659 return 0;
00660 }
00661
00662
00663
00664
00665 int vm_get_current_menu(vm_t *vm, int *menuid) {
00666 pgcit_t* pgcit;
00667 int pgcn;
00668 pgcn = (vm->state).pgcN;
00669 pgcit = get_PGCIT(vm);
00670 if(pgcit==NULL) return 0;
00671 *menuid = pgcit->pgci_srp[pgcn - 1].entry_id & 0xf ;
00672 return 1;
00673 }
00674
00675 int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) {
00676 vts_ptt_srpt_t *vts_ptt_srpt;
00677 int title, part = 0, vts_ttn;
00678 int found;
00679 int16_t pgcN, pgN;
00680
00681 vts_ptt_srpt = vm->vtsi->vts_ptt_srpt;
00682 pgcN = get_PGCN(vm);
00683 pgN = vm->state.pgN;
00684
00685 found = 0;
00686 for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) {
00687 for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) {
00688 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) {
00689 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN) {
00690 found = 1;
00691 break;
00692 }
00693 if (part > 0 && vts_ptt_srpt->title[vts_ttn].ptt[part].pgn > pgN &&
00694 vts_ptt_srpt->title[vts_ttn].ptt[part - 1].pgn < pgN) {
00695 part--;
00696 found = 1;
00697 break;
00698 }
00699 }
00700 }
00701 if (found) break;
00702 }
00703 vts_ttn++;
00704 part++;
00705
00706 if (!found) {
00707 fprintf(MSG_OUT, "libdvdnav: chapter NOT FOUND!\n");
00708 return 0;
00709 }
00710
00711 title = get_TT(vm, vm->state.vtsN, vts_ttn);
00712
00713 #ifdef TRACE
00714 if (title) {
00715 fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n");
00716 fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n",
00717 title, part,
00718 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgcn ,
00719 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgn );
00720 }
00721 #endif
00722 *title_result = title;
00723 *part_result = part;
00724 return 1;
00725 }
00726
00727
00728
00729
00730 int vm_get_audio_stream(vm_t *vm, int audioN) {
00731 int streamN = -1;
00732 const uint AC3_OFFSET = 0x80;
00733 const uint DTS_OFFSET = 0x88;
00734 const uint LPCM_OFFSET = 0xA0;
00735 const uint MP2_OFFSET = 0xC0;
00736
00737 int stream_id = audioN;
00738 if (stream_id >= MP2_OFFSET) {
00739 stream_id -= MP2_OFFSET;
00740 } else if (stream_id >= LPCM_OFFSET) {
00741 stream_id -= LPCM_OFFSET;
00742 } else if (stream_id >= DTS_OFFSET) {
00743 stream_id -= DTS_OFFSET;
00744 } else if (stream_id >= AC3_OFFSET) {
00745 stream_id -= AC3_OFFSET;
00746 }
00747
00748 if((vm->state).domain != VTS_DOMAIN)
00749 stream_id = 0;
00750
00751 if(stream_id < 8) {
00752
00753 if((vm->state).pgc->audio_control[stream_id] & (1<<15)) {
00754 streamN = ((vm->state).pgc->audio_control[stream_id] >> 8) & 0x07;
00755 }
00756 }
00757
00758 if((vm->state).domain != VTS_DOMAIN && streamN == -1)
00759 streamN = 0;
00760
00761 return streamN;
00762 }
00763
00764
00765
00766
00767
00768
00769
00770 int vm_get_subp_stream(vm_t *vm, int subpN, int mode) {
00771 int streamN = -1;
00772 int source_aspect = vm_get_video_aspect(vm);
00773
00774 if((vm->state).domain != VTS_DOMAIN)
00775 subpN = 0;
00776
00777 if(subpN < 32) {
00778
00779 if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
00780 if(source_aspect == 0)
00781 streamN = ((vm->state).pgc->subp_control[subpN] >> 24) & 0x1f;
00782 if(source_aspect == 3)
00783 switch (mode) {
00784 case 0:
00785 streamN = ((vm->state).pgc->subp_control[subpN] >> 16) & 0x1f;
00786 break;
00787 case 1:
00788 streamN = ((vm->state).pgc->subp_control[subpN] >> 8) & 0x1f;
00789 break;
00790 case 2:
00791 streamN = (vm->state).pgc->subp_control[subpN] & 0x1f;
00792 }
00793 }
00794 }
00795
00796 if((vm->state).domain != VTS_DOMAIN && streamN == -1)
00797 streamN = 0;
00798
00799
00800 return streamN;
00801 }
00802
00803 int vm_get_audio_active_stream(vm_t *vm) {
00804 int audioN;
00805 int streamN;
00806 audioN = (vm->state).AST_REG ;
00807 streamN = vm_get_audio_stream(vm, audioN);
00808
00809
00810 if(streamN == -1) {
00811 for(audioN = 0; audioN < 8; audioN++) {
00812 if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
00813 if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0)
00814 break;
00815 }
00816 }
00817 }
00818
00819 return streamN;
00820 }
00821
00822 int vm_set_audio_active_stream(vm_t *vm, int audioN) {
00823
00824 if (audioN >= 8)
00825 return -1;
00826
00827
00828 if(! (vm->state).pgc->audio_control[audioN] & (1<<15))
00829 return -1;
00830
00831 (vm->state).AST_REG = audioN;
00832 return 0;
00833 }
00834
00835 int vm_get_subp_active_stream(vm_t *vm, int mode) {
00836 int subpN;
00837 int streamN;
00838 subpN = (vm->state).SPST_REG & ~0x40;
00839 streamN = vm_get_subp_stream(vm, subpN, mode);
00840
00841
00842 if(streamN == -1) {
00843 for(subpN = 0; subpN < 32; subpN++) {
00844 if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
00845 if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0)
00846 break;
00847 }
00848 }
00849 }
00850
00851 if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40))
00852
00853 return (streamN | 0x80);
00854 else
00855 return streamN;
00856 }
00857
00858 void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) {
00859 *num_avail = 1;
00860 *current = 1;
00861
00862 if((vm->state).domain == VTS_DOMAIN) {
00863 title_info_t *title;
00864
00865 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
00866 return;
00867 title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1];
00868 if(title->title_set_nr != (vm->state).vtsN ||
00869 title->vts_ttn != (vm->state).VTS_TTN_REG)
00870 return;
00871 *num_avail = title->nr_of_angles;
00872 *current = (vm->state).AGL_REG;
00873 }
00874 }
00875
00876 #if 0
00877
00878 void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) {
00879 switch ((vm->state).domain) {
00880 case VTS_DOMAIN:
00881 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams;
00882 *current = (vm->state).AST_REG;
00883 break;
00884 case VTSM_DOMAIN:
00885 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams;
00886 *current = 1;
00887 break;
00888 case VMGM_DOMAIN:
00889 case FP_DOMAIN:
00890 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams;
00891 *current = 1;
00892 break;
00893 }
00894 }
00895
00896
00897 void vm_get_subp_info(vm_t *vm, int *current, int *num_avail) {
00898 switch ((vm->state).domain) {
00899 case VTS_DOMAIN:
00900 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams;
00901 *current = (vm->state).SPST_REG;
00902 break;
00903 case VTSM_DOMAIN:
00904 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams;
00905 *current = 0x41;
00906 break;
00907 case VMGM_DOMAIN:
00908 case FP_DOMAIN:
00909 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams;
00910 *current = 0x41;
00911 break;
00912 }
00913 }
00914 #endif
00915
00916 void vm_get_video_res(vm_t *vm, int *width, int *height) {
00917 video_attr_t attr = vm_get_video_attr(vm);
00918
00919 if(attr.video_format != 0)
00920 *height = 576;
00921 else
00922 *height = 480;
00923 switch(attr.picture_size) {
00924 case 0:
00925 *width = 720;
00926 break;
00927 case 1:
00928 *width = 704;
00929 break;
00930 case 2:
00931 *width = 352;
00932 break;
00933 case 3:
00934 *width = 352;
00935 *height /= 2;
00936 break;
00937 }
00938 }
00939
00940 int vm_get_video_aspect(vm_t *vm) {
00941 int aspect = vm_get_video_attr(vm).display_aspect_ratio;
00942
00943 assert(aspect == 0 || aspect == 3);
00944 (vm->state).registers.SPRM[14] &= ~(0x3 << 10);
00945 (vm->state).registers.SPRM[14] |= aspect << 10;
00946
00947 return aspect;
00948 }
00949
00950 int vm_get_video_scale_permission(vm_t *vm) {
00951 return vm_get_video_attr(vm).permitted_df;
00952 }
00953
00954 int vm_get_video_format(vm_t *vm) {
00955 return vm_get_video_attr(vm).video_format;
00956 }
00957
00958 video_attr_t vm_get_video_attr(vm_t *vm) {
00959 switch ((vm->state).domain) {
00960 case VTS_DOMAIN:
00961 return vm->vtsi->vtsi_mat->vts_video_attr;
00962 case VTSM_DOMAIN:
00963 return vm->vtsi->vtsi_mat->vtsm_video_attr;
00964 case VMGM_DOMAIN:
00965 case FP_DOMAIN:
00966 return vm->vmgi->vmgi_mat->vmgm_video_attr;
00967 default:
00968 abort();
00969 }
00970 }
00971
00972 audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) {
00973 switch ((vm->state).domain) {
00974 case VTS_DOMAIN:
00975 return vm->vtsi->vtsi_mat->vts_audio_attr[streamN];
00976 case VTSM_DOMAIN:
00977 return vm->vtsi->vtsi_mat->vtsm_audio_attr;
00978 case VMGM_DOMAIN:
00979 case FP_DOMAIN:
00980 return vm->vmgi->vmgi_mat->vmgm_audio_attr;
00981 default:
00982 abort();
00983 }
00984 }
00985
00986 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) {
00987 switch ((vm->state).domain) {
00988 case VTS_DOMAIN:
00989 return vm->vtsi->vtsi_mat->vts_subp_attr[streamN];
00990 case VTSM_DOMAIN:
00991 return vm->vtsi->vtsi_mat->vtsm_subp_attr;
00992 case VMGM_DOMAIN:
00993 case FP_DOMAIN:
00994 return vm->vmgi->vmgi_mat->vmgm_subp_attr;
00995 default:
00996 abort();
00997 }
00998 }
00999
01000
01001
01002
01003 static link_t play_PGC(vm_t *vm) {
01004 link_t link_values;
01005
01006 #ifdef TRACE
01007 fprintf(MSG_OUT, "libdvdnav: play_PGC:");
01008 if((vm->state).domain != FP_DOMAIN) {
01009 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm));
01010 } else {
01011 fprintf(MSG_OUT, " first_play_pgc\n");
01012 }
01013 #endif
01014
01015
01016
01017
01018
01019 (vm->state).pgN = 1;
01020 (vm->state).cellN = 0;
01021 (vm->state).blockN = 0;
01022
01023
01024
01025
01026
01027
01028 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
01029 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
01030 (vm->state).pgc->command_tbl->nr_of_pre,
01031 &(vm->state).registers, &link_values)) {
01032
01033 return link_values;
01034 } else {
01035 #ifdef TRACE
01036 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n");
01037 #endif
01038 }
01039 }
01040 return play_PG(vm);
01041 }
01042
01043 static link_t play_PGC_PG(vm_t *vm, int pgN) {
01044 link_t link_values;
01045
01046 #ifdef TRACE
01047 fprintf(MSG_OUT, "libdvdnav: play_PGC_PG:");
01048 if((vm->state).domain != FP_DOMAIN) {
01049 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm));
01050 } else {
01051 fprintf(MSG_OUT, " first_play_pgc\n");
01052 }
01053 #endif
01054
01055
01056
01057
01058
01059 (vm->state).pgN = pgN;
01060 (vm->state).cellN = 0;
01061 (vm->state).blockN = 0;
01062
01063
01064
01065
01066
01067
01068 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
01069 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
01070 (vm->state).pgc->command_tbl->nr_of_pre,
01071 &(vm->state).registers, &link_values)) {
01072
01073 return link_values;
01074 } else {
01075 #ifdef TRACE
01076 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n");
01077 #endif
01078 }
01079 }
01080 return play_PG(vm);
01081 }
01082
01083 static link_t play_PGC_post(vm_t *vm) {
01084 link_t link_values;
01085
01086 #ifdef TRACE
01087 fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n");
01088 #endif
01089
01090
01091
01092
01093
01094
01095 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_post &&
01096 vmEval_CMD((vm->state).pgc->command_tbl->post_cmds,
01097 (vm->state).pgc->command_tbl->nr_of_post,
01098 &(vm->state).registers, &link_values)) {
01099 return link_values;
01100 }
01101
01102 #ifdef TRACE
01103 fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n");
01104 #endif
01105
01106 if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) {
01107 link_values.command = Exit;
01108 link_values.data1 = link_values.data2 = link_values.data3 = 0;
01109 return link_values;
01110 }
01111 return play_PGC(vm);
01112 }
01113
01114 static link_t play_PG(vm_t *vm) {
01115 #ifdef TRACE
01116 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN);
01117 #endif
01118
01119 assert((vm->state).pgN > 0);
01120 if((vm->state).pgN > (vm->state).pgc->nr_of_programs) {
01121 #ifdef TRACE
01122 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i) > pgc->nr_of_programs (%i)\n",
01123 (vm->state).pgN, (vm->state).pgc->nr_of_programs );
01124 #endif
01125 assert((vm->state).pgN == (vm->state).pgc->nr_of_programs + 1);
01126 return play_PGC_post(vm);
01127 }
01128
01129 (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1];
01130
01131 return play_Cell(vm);
01132 }
01133
01134 static link_t play_Cell(vm_t *vm) {
01135 static const link_t play_this = {PlayThis, 0, 0, 0};
01136
01137 #ifdef TRACE
01138 fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN);
01139 #endif
01140
01141 assert((vm->state).cellN > 0);
01142 if((vm->state).cellN > (vm->state).pgc->nr_of_cells) {
01143 #ifdef TRACE
01144 fprintf(MSG_OUT, "libdvdnav: (vm->state).cellN (%i) > pgc->nr_of_cells (%i)\n",
01145 (vm->state).cellN, (vm->state).pgc->nr_of_cells );
01146 #endif
01147 assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1);
01148 return play_PGC_post(vm);
01149 }
01150
01151
01152 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
01153 case 0:
01154 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
01155 break;
01156 case 1:
01157 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
01158 case 0:
01159 assert(0);
01160 break;
01161 case 1:
01162
01163 (vm->state).cellN += (vm->state).AGL_REG - 1;
01164 #ifdef STRICT
01165 assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells);
01166 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0);
01167 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1);
01168 #else
01169 if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) ||
01170 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) ||
01171 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) {
01172 fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n");
01173 (vm->state).cellN -= (vm->state).AGL_REG - 1;
01174 }
01175 #endif
01176 break;
01177 case 2:
01178 case 3:
01179 default:
01180 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
01181 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
01182 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
01183 assert(0);
01184 }
01185 break;
01186 case 2:
01187 case 3:
01188
01189 default:
01190 fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n");
01191 }
01192
01193
01194 if(!set_PGN(vm)) {
01195
01196 assert(0);
01197 return play_PGC_post(vm);
01198 }
01199 (vm->state).cell_restart++;
01200 (vm->state).blockN = 0;
01201 #ifdef TRACE
01202 fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n");
01203 #endif
01204 return play_this;
01205 }
01206
01207 static link_t play_Cell_post(vm_t *vm) {
01208 cell_playback_t *cell;
01209
01210 #ifdef TRACE
01211 fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN);
01212 #endif
01213
01214 cell = &(vm->state).pgc->cell_playback[(vm->state).cellN - 1];
01215
01216
01217
01218
01219 if(cell->cell_cmd_nr != 0) {
01220 link_t link_values;
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231 if ((vm->state).pgc->command_tbl != NULL &&
01232 (vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr) {
01233 #ifdef TRACE
01234 fprintf(MSG_OUT, "libdvdnav: Cell command present, executing\n");
01235 #endif
01236 if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1,
01237 &(vm->state).registers, &link_values)) {
01238 return link_values;
01239 } else {
01240 #ifdef TRACE
01241 fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n");
01242 #endif
01243 }
01244 } else {
01245 #ifdef TRACE
01246 fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n");
01247 #endif
01248 }
01249 }
01250
01251
01252
01253 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
01254 case 0:
01255 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
01256 (vm->state).cellN++;
01257 break;
01258 case 1:
01259 case 2:
01260 case 3:
01261 default:
01262 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
01263 case 0:
01264 assert(0);
01265 break;
01266 case 1:
01267
01268 (vm->state).cellN++;
01269 while((vm->state).cellN <= (vm->state).pgc->nr_of_cells &&
01270 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) {
01271 (vm->state).cellN++;
01272 }
01273 break;
01274 case 2:
01275 case 3:
01276 default:
01277 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
01278 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
01279 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
01280 assert(0);
01281 }
01282 break;
01283 }
01284
01285
01286 if(!set_PGN(vm)) {
01287 #ifdef TRACE
01288 fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n");
01289 #endif
01290 return play_PGC_post(vm);
01291 }
01292 return play_Cell(vm);
01293 }
01294
01295
01296
01297
01298 static int process_command(vm_t *vm, link_t link_values) {
01299
01300 while(link_values.command != PlayThis) {
01301
01302 #ifdef TRACE
01303 fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n");
01304 vm_print_link(link_values);
01305 fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command,
01306 link_values.data1, link_values.data2, link_values.data3);
01307 vm_print_current_domain_state(vm);
01308 fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n");
01309 #endif
01310
01311 switch(link_values.command) {
01312 case LinkNoLink:
01313
01314 if(link_values.data1 != 0)
01315 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01316 return 0;
01317
01318 case LinkTopC:
01319
01320
01321 if(link_values.data1 != 0)
01322 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01323 link_values = play_Cell(vm);
01324 break;
01325 case LinkNextC:
01326
01327
01328 if(link_values.data1 != 0)
01329 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01330 (vm->state).cellN += 1;
01331 link_values = play_Cell(vm);
01332 break;
01333 case LinkPrevC:
01334
01335
01336 if(link_values.data1 != 0)
01337 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01338 assert((vm->state).cellN > 1);
01339 (vm->state).cellN -= 1;
01340 link_values = play_Cell(vm);
01341 break;
01342
01343 case LinkTopPG:
01344
01345
01346 if(link_values.data1 != 0)
01347 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01348 link_values = play_PG(vm);
01349 break;
01350 case LinkNextPG:
01351
01352
01353 if(link_values.data1 != 0)
01354 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01355 (vm->state).pgN += 1;
01356 link_values = play_PG(vm);
01357 break;
01358 case LinkPrevPG:
01359
01360
01361 if(link_values.data1 != 0)
01362 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01363 assert((vm->state).pgN > 1);
01364 (vm->state).pgN -= 1;
01365 link_values = play_PG(vm);
01366 break;
01367
01368 case LinkTopPGC:
01369
01370
01371 if(link_values.data1 != 0)
01372 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01373 link_values = play_PGC(vm);
01374 break;
01375 case LinkNextPGC:
01376
01377
01378 if(link_values.data1 != 0)
01379 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01380 assert((vm->state).pgc->next_pgc_nr != 0);
01381 if(set_PGCN(vm, (vm->state).pgc->next_pgc_nr))
01382 link_values = play_PGC(vm);
01383 else
01384 link_values.command = Exit;
01385 break;
01386 case LinkPrevPGC:
01387
01388
01389 if(link_values.data1 != 0)
01390 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01391 assert((vm->state).pgc->prev_pgc_nr != 0);
01392 if(set_PGCN(vm, (vm->state).pgc->prev_pgc_nr))
01393 link_values = play_PGC(vm);
01394 else
01395 link_values.command = Exit;
01396 break;
01397 case LinkGoUpPGC:
01398
01399
01400 if(link_values.data1 != 0)
01401 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01402 assert((vm->state).pgc->goup_pgc_nr != 0);
01403 if(set_PGCN(vm, (vm->state).pgc->goup_pgc_nr))
01404 link_values = play_PGC(vm);
01405 else
01406 link_values.command = Exit;
01407 break;
01408 case LinkTailPGC:
01409
01410
01411 if(link_values.data1 != 0)
01412 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01413 link_values = play_PGC_post(vm);
01414 break;
01415
01416 case LinkRSM:
01417 {
01418
01419 int i;
01420
01421
01422 if (!(vm->state).rsm_vtsN) {
01423 fprintf(MSG_OUT, "libdvdnav: trying to resume without any resume info set\n");
01424 link_values.command = Exit;
01425 break;
01426 }
01427
01428 (vm->state).domain = VTS_DOMAIN;
01429 if (!ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN))
01430 assert(0);
01431 set_PGCN(vm, (vm->state).rsm_pgcN);
01432
01433
01434
01435
01436 for(i = 0; i < 5; i++) {
01437 (vm->state).registers.SPRM[4 + i] = (vm->state).rsm_regs[i];
01438 }
01439
01440 if(link_values.data1 != 0)
01441 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
01442
01443 if((vm->state).rsm_cellN == 0) {
01444 assert((vm->state).cellN);
01445 (vm->state).pgN = 1;
01446 link_values = play_PG(vm);
01447 } else {
01448
01449 (vm->state).cellN = (vm->state).rsm_cellN;
01450 link_values.command = PlayThis;
01451 link_values.data1 = (vm->state).rsm_blockN & 0xffff;
01452 link_values.data2 = (vm->state).rsm_blockN >> 16;
01453 if(!set_PGN(vm)) {
01454
01455 assert(0);
01456 link_values.command = LinkTailPGC;
01457 link_values.data1 = 0;
01458 }
01459 }
01460 }
01461 break;
01462 case LinkPGCN:
01463
01464 if(!set_PGCN(vm, link_values.data1))
01465 assert(0);
01466 link_values = play_PGC(vm);
01467 break;
01468 case LinkPTTN:
01469
01470
01471
01472 assert((vm->state).domain == VTS_DOMAIN);
01473 if(link_values.data2 != 0)
01474 (vm->state).HL_BTNN_REG = link_values.data2 << 10;
01475 if(!set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1))
01476 link_values.command = Exit;
01477 else
01478 link_values = play_PG(vm);
01479 break;
01480 case LinkPGN:
01481
01482
01483 if(link_values.data2 != 0)
01484 (vm->state).HL_BTNN_REG = link_values.data2 << 10;
01485
01486 (vm->state).pgN = link_values.data1;
01487 link_values = play_PG(vm);
01488 break;
01489 case LinkCN:
01490
01491
01492 if(link_values.data2 != 0)
01493 (vm->state).HL_BTNN_REG = link_values.data2 << 10;
01494
01495 (vm->state).cellN = link_values.data1;
01496 link_values = play_Cell(vm);
01497 break;
01498
01499 case Exit:
01500 vm->stopped = 1;
01501 return 0;
01502
01503 case JumpTT:
01504
01505
01506
01507
01508
01509 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN);
01510 if(set_TT(vm, link_values.data1))
01511 link_values = play_PGC(vm);
01512 else
01513 link_values.command = Exit;
01514 break;
01515 case JumpVTS_TT:
01516
01517
01518
01519
01520
01521 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN);
01522 if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1))
01523 link_values.command = Exit;
01524 else
01525 link_values = play_PGC(vm);
01526 break;
01527 case JumpVTS_PTT:
01528
01529
01530
01531
01532
01533 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN);
01534 if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2))
01535 link_values.command = Exit;
01536 else
01537 link_values = play_PGC_PG(vm, (vm->state).pgN);
01538 break;
01539
01540 case JumpSS_FP:
01541
01542
01543
01544
01545 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN);
01546 if (!set_FP_PGC(vm))
01547 assert(0);
01548 link_values = play_PGC(vm);
01549 break;
01550 case JumpSS_VMGM_MENU:
01551
01552
01553
01554 assert((vm->state).domain != VTS_DOMAIN);
01555 if(vm->vmgi == NULL || vm->vmgi->pgci_ut == NULL) {
01556 link_values.command = Exit;
01557 break;
01558 }
01559 (vm->state).domain = VMGM_DOMAIN;
01560 if(!set_MENU(vm, link_values.data1))
01561 assert(0);
01562 link_values = play_PGC(vm);
01563 break;
01564 case JumpSS_VTSM:
01565
01566
01567
01568
01569
01570
01571 if(link_values.data1 != 0) {
01572 if (link_values.data1 != (vm->state).vtsN) {
01573
01574 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN);
01575 if (!ifoOpenNewVTSI(vm, vm->dvd, link_values.data1))
01576 assert(0);
01577 if(vm->vtsi == NULL || vm->vtsi->pgci_ut == NULL) {
01578 link_values.command = Exit;
01579 break;
01580 }
01581 (vm->state).domain = VTSM_DOMAIN;
01582 } else {
01583
01584
01585 assert((vm->state).domain == VTSM_DOMAIN ||
01586 (vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN);
01587 if(vm->vtsi == NULL || vm->vtsi->pgci_ut == NULL) {
01588 link_values.command = Exit;
01589 break;
01590 }
01591 (vm->state).domain = VTSM_DOMAIN;
01592 }
01593 } else {
01594
01595 assert((vm->state).domain == VTSM_DOMAIN);
01596 }
01597
01598
01599
01600 (vm->state).VTS_TTN_REG = link_values.data2;
01601
01602
01603 (vm->state).TTN_REG = get_TT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG);
01604 if(!set_MENU(vm, link_values.data3))
01605 assert(0);
01606 link_values = play_PGC(vm);
01607 break;
01608 case JumpSS_VMGM_PGC:
01609
01610
01611 assert((vm->state).domain != VTS_DOMAIN);
01612 if(vm->vmgi == NULL || vm->vmgi->pgci_ut == NULL) {
01613 link_values.command = Exit;
01614 break;
01615 }
01616 (vm->state).domain = VMGM_DOMAIN;
01617 if(!set_PGCN(vm, link_values.data1))
01618 assert(0);
01619 link_values = play_PGC(vm);
01620 break;
01621
01622 case CallSS_FP:
01623
01624 assert((vm->state).domain == VTS_DOMAIN);
01625
01626 set_RSMinfo(vm, link_values.data1, 0);
01627 set_FP_PGC(vm);
01628 link_values = play_PGC(vm);
01629 break;
01630 case CallSS_VMGM_MENU:
01631
01632
01633 assert((vm->state).domain == VTS_DOMAIN);
01634
01635 if(vm->vmgi == NULL || vm->vmgi->pgci_ut == NULL) {
01636 link_values.command = Exit;
01637 break;
01638 }
01639 set_RSMinfo(vm, link_values.data2, 0);
01640 (vm->state).domain = VMGM_DOMAIN;
01641 if(!set_MENU(vm, link_values.data1))
01642 assert(0);
01643 link_values = play_PGC(vm);
01644 break;
01645 case CallSS_VTSM:
01646
01647
01648 assert((vm->state).domain == VTS_DOMAIN);
01649
01650 if(vm->vtsi == NULL || vm->vtsi->pgci_ut == NULL) {
01651 link_values.command = Exit;
01652 break;
01653 }
01654 set_RSMinfo(vm, link_values.data2, 0);
01655 (vm->state).domain = VTSM_DOMAIN;
01656 if(!set_MENU(vm, link_values.data1))
01657 assert(0);
01658 link_values = play_PGC(vm);
01659 break;
01660 case CallSS_VMGM_PGC:
01661
01662
01663 assert((vm->state).domain == VTS_DOMAIN);
01664
01665 if(vm->vmgi == NULL || vm->vmgi->pgci_ut == NULL) {
01666 link_values.command = Exit;
01667 break;
01668 }
01669 set_RSMinfo(vm, link_values.data2, 0);
01670 (vm->state).domain = VMGM_DOMAIN;
01671 if(!set_PGCN(vm, link_values.data1))
01672 assert(0);
01673 link_values = play_PGC(vm);
01674 break;
01675 case PlayThis:
01676
01677 assert(0);
01678 break;
01679 }
01680
01681 #ifdef TRACE
01682 fprintf(MSG_OUT, "libdvdnav: After printout starts:\n");
01683 vm_print_current_domain_state(vm);
01684 fprintf(MSG_OUT, "libdvdnav: After printout ends.\n");
01685 #endif
01686
01687 }
01688 (vm->state).blockN = link_values.data1 | (link_values.data2 << 16);
01689 return 1;
01690 }
01691
01692
01693
01694
01695 static int set_TT(vm_t *vm, int tt) {
01696 return set_PTT(vm, tt, 1);
01697 }
01698
01699 static int set_PTT(vm_t *vm, int tt, int ptt) {
01700 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts);
01701 return set_VTS_PTT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr,
01702 vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, ptt);
01703 }
01704
01705 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) {
01706 return set_VTS_PTT(vm, vtsN, vts_ttn, 1);
01707 }
01708
01709 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) {
01710 int pgcN, pgN, res;
01711
01712 (vm->state).domain = VTS_DOMAIN;
01713
01714 if (vtsN != (vm->state).vtsN)
01715 if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN))
01716 return 0;
01717
01718 if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) ||
01719 (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) {
01720 return 0;
01721 }
01722
01723 pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn;
01724 pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn;
01725
01726 (vm->state).TT_PGCN_REG = pgcN;
01727 (vm->state).PTTN_REG = part;
01728 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn);
01729 if( (vm->state.TTN_REG) == 0 )
01730 return 0;
01731
01732 (vm->state).VTS_TTN_REG = vts_ttn;
01733 (vm->state).vtsN = vtsN;
01734
01735
01736 res = set_PGCN(vm, pgcN);
01737 (vm->state).pgN = pgN;
01738 return res;
01739 }
01740
01741 static int set_PROG(vm_t *vm, int tt, int pgcn, int pgn) {
01742 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts);
01743 return set_VTS_PROG(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr,
01744 vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, pgcn, pgn);
01745 }
01746
01747 static int set_VTS_PROG(vm_t *vm, int vtsN, int vts_ttn, int pgcn, int pgn) {
01748 int pgcN, pgN, res, title, part = 0;
01749
01750 (vm->state).domain = VTS_DOMAIN;
01751
01752 if (vtsN != (vm->state).vtsN)
01753 if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN))
01754 return 0;
01755
01756 if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts)) {
01757 return 0;
01758 }
01759
01760 pgcN = pgcn;
01761 pgN = pgn;
01762
01763 (vm->state).TT_PGCN_REG = pgcN;
01764 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn);
01765 assert( (vm->state.TTN_REG) != 0 );
01766 (vm->state).VTS_TTN_REG = vts_ttn;
01767 (vm->state).vtsN = vtsN;
01768
01769
01770 res = set_PGCN(vm, pgcN);
01771 (vm->state).pgN = pgN;
01772 vm_get_current_title_part(vm, &title, &part);
01773 (vm->state).PTTN_REG = part;
01774 return res;
01775 }
01776
01777 static int set_FP_PGC(vm_t *vm) {
01778 (vm->state).domain = FP_DOMAIN;
01779 if (!vm->vmgi->first_play_pgc) {
01780 return set_PGCN(vm, 1);
01781 }
01782 (vm->state).pgc = vm->vmgi->first_play_pgc;
01783 (vm->state).pgcN = vm->vmgi->vmgi_mat->first_play_pgc;
01784 return 1;
01785 }
01786
01787
01788 static int set_MENU(vm_t *vm, int menu) {
01789 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN);
01790 return set_PGCN(vm, get_ID(vm, menu));
01791 }
01792
01793 static int set_PGCN(vm_t *vm, int pgcN) {
01794 pgcit_t *pgcit;
01795
01796 pgcit = get_PGCIT(vm);
01797 assert(pgcit != NULL);
01798
01799 if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) {
01800 #ifdef TRACE
01801 fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN);
01802 #endif
01803 return 0;
01804 }
01805
01806 (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc;
01807 (vm->state).pgcN = pgcN;
01808 (vm->state).pgN = 1;
01809
01810 if((vm->state).domain == VTS_DOMAIN)
01811 (vm->state).TT_PGCN_REG = pgcN;
01812
01813 return 1;
01814 }
01815
01816
01817 static int set_PGN(vm_t *vm) {
01818 int new_pgN = 0;
01819 int dummy, part = 0;
01820
01821 while(new_pgN < (vm->state).pgc->nr_of_programs
01822 && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN])
01823 new_pgN++;
01824
01825 if(new_pgN == (vm->state).pgc->nr_of_programs)
01826 if((vm->state).cellN > (vm->state).pgc->nr_of_cells)
01827 return 0;
01828
01829 (vm->state).pgN = new_pgN;
01830
01831 if((vm->state).domain == VTS_DOMAIN) {
01832 playback_type_t *pb_ty;
01833 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
01834 return 0;
01835 pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty;
01836 vm_get_current_title_part(vm, &dummy, &part);
01837 (vm->state).PTTN_REG = part;
01838 }
01839 return 1;
01840 }
01841
01842
01843 static void set_RSMinfo(vm_t *vm, int cellN, int blockN) {
01844 int i;
01845
01846 if(cellN) {
01847 (vm->state).rsm_cellN = cellN;
01848 (vm->state).rsm_blockN = blockN;
01849 } else {
01850 (vm->state).rsm_cellN = (vm->state).cellN;
01851 (vm->state).rsm_blockN = blockN;
01852 }
01853 (vm->state).rsm_vtsN = (vm->state).vtsN;
01854 (vm->state).rsm_pgcN = get_PGCN(vm);
01855
01856
01857
01858 for(i = 0; i < 5; i++) {
01859 (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i];
01860 }
01861 }
01862
01863
01864
01865
01866
01867
01868
01869
01870 static int get_TT(vm_t *vm, int vtsN, int vts_ttn) {
01871 int i;
01872 int tt=0;
01873
01874 for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) {
01875 if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN &&
01876 vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) {
01877 tt=i;
01878 break;
01879 }
01880 }
01881 return tt;
01882 }
01883
01884
01885
01886
01887 static int get_ID(vm_t *vm, int id) {
01888 int pgcN, i;
01889 pgcit_t *pgcit;
01890
01891
01892 pgcit = get_PGCIT(vm);
01893 assert(pgcit != NULL);
01894 #ifdef TRACE
01895 fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id);
01896 #endif
01897
01898
01899 id |=0x80;
01900
01901
01902 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
01903 if( (pgcit->pgci_srp[i].entry_id) == id) {
01904 pgcN = i + 1;
01905 #ifdef TRACE
01906 fprintf(MSG_OUT, "libdvdnav: Found menu.\n");
01907 #endif
01908 return pgcN;
01909 }
01910 }
01911 #ifdef TRACE
01912 fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f);
01913 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
01914 if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) {
01915 fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n",
01916 pgcit->pgci_srp[i].entry_id & 0x7f);
01917 }
01918 }
01919 #endif
01920 return 0;
01921 }
01922
01923
01924 static int get_PGCN(vm_t *vm) {
01925 pgcit_t *pgcit;
01926 int pgcN = 1;
01927
01928 pgcit = get_PGCIT(vm);
01929
01930 if (pgcit) {
01931 while(pgcN <= pgcit->nr_of_pgci_srp) {
01932 if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) {
01933 assert((vm->state).pgcN == pgcN);
01934 return pgcN;
01935 }
01936 pgcN++;
01937 }
01938 }
01939 fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n",
01940 (vm->state).domain);
01941 return 0;
01942 }
01943
01944 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) {
01945 int i;
01946
01947 if(h == NULL || h->pgci_ut == NULL) {
01948 fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n");
01949 return NULL;
01950 }
01951
01952 i = 0;
01953 while(i < h->pgci_ut->nr_of_lus
01954 && h->pgci_ut->lu[i].lang_code != lang)
01955 i++;
01956 if(i == h->pgci_ut->nr_of_lus) {
01957 fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n",
01958 (char)(lang >> 8), (char)(lang & 0xff),
01959 (char)(h->pgci_ut->lu[0].lang_code >> 8),
01960 (char)(h->pgci_ut->lu[0].lang_code & 0xff));
01961 fprintf(MSG_OUT, "libdvdnav: Menu Languages available: ");
01962 for(i = 0; i < h->pgci_ut->nr_of_lus; i++) {
01963 fprintf(MSG_OUT, "%c%c ",
01964 (char)(h->pgci_ut->lu[i].lang_code >> 8),
01965 (char)(h->pgci_ut->lu[i].lang_code & 0xff));
01966 }
01967 fprintf(MSG_OUT, "\n");
01968 i = 0;
01969 }
01970
01971 return h->pgci_ut->lu[i].pgcit;
01972 }
01973
01974
01975 static pgcit_t* get_PGCIT(vm_t *vm) {
01976 pgcit_t *pgcit = NULL;
01977
01978 switch ((vm->state).domain) {
01979 case VTS_DOMAIN:
01980 if(!vm->vtsi) return NULL;
01981 pgcit = vm->vtsi->vts_pgcit;
01982 break;
01983 case VTSM_DOMAIN:
01984 if(!vm->vtsi) return NULL;
01985 pgcit = get_MENU_PGCIT(vm, vm->vtsi, (vm->state).registers.SPRM[0]);
01986 break;
01987 case VMGM_DOMAIN:
01988 case FP_DOMAIN:
01989 pgcit = get_MENU_PGCIT(vm, vm->vmgi, (vm->state).registers.SPRM[0]);
01990 break;
01991 default:
01992 abort();
01993 }
01994
01995 return pgcit;
01996 }
01997
01998
01999
02000 ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title)
02001 {
02002 ifo_handle_t *ifo = NULL;
02003 uint8_t titleset_nr;
02004 if((title < 1) || (title > vm->vmgi->tt_srpt->nr_of_srpts))
02005 return NULL;
02006 titleset_nr = vm->vmgi->tt_srpt->title[title-1].title_set_nr;
02007 ifo = ifoOpen(vm->dvd, titleset_nr);
02008 return ifo;
02009 }
02010
02011 void vm_ifo_close(ifo_handle_t *ifo)
02012 {
02013 ifoClose(ifo);
02014 }
02015
02016
02017
02018 #ifdef TRACE
02019 void vm_position_print(vm_t *vm, vm_position_t *position) {
02020 fprintf(MSG_OUT, "libdvdnav: But=%x Spu=%x Aud=%x Ang=%x Hop=%x vts=%x dom=%x cell=%x cell_restart=%x cell_start=%x still=%x block=%x\n",
02021 position->button,
02022 position->spu_channel,
02023 position->audio_channel,
02024 position->angle_channel,
02025 position->hop_channel,
02026 position->vts,
02027 position->domain,
02028 position->cell,
02029 position->cell_restart,
02030 position->cell_start,
02031 position->still,
02032 position->block);
02033 }
02034 #endif
02035