comparison vm.c @ 114:b6834e6359cf src

big libdvdnav cleanup, quoting the ChangeLog: * some bugfixes * code cleanup * build process polishing * more sensible event order in get_next_block to ensure useful event delivery * VOBU level resume * fixed: seeking in a multiangle feature briefly showed the wrong angle
author mroi
date Thu, 20 Feb 2003 15:32:21 +0000
parents ec2df154be56
children 66ca475e2a5a
comparison
equal deleted inserted replaced
113:ec2df154be56 114:b6834e6359cf
43 #include "decoder.h" 43 #include "decoder.h"
44 #include "vmcmd.h" 44 #include "vmcmd.h"
45 #include "vm.h" 45 #include "vm.h"
46 #include "dvdnav_internal.h" 46 #include "dvdnav_internal.h"
47 47
48 48 /*
49 #define STRICT 49 #define STRICT
50 50 */
51 51
52 /* Local prototypes */ 52 /* Local prototypes */
53 53
54 static void saveRSMinfo(vm_t *vm,int cellN, int blockN); 54 /* get_XYZ returns a value.
55 * set_XYZ sets state using passed parameters.
56 * returns success/failure.
57 */
58
59 /* Play */
55 static link_t play_PGC(vm_t *vm); 60 static link_t play_PGC(vm_t *vm);
56 static link_t play_PGC_PG(vm_t *vm, int pgN); 61 static link_t play_PGC_PG(vm_t *vm, int pgN);
57 static link_t play_PGC_post(vm_t *vm); 62 static link_t play_PGC_post(vm_t *vm);
58 static link_t play_PG(vm_t *vm); 63 static link_t play_PG(vm_t *vm);
59 static link_t play_Cell(vm_t *vm); 64 static link_t play_Cell(vm_t *vm);
60 static link_t play_Cell_post(vm_t *vm); 65 static link_t play_Cell_post(vm_t *vm);
61 static link_t process_command(vm_t *vm,link_t link_values); 66
62 67 /* Process link - returns 1 if a hop has been performed */
63 static void ifoOpenNewVTSI(vm_t *vm,dvd_reader_t *dvd, int vtsN); 68 static int process_command(vm_t *vm,link_t link_values);
69
70 /* Set */
71 static int set_TT(vm_t *vm, int tt);
72 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn);
73 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part);
74 static int set_FP_PGC(vm_t *vm);
75 static int set_MENU(vm_t *vm, int menu);
76 static int set_PGCN(vm_t *vm, int pgcN);
77 static int set_PGN(vm_t *vm); /* Set PGN based on (vm->state).CellN */
78 static void set_RSMinfo(vm_t *vm, int cellN, int blockN);
79
80 /* Get */
81 static int get_TT(vm_t *vm, int vtsN, int vts_ttn);
82 static int get_ID(vm_t *vm, int id);
83 static int get_PGCN(vm_t *vm);
84
85 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang);
64 static pgcit_t* get_PGCIT(vm_t *vm); 86 static pgcit_t* get_PGCIT(vm_t *vm);
65 87
66 /* get_XYZ returns a value. 88
67 * ser_XYZ sets state using passed parameters. 89 /* Helper functions */
68 * returns success/failure. 90
69 */ 91 #ifdef TRACE
70
71 /* Can only be called when in VTS_DOMAIN */
72 static int set_FP_PGC(vm_t *vm); /* FP */
73 static int set_TT(vm_t *vm,int tt);
74 static int set_VTS_TT(vm_t *vm,int vtsN, int vts_ttn);
75 static int set_VTS_PTT(vm_t *vm,int vtsN, int vts_ttn, int part);
76
77 static int set_MENU(vm_t *vm,int menu); /* VTSM & VMGM */
78
79 /* Called in any domain */
80 static int get_TT(vm_t *vm, int vtsN, int vts_ttn);
81 static int get_ID(vm_t *vm,int id);
82 static int get_PGCN(vm_t *vm);
83 static int set_PGN(vm_t *vm); /* Set PGN based on (vm->state).CellN */
84 static int set_PGC(vm_t *vm,int pgcN);
85
86 /* Initialisation */
87
88 vm_t* vm_new_vm() {
89 vm_t *vm = (vm_t*)calloc(sizeof(vm_t), sizeof(char));
90
91 return vm;
92 }
93
94 static void vm_print_current_domain_state(vm_t *vm) { 92 static void vm_print_current_domain_state(vm_t *vm) {
95 switch((vm->state).domain) { 93 switch((vm->state).domain) {
96 case VTS_DOMAIN: 94 case VTS_DOMAIN:
97 fprintf(MSG_OUT, "libdvdnav: Video Title Domain: -\n"); 95 fprintf(MSG_OUT, "libdvdnav: Video Title Domain: -\n");
98 break; 96 break;
121 (vm->state).blockN, 119 (vm->state).blockN,
122 (vm->state).VTS_TTN_REG, 120 (vm->state).VTS_TTN_REG,
123 (vm->state).TTN_REG, 121 (vm->state).TTN_REG,
124 (vm->state).TT_PGCN_REG); 122 (vm->state).TT_PGCN_REG);
125 } 123 }
126 124 #endif
127 void vm_stop(vm_t *vm) { 125
128 if(!vm) 126 void dvd_read_name( vm_t *this, const char *devname) {
129 return;
130
131 if(vm->vmgi) {
132 ifoClose(vm->vmgi);
133 vm->vmgi=NULL;
134 }
135
136 if(vm->vtsi) {
137 ifoClose(vm->vtsi);
138 vm->vmgi=NULL;
139 }
140
141 if(vm->dvd) {
142 DVDClose(vm->dvd);
143 vm->dvd=NULL;
144 }
145 }
146
147 void vm_free_vm(vm_t *vm) {
148 if(vm) {
149 vm_stop(vm);
150 free(vm);
151 }
152 }
153
154 /* IFO Access */
155
156 ifo_handle_t *vm_get_vmgi(vm_t *vm) {
157 if(!vm)
158 return NULL;
159
160 return vm->vmgi;
161 }
162
163 ifo_handle_t *vm_get_vtsi(vm_t *vm) {
164 if(!vm)
165 return NULL;
166
167 return vm->vtsi;
168 }
169
170 /* Reader Access */
171
172 dvd_reader_t *vm_get_dvd_reader(vm_t *vm) {
173 if(!vm)
174 return NULL;
175
176 return vm->dvd;
177 }
178
179 void dvd_read_name( vm_t *this, char *devname) {
180 int fd, i; 127 int fd, i;
128 #ifndef __FreeBSD__
181 off64_t off; 129 off64_t off;
130 #else
131 off_t off;
132 #endif
182 uint8_t data[DVD_VIDEO_LB_LEN]; 133 uint8_t data[DVD_VIDEO_LB_LEN];
183 134
184 /* Read DVD name */ 135 /* Read DVD name */
185 fd=open(devname, O_RDONLY); 136 fd=open(devname, O_RDONLY);
186 if (fd > 0) { 137 if (fd > 0) {
187 off = lseek64( fd, 32 * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET ); 138 off = lseek64( fd, 32 * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
188 if( off == ( 32 * (int64_t) DVD_VIDEO_LB_LEN ) ) { 139 if( off == ( 32 * (int64_t) DVD_VIDEO_LB_LEN ) ) {
189 off = read( fd, data, DVD_VIDEO_LB_LEN ); 140 off = read( fd, data, DVD_VIDEO_LB_LEN );
190 close(fd); 141 close(fd);
191 if (off == ( (int64_t) DVD_VIDEO_LB_LEN )) { 142 if (off == ( (int64_t) DVD_VIDEO_LB_LEN )) {
192 fprintf( stderr, "VM DVD Title: "); 143 fprintf(MSG_OUT, "libdvdnav: DVD Title: ");
193 for(i=25; i < 73; i++ ) { 144 for(i=25; i < 73; i++ ) {
194 if((data[i] == 0)) break; 145 if((data[i] == 0)) break;
195 if((data[i] > 32) && (data[i] < 127)) { 146 if((data[i] > 32) && (data[i] < 127)) {
196 fprintf(stderr, "%c", data[i]); 147 fprintf(MSG_OUT, "%c", data[i]);
197 } else { 148 } else {
198 fprintf(stderr, " "); 149 fprintf(MSG_OUT, " ");
199 } 150 }
200 } 151 }
201 strncpy(&this->dvd_name[0], &data[25], 48); 152 strncpy(&this->dvd_name[0], &data[25], 48);
202 /* fprintf(stderr, "TITLE:%s\n",&this->dvd_name[0]); */
203 this->dvd_name[48]=0; 153 this->dvd_name[48]=0;
204 this->dvd_name_length=strlen(&this->dvd_name[0]); 154 fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: ");
205 fprintf( stderr, "\nVM DVD Serial Number: ");
206 for(i=73; i < 89; i++ ) { 155 for(i=73; i < 89; i++ ) {
207 if((data[i] == 0)) break; 156 if((data[i] == 0)) break;
208 if((data[i] > 32) && (data[i] < 127)) { 157 if((data[i] > 32) && (data[i] < 127)) {
209 fprintf(stderr, "%c", data[i]); 158 fprintf(MSG_OUT, "%c", data[i]);
210 } else { 159 } else {
211 fprintf(stderr, " "); 160 fprintf(MSG_OUT, " ");
212 } 161 }
213 } 162 }
214 fprintf( stderr, "\nVM DVD Title (Alternative): "); 163 fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): ");
215 for(i=89; i < 128; i++ ) { 164 for(i=89; i < 128; i++ ) {
216 if((data[i] == 0)) break; 165 if((data[i] == 0)) break;
217 if((data[i] > 32) && (data[i] < 127)) { 166 if((data[i] > 32) && (data[i] < 127)) {
218 fprintf(stderr, "%c", data[i]); 167 fprintf(MSG_OUT, "%c", data[i]);
219 } else { 168 } else {
220 fprintf(stderr, " "); 169 fprintf(MSG_OUT, " ");
221 } 170 }
222 } 171 }
223 fprintf( stderr, "\n"); 172 fprintf(MSG_OUT, "\n");
224 } else { 173 } else {
225 fprintf( stderr, "libdvdread: Can't read name block. Probably not a DVD-ROM device.\n"); 174 fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a DVD-ROM device.\n");
226 } 175 }
227 } else { 176 } else {
228 fprintf( stderr, "libdvdread: Can't seek to block %u\n", 32 ); 177 fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 );
229 } 178 }
230 close(fd); 179 close(fd);
231 } else { 180 } else {
232 fprintf(stderr,"NAME OPEN FAILED\n"); 181 fprintf(MSG_OUT, "NAME OPEN FAILED\n");
233 } 182 }
234 } 183 }
235 184
236 int vm_reset(vm_t *vm, char *dvdroot) /* , register_t regs) */ { 185 static void ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) {
186 if((vm->state).vtsN == vtsN) {
187 return; /* We alread have it */
188 }
189
190 if(vm->vtsi != NULL)
191 ifoClose(vm->vtsi);
192
193 vm->vtsi = ifoOpenVTSI(dvd, vtsN);
194 if(vm->vtsi == NULL) {
195 fprintf(MSG_OUT, "libdvdnav: ifoOpenVTSI failed - CRASHING!!!\n");
196 assert(0);
197 }
198 if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) {
199 fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed - CRASHING!!!\n");
200 assert(0);
201 }
202 if(!ifoRead_PGCIT(vm->vtsi)) {
203 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed - CRASHING!!!\n");
204 assert(0);
205 }
206 if(!ifoRead_PGCI_UT(vm->vtsi)) {
207 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed - CRASHING!!!\n");
208 assert(0);
209 }
210 if(!ifoRead_VOBU_ADMAP(vm->vtsi)) {
211 fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed - CRASHING\n");
212 assert(0);
213 }
214 if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) {
215 fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed - CRASHING\n");
216 assert(0);
217 }
218 (vm->state).vtsN = vtsN;
219 }
220
221
222 /* Initialisation & Destruction */
223
224 vm_t* vm_new_vm() {
225 return (vm_t*)calloc(sizeof(vm_t), sizeof(char));
226 }
227
228 void vm_free_vm(vm_t *vm) {
229 vm_stop(vm);
230 free(vm);
231 }
232
233
234 /* IFO Access */
235
236 ifo_handle_t *vm_get_vmgi(vm_t *vm) {
237 return vm->vmgi;
238 }
239
240 ifo_handle_t *vm_get_vtsi(vm_t *vm) {
241 return vm->vtsi;
242 }
243
244
245 /* Reader Access */
246
247 dvd_reader_t *vm_get_dvd_reader(vm_t *vm) {
248 return vm->dvd;
249 }
250
251
252 /* Basic Handling */
253
254 void vm_start(vm_t *vm)
255 {
256 /* Set pgc to FP (First Play) pgc */
257 set_FP_PGC(vm);
258 process_command(vm, play_PGC(vm));
259 }
260
261 void vm_stop(vm_t *vm) {
262 if(vm->vmgi) {
263 ifoClose(vm->vmgi);
264 vm->vmgi=NULL;
265 }
266 if(vm->vtsi) {
267 ifoClose(vm->vtsi);
268 vm->vmgi=NULL;
269 }
270 if(vm->dvd) {
271 DVDClose(vm->dvd);
272 vm->dvd=NULL;
273 }
274 vm->stopped = 1;
275 }
276
277 int vm_reset(vm_t *vm, const char *dvdroot) {
237 /* Setup State */ 278 /* Setup State */
238 memset((vm->state).registers.SPRM, 0, sizeof(uint16_t)*24); 279 memset((vm->state).registers.SPRM, 0, sizeof((vm->state).registers.SPRM));
239 memset((vm->state).registers.GPRM, 0, sizeof((vm->state).registers.GPRM)); 280 memset((vm->state).registers.GPRM, 0, sizeof((vm->state).registers.GPRM));
240 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode)); 281 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
241 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode)); 282 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode));
242 memset((vm->state).registers.GPRM_time, 0, sizeof((vm->state).registers.GPRM_time)); 283 memset((vm->state).registers.GPRM_time, 0, sizeof((vm->state).registers.GPRM_time));
243 (vm->state).registers.SPRM[0] = ('e'<<8)|'n'; /* Player Menu Languange code */ 284 (vm->state).registers.SPRM[0] = ('e'<<8)|'n'; /* Player Menu Languange code */
244 (vm->state).AST_REG = 15; /* 15 why? */ 285 (vm->state).AST_REG = 15; /* 15 why? */
245 (vm->state).SPST_REG = 62; /* 62 why? */ 286 (vm->state).SPST_REG = 62; /* 62 why? */
246 (vm->state).AGL_REG = 1; 287 (vm->state).AGL_REG = 1;
247 (vm->state).TTN_REG = 1; 288 (vm->state).TTN_REG = 1;
248 (vm->state).VTS_TTN_REG = 1; 289 (vm->state).VTS_TTN_REG = 1;
249 /* (vm->state).TT_PGCN_REG = 0 */ 290 /* (vm->state).TT_PGCN_REG = 0 */
250 (vm->state).PTTN_REG = 1; 291 (vm->state).PTTN_REG = 1;
251 (vm->state).HL_BTNN_REG = 1 << 10; 292 (vm->state).HL_BTNN_REG = 1 << 10;
252 293 (vm->state).PTL_REG = 15; /* Parental Level */
253 (vm->state).PTL_REG = 15; /* Parental Level */ 294 (vm->state).registers.SPRM[12] = ('U'<<8)|'S'; /* Parental Management Country Code */
254 (vm->state).registers.SPRM[12] = ('U'<<8)|'S'; /* Parental Management Country Code */ 295 (vm->state).registers.SPRM[16] = ('e'<<8)|'n'; /* Initial Language Code for Audio */
255 (vm->state).registers.SPRM[16] = ('e'<<8)|'n'; /* Initial Language Code for Audio */ 296 (vm->state).registers.SPRM[18] = ('e'<<8)|'n'; /* Initial Language Code for Spu */
256 (vm->state).registers.SPRM[18] = ('e'<<8)|'n'; /* Initial Language Code for Spu */ 297 (vm->state).registers.SPRM[20] = 0x1; /* Player Regional Code Mask. Region free! */
257 /* Player Regional Code Mask. 298 (vm->state).registers.SPRM[14] = 0x100; /* Try Pan&Scan */
258 * bit0 = Region 1
259 * bit1 = Region 2
260 */
261 (vm->state).registers.SPRM[20] = 0x1; /* Player Regional Code Mask. Region free! */
262 (vm->state).registers.SPRM[14] = 0x100; /* Try Pan&Scan */
263 299
264 (vm->state).pgN = 0; 300 (vm->state).pgN = 0;
265 (vm->state).cellN = 0; 301 (vm->state).cellN = 0;
266 (vm->state).cell_restart = 0; 302 (vm->state).cell_restart = 0;
267 303
268 (vm->state).domain = FP_DOMAIN; 304 (vm->state).domain = FP_DOMAIN;
269 (vm->state).rsm_vtsN = 0; 305 (vm->state).rsm_vtsN = 0;
270 (vm->state).rsm_cellN = 0; 306 (vm->state).rsm_cellN = 0;
271 (vm->state).rsm_blockN = 0; 307 (vm->state).rsm_blockN = 0;
272 308
273 (vm->state).vtsN = -1; 309 (vm->state).vtsN = -1;
274 310
275 if (vm->dvd && dvdroot) { 311 if (vm->dvd && dvdroot) {
276 /* a new dvd device has been requested */ 312 /* a new dvd device has been requested */
277 vm_stop(vm); 313 vm_stop(vm);
278 } 314 }
279 if (!vm->dvd) { 315 if (!vm->dvd) {
280 vm->dvd = DVDOpen(dvdroot); 316 vm->dvd = DVDOpen(dvdroot);
281 if(!vm->dvd) { 317 if(!vm->dvd) {
282 fprintf(MSG_OUT, "libdvdnav: vm: faild to open/read the DVD\n"); 318 fprintf(MSG_OUT, "libdvdnav: vm: faild to open/read the DVD\n");
283 return -1; 319 return 0;
284 } 320 }
285 dvd_read_name(vm, dvdroot); 321 dvd_read_name(vm, dvdroot);
286 vm->map = remap_loadmap( vm->dvd_name); 322 vm->map = remap_loadmap(vm->dvd_name);
287
288 vm->vmgi = ifoOpenVMGI(vm->dvd); 323 vm->vmgi = ifoOpenVMGI(vm->dvd);
289 if(!vm->vmgi) { 324 if(!vm->vmgi) {
290 fprintf(MSG_OUT, "libdvdnav: vm: faild to read VIDEO_TS.IFO\n"); 325 fprintf(MSG_OUT, "libdvdnav: vm: faild to read VIDEO_TS.IFO\n");
291 return -1; 326 return 0;
292 } 327 }
293 if(!ifoRead_FP_PGC(vm->vmgi)) { 328 if(!ifoRead_FP_PGC(vm->vmgi)) {
294 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_FP_PGC failed\n"); 329 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_FP_PGC failed\n");
295 return -1; 330 return 0;
296 } 331 }
297 if(!ifoRead_TT_SRPT(vm->vmgi)) { 332 if(!ifoRead_TT_SRPT(vm->vmgi)) {
298 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_TT_SRPT failed\n"); 333 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_TT_SRPT failed\n");
299 return -1; 334 return 0;
300 } 335 }
301 if(!ifoRead_PGCI_UT(vm->vmgi)) { 336 if(!ifoRead_PGCI_UT(vm->vmgi)) {
302 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PGCI_UT failed\n"); 337 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PGCI_UT failed\n");
303 return -1; 338 return 0;
304 } 339 }
305 if(!ifoRead_PTL_MAIT(vm->vmgi)) { 340 if(!ifoRead_PTL_MAIT(vm->vmgi)) {
306 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PTL_MAIT failed\n"); 341 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PTL_MAIT failed\n");
307 ; /* return -1; Not really used for now.. */ 342 /* return 0; Not really used for now.. */
308 } 343 }
309 if(!ifoRead_VTS_ATRT(vm->vmgi)) { 344 if(!ifoRead_VTS_ATRT(vm->vmgi)) {
310 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VTS_ATRT failed\n"); 345 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VTS_ATRT failed\n");
311 ; /* return -1; Not really used for now.. */ 346 /* return 0; Not really used for now.. */
312 } 347 }
313 if(!ifoRead_VOBU_ADMAP(vm->vmgi)) { 348 if(!ifoRead_VOBU_ADMAP(vm->vmgi)) {
314 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VOBU_ADMAP vgmi failed\n"); 349 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VOBU_ADMAP vgmi failed\n");
315 ; /* return -1; Not really used for now.. */ 350 /* return 0; Not really used for now.. */
316 } 351 }
317 /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */ 352 /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */
318 } 353 }
319 else fprintf(MSG_OUT, "libdvdnav: vm: reset\n");
320 if (vm->vmgi) { 354 if (vm->vmgi) {
321 fprintf(MSG_OUT, "libdvdnav: DVD disk reports itself with Region mask 0x%08x. Maybe region %u.\n", 355 int i, mask;
322 vm->vmgi->vmgi_mat->vmg_category, 356 fprintf(MSG_OUT, "libdvdnav: DVD disk reports itself with Region mask 0x%08x. Regions:",
323 (((vm->vmgi->vmgi_mat->vmg_category >> 16) ^ 0xff) & 0xff) ); 357 vm->vmgi->vmgi_mat->vmg_category);
324 } 358 for (i = 1, mask = 1; i <= 8; i++, mask <<= 1)
325 return 0; 359 if (((vm->vmgi->vmgi_mat->vmg_category >> 16) & mask) == 0)
326 } 360 fprintf(MSG_OUT, " %d", i);
327 361 fprintf(MSG_OUT, "\n");
328 /* FIXME TODO XXX $$$ Handle error condition too... */ 362 }
329 int vm_start(vm_t *vm) 363 return 1;
330 { 364 }
331 link_t link_values; 365
332 366
333 /* Set pgc to FP(First Play) pgc */ 367 /* regular playback */
334 set_FP_PGC(vm); 368
335 link_values = play_PGC(vm); 369 void vm_position_get(vm_t *vm, vm_position_t *position) {
336 link_values = process_command(vm,link_values);
337 assert(link_values.command == PlayThis);
338 (vm->state).blockN = link_values.data1;
339 #ifdef TRACE
340 fprintf(MSG_OUT, "libdvdnav: vm_start: blockN set to 0x%x\n", (vm->state).blockN);
341 #endif
342 assert( (vm->state).blockN == 0 );
343
344
345 return 0; /* ?? */
346 }
347
348 int vm_position_get(vm_t *vm, vm_position_t *position) {
349 position->button = (vm->state).HL_BTNN_REG >> 10; 370 position->button = (vm->state).HL_BTNN_REG >> 10;
371 position->vts = (vm->state).vtsN;
372 position->domain = (vm->state).domain;
350 position->spu_channel = (vm->state).SPST_REG; 373 position->spu_channel = (vm->state).SPST_REG;
351 position->audio_channel = (vm->state).AST_REG; 374 position->audio_channel = (vm->state).AST_REG;
352 position->angle_channel = (vm->state).AGL_REG; 375 position->angle_channel = (vm->state).AGL_REG;
353 position->hop_channel = vm->hop_channel; /* Increases by one on each hop */ 376 position->hop_channel = vm->hop_channel; /* Increases by one on each hop */
354 position->vts = (vm->state).vtsN;
355 position->domain = (vm->state).domain;
356 position->cell = (vm->state).cellN; 377 position->cell = (vm->state).cellN;
357 position->cell_restart = (vm->state).cell_restart; 378 position->cell_restart = (vm->state).cell_restart;
379 position->cell_start = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector;
358 position->still = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].still_time; 380 position->still = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].still_time;
359 position->vobu_start = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector; 381 position->block = (vm->state).blockN;
360 position->vobu_next = (vm->state).blockN;
361 382
362 /* still already detrmined or not at PGC end */ 383 /* still already detrmined or not at PGC end */
363 if (position->still || (vm->state).cellN < (vm->state).pgc->nr_of_cells) 384 if (position->still || (vm->state).cellN < (vm->state).pgc->nr_of_cells)
364 return 1; 385 return;
365 /* handle PGC stills */ 386 /* handle PGC stills */
366 if ((vm->state).pgc->still_time) { 387 if ((vm->state).pgc->still_time) {
367 position->still = (vm->state).pgc->still_time; 388 position->still = (vm->state).pgc->still_time;
368 return 1; 389 return;
369 } 390 }
370 /* This is a rough fix for some strange still situations on some strange DVDs. 391 /* This is a rough fix for some strange still situations on some strange DVDs.
371 * There are discs (like the German "Back to the Future" RC2) where the only 392 * There are discs (like the German "Back to the Future" RC2) where the only
372 * indication of a still is a cell playback time higher than the time the frames 393 * indication of a still is a cell playback time higher than the time the frames
373 * in this cell actually take to play (like 1 frame with 1 minute playback time). 394 * in this cell actually take to play (like 1 frame with 1 minute playback time).
387 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0xf0) * 10; 408 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0xf0) * 10;
388 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0x0f) * 1; 409 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0x0f) * 1;
389 if (time > 0xff) time = 0xff; 410 if (time > 0xff) time = 0xff;
390 position->still = time; 411 position->still = time;
391 } 412 }
392 413 }
414
415 void vm_get_next_cell(vm_t *vm) {
416 process_command(vm, play_Cell_post(vm));
417 }
418
419
420 /* Jumping */
421
422 int vm_jump_pg(vm_t *vm, int pg) {
423 (vm->state).pgN = pg;
424 process_command(vm, play_PG(vm));
393 return 1; 425 return 1;
394 } 426 }
395 427
396 int vm_position_print(vm_t *vm, vm_position_t *position) { 428 int vm_jump_title_part(vm_t *vm, int title, int part) {
397 fprintf(MSG_OUT, "libdvdnav: But=%x Spu=%x Aud=%x Ang=%x Hop=%x vts=%x dom=%x cell=%x cell_restart=%x still=%x start=%x next=%x\n", 429 int vtsN;
398 position->button, 430
399 position->spu_channel, 431 vtsN = vm->vmgi->tt_srpt->title[title - 1].title_set_nr;
400 position->audio_channel, 432
401 position->angle_channel, 433 if(!set_VTS_PTT(vm, vtsN, title, part))
402 position->hop_channel, 434 return 0;
403 position->vts, 435 process_command(vm, play_PGC_PG(vm, (vm->state).pgN));
404 position->domain, 436 vm->hop_channel++;
405 position->cell,
406 position->cell_restart,
407 position->still,
408 position->vobu_start,
409 position->vobu_next);
410 return 1; 437 return 1;
411 } 438 }
412 439
413 440 int vm_jump_top_pg(vm_t *vm) {
414 int vm_start_title(vm_t *vm, int tt) { 441 process_command(vm, play_PG(vm));
415 link_t link_values; 442 return 1;
416 443 }
417 set_TT(vm, tt); 444
418 link_values = play_PGC(vm); 445 int vm_jump_next_pg(vm_t *vm) {
419 link_values = process_command(vm, link_values);
420 assert(link_values.command == PlayThis);
421 (vm->state).blockN = link_values.data1;
422 #ifdef TRACE
423 fprintf(MSG_OUT, "libdvdnav: vm_start_title: blockN set to 0x%x\n", (vm->state).blockN);
424 #endif
425 assert( (vm->state).blockN == 0 );
426
427 return 0; /* ?? */
428 }
429
430 int vm_jump_prog(vm_t *vm, int pr) {
431 link_t link_values;
432
433
434 set_PGC(vm, get_PGCN(vm));
435 (vm->state).pgN = pr; /* ?? set_PGC() clobbers pgN */
436 link_values = play_PG(vm);
437 link_values = process_command(vm, link_values);
438 assert(link_values.command == PlayThis);
439 (vm->state).blockN = link_values.data1;
440 #ifdef TRACE
441 fprintf(MSG_OUT, "libdvdnav: vm_jump_prog: blockN set to 0x%x\n", (vm->state).blockN);
442 #endif
443 assert( (vm->state).blockN == 0 );
444
445 return 0; /* ?? */
446 }
447
448 int vm_eval_cmd(vm_t *vm, vm_cmd_t *cmd)
449 {
450 link_t link_values;
451
452 if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values)) {
453 link_values = process_command(vm, link_values);
454 assert(link_values.command == PlayThis);
455 (vm->state).blockN = link_values.data1;
456 #ifdef TRACE
457 fprintf(MSG_OUT, "libdvdnav: vm_eval_cmd: blockN set to 0x%x\n", (vm->state).blockN);
458 #endif
459 return link_values.data2; /* return if there acutally was a jump */
460 } else {
461 return 0; /* It updated some state thats all... */
462 }
463 }
464
465 int vm_get_next_cell(vm_t *vm)
466 {
467 link_t link_values;
468 link_values = play_Cell_post(vm);
469 link_values = process_command(vm,link_values);
470 assert(link_values.command == PlayThis);
471 (vm->state).blockN = link_values.data1;
472 #ifdef TRACE
473 fprintf(MSG_OUT, "libdvdnav: vm_get_next_cell: blockN set to 0x%x\n", (vm->state).blockN);
474 #endif
475 assert( (vm->state).blockN == 0 );
476
477 return 0; /* ?? */
478 }
479
480 int vm_top_pg(vm_t *vm)
481 {
482 link_t link_values;
483 link_values = play_PG(vm);
484 link_values = process_command(vm,link_values);
485 assert(link_values.command == PlayThis);
486 (vm->state).blockN = link_values.data1;
487 #ifdef TRACE
488 fprintf(MSG_OUT, "libdvdnav: vm_top_pg: blockN set to 0x%x\n", (vm->state).blockN);
489 #endif
490 assert( (vm->state).blockN == 0 );
491
492 return 1; /* Jump */
493 }
494
495 int vm_go_up(vm_t *vm)
496 {
497 link_t link_values;
498
499 if(set_PGC(vm, (vm->state).pgc->goup_pgc_nr))
500 assert(0);
501
502 link_values = play_PGC(vm);
503 link_values = process_command(vm,link_values);
504 assert(link_values.command == PlayThis);
505 (vm->state).blockN = link_values.data1;
506 #ifdef TRACE
507 fprintf(MSG_OUT, "libdvdnav: vm_go_up: blockN set to 0x%x\n", (vm->state).blockN);
508 #endif
509 assert( (vm->state).blockN == 0 );
510
511 return 1; /* Jump */
512 }
513
514 int vm_next_pg(vm_t *vm)
515 {
516 if((vm->state).pgN >= (vm->state).pgc->nr_of_programs) { 446 if((vm->state).pgN >= (vm->state).pgc->nr_of_programs) {
517 /* last program -> move to first program of next PGC */ 447 /* last program -> move to TailPGC */
518 if ((vm->state).pgc->next_pgc_nr != 0 && set_PGC(vm, (vm->state).pgc->next_pgc_nr) == 0) { 448 process_command(vm, play_PGC_post(vm));
519 vm_jump_prog(vm, 1);
520 return 1;
521 }
522 /* something failed, try to move to the cell after the last */
523 (vm->state).cellN = (vm->state).pgc->nr_of_cells;
524 vm_get_next_cell(vm);
525 return 1; 449 return 1;
526 } else { 450 } else {
527 vm_jump_prog(vm, (vm->state).pgN + 1); 451 vm_jump_pg(vm, (vm->state).pgN + 1);
528 return 1; 452 return 1;
529 } 453 }
530 } 454 }
531 455
532 int vm_prev_pg(vm_t *vm) 456 int vm_jump_prev_pg(vm_t *vm) {
533 {
534 if ((vm->state).pgN <= 1) { 457 if ((vm->state).pgN <= 1) {
535 /* first program -> move to last program of previous PGC */ 458 /* first program -> move to last program of previous PGC */
536 if ((vm->state).pgc->prev_pgc_nr != 0 && set_PGC(vm, (vm->state).pgc->prev_pgc_nr) == 0) { 459 if ((vm->state).pgc->prev_pgc_nr && set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) {
537 vm_jump_prog(vm, (vm->state).pgc->nr_of_programs); 460 process_command(vm, play_PGC(vm));
538 return 1; 461 return 1;
539 } 462 }
540 return 0; 463 return 0;
541 } else { 464 } else {
542 vm_jump_prog(vm, (vm->state).pgN - 1); 465 vm_jump_pg(vm, (vm->state).pgN - 1);
543 return 1; 466 return 1;
544 } 467 }
545 } 468 }
546 469
547 /* Get the current title and part from the current playing position. */ 470 int vm_jump_up(vm_t *vm) {
548 /* returns S_ERR if not in the VTS_DOMAIN */ 471 if((vm->state).pgc->goup_pgc_nr && set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) {
549 /* FIXME: Should we do some locking here ? */ 472 process_command(vm, play_PGC(vm));
550 int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) 473 return 1;
551 { 474 }
475 return 0;
476 }
477
478 int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid) {
479 domain_t old_domain = (vm->state).domain;
480
481 switch ((vm->state).domain) {
482 case VTS_DOMAIN:
483 set_RSMinfo(vm, 0, (vm->state).blockN);
484 /* FALL THROUGH */
485 case VTSM_DOMAIN:
486 case VMGM_DOMAIN:
487 switch(menuid) {
488 case DVD_MENU_Title:
489 (vm->state).domain = VMGM_DOMAIN;
490 break;
491 case DVD_MENU_Root:
492 case DVD_MENU_Subpicture:
493 case DVD_MENU_Audio:
494 case DVD_MENU_Angle:
495 case DVD_MENU_Part:
496 (vm->state).domain = VTSM_DOMAIN;
497 break;
498 }
499 if(get_PGCIT(vm) && set_MENU(vm, menuid)) {
500 process_command(vm, play_PGC(vm));
501 return 1; /* Jump */
502 } else {
503 (vm->state).domain = old_domain;
504 }
505 break;
506 case FP_DOMAIN: /* FIXME XXX $$$ What should we do here? */
507 break;
508 }
509
510 return 0;
511 }
512
513 int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd) {
514 link_t link_values;
515
516 if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values))
517 return process_command(vm, link_values);
518 else
519 return 0; /* It updated some state thats all... */
520 }
521
522
523 /* getting information */
524
525 int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) {
552 vts_ptt_srpt_t *vts_ptt_srpt; 526 vts_ptt_srpt_t *vts_ptt_srpt;
553 int title=0, part=0, ttn=0; 527 int title, part = 0, vts_ttn;
554 int found = 0; 528 int found;
555 int16_t pgcN, pgN; 529 int16_t pgcN, pgN;
556 530
557 if((!vm) || (!vm->vtsi) )
558 return S_ERR;
559
560 if(!title_result || !part_result) {
561 fprintf(MSG_OUT, "libdvdnav:vm_get_current_title_part: Passed a NULL pointer");
562 return S_ERR;
563 }
564
565 if(!(vm->state.pgc) )
566 return S_ERR;
567 if (vm->state.domain != VTS_DOMAIN)
568 return S_ERR;
569 vts_ptt_srpt = vm->vtsi->vts_ptt_srpt; 531 vts_ptt_srpt = vm->vtsi->vts_ptt_srpt;
570 pgcN = get_PGCN(vm); 532 pgcN = get_PGCN(vm);
571 pgN = vm->state.pgN; 533 pgN = vm->state.pgN;
572 printf("VTS_PTT_SRPT - PGC: %3i PG: %3i\n", 534
573 pgcN, pgN); 535 found = 0;
574 536 for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) {
575 for(ttn=0;( (ttn < vts_ptt_srpt->nr_of_srpts) && (found == 0) );ttn++) { 537 for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) {
576 for(part=0;((part < vts_ptt_srpt->title[ttn].nr_of_ptts) && (found == 0));part++) { 538 if ((vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) &&
577 if ( (vts_ptt_srpt->title[ttn].ptt[part].pgcn == pgcN) && 539 (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN )) {
578 (vts_ptt_srpt->title[ttn].ptt[part].pgn == pgN ) ) {
579 found = 1; 540 found = 1;
580 break; 541 break;
581 } 542 }
582 } 543 }
583 if (found != 0) break; 544 if (found) break;
584 } 545 }
585 ttn++; 546 vts_ttn++;
586 part++; 547 part++;
587 for(title=0; title < vm->vmgi->tt_srpt->nr_of_srpts; title++){ 548
588 if( (vm->vmgi->tt_srpt->title[title].vts_ttn == ttn) && 549 title = get_TT(vm, vm->state.vtsN, vts_ttn);
589 (vm->vmgi->tt_srpt->title[title].title_set_nr == vm->state.vtsN)){ 550
590 found = 1; 551 #ifdef TRACE
591 break; 552 if (title) {
592 }
593 }
594 title++;
595
596 if (found == 1) {
597 fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n"); 553 fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n");
598 fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n", 554 fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n",
599 title, part, 555 title, part,
600 vts_ptt_srpt->title[ttn-1].ptt[part-1].pgcn , 556 vts_ptt_srpt->title[ttn-1].ptt[part-1].pgcn ,
601 vts_ptt_srpt->title[ttn-1].ptt[part-1].pgn ); 557 vts_ptt_srpt->title[ttn-1].ptt[part-1].pgn );
602 } else { 558 } else {
603 fprintf(MSG_OUT, "libdvdnav: ************ this chapter NOT FOUND!\n"); 559 fprintf(MSG_OUT, "libdvdnav: ************ this chapter NOT FOUND!\n");
604 return S_ERR; 560 }
605 } 561 #endif
562 if (!title)
563 return 0;
606 *title_result = title; 564 *title_result = title;
607 *part_result = part; 565 *part_result = part;
608 return 1; 566 return 1;
609 } 567 }
610 568
611 /* Jump to a particlar part of a particlar title on this vts */ 569 /* Return the substream id for 'logical' audio stream audioN.
612 /* returns S_ERR if not in the VTS_DOMAIN */ 570 * 0 <= audioN < 8
613 /* FIXME: Should we do some locking here ? */
614 int vm_jump_title_part(vm_t *vm, int title, int part) {
615 link_t link_values;
616 int vtsN;
617
618 if((!vm) || (!vm->vtsi) || (!vm->vmgi) )
619 return S_ERR;
620
621 if(!(vm->state.pgc) )
622 return S_ERR;
623 /* if ( (title < 1) || (title > vm->vtsi->vts_ptt_srpt->nr_of_srpts) ||
624 (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[title].nr_of_ptts) ) {
625 return S_ERR;
626 }
627 */ 571 */
628 if( (title < 1) || (title > vm->vmgi->tt_srpt->nr_of_srpts) ) { 572 int vm_get_audio_stream(vm_t *vm, int audioN) {
629 return S_ERR;
630 }
631 vtsN = vm->vmgi->tt_srpt->title[title - 1].title_set_nr;
632
633 if(set_VTS_PTT(vm, vtsN, title, part) == -1) {
634 return S_ERR;
635 }
636 link_values = play_PGC_PG( vm, (vm->state).pgN );
637 link_values = process_command(vm,link_values);
638 assert(link_values.command == PlayThis);
639 (vm->state).blockN = link_values.data1;
640 assert( (vm->state).blockN == 0 );
641 vm->hop_channel++;
642
643 fprintf(MSG_OUT, "libdvdnav: previous chapter done\n");
644
645 return 1;
646 }
647
648 static domain_t menuid2domain(DVDMenuID_t menuid)
649 {
650 domain_t result = VTSM_DOMAIN; /* Really shouldn't have to.. */
651
652 switch(menuid) {
653 case DVD_MENU_Title:
654 result = VMGM_DOMAIN;
655 break;
656 case DVD_MENU_Root:
657 case DVD_MENU_Subpicture:
658 case DVD_MENU_Audio:
659 case DVD_MENU_Angle:
660 case DVD_MENU_Part:
661 result = VTSM_DOMAIN;
662 break;
663 }
664
665 return result;
666 }
667
668 int vm_menu_call(vm_t *vm, DVDMenuID_t menuid, int block)
669 {
670 domain_t old_domain;
671 link_t link_values;
672
673 /* Should check if we are allowed/can acces this menu */
674
675
676 /* FIXME XXX $$$ How much state needs to be restored
677 * when we fail to find a menu? */
678
679 old_domain = (vm->state).domain;
680
681 switch((vm->state).domain) {
682 case VTS_DOMAIN:
683 saveRSMinfo(vm, 0, block);
684 /* FALL THROUGH */
685 case VTSM_DOMAIN:
686 case VMGM_DOMAIN:
687 (vm->state).domain = menuid2domain(menuid);
688 if(get_PGCIT(vm) != NULL && set_MENU(vm, menuid) != -1) {
689 link_values = play_PGC(vm);
690 link_values = process_command(vm, link_values);
691 assert(link_values.command == PlayThis);
692 (vm->state).blockN = link_values.data1;
693 #ifdef TRACE
694 fprintf(MSG_OUT, "libdvdnav: vm_menu_call: blockN set to 0x%x\n", (vm->state).blockN);
695 #endif
696 assert( (vm->state).blockN == 0 );
697 return 1; /* Jump */
698 } else {
699 (vm->state).domain = old_domain;
700 }
701 break;
702 case FP_DOMAIN: /* FIXME XXX $$$ What should we do here? */
703 break;
704 }
705
706 return 0;
707 }
708
709
710 int vm_resume(vm_t *vm)
711 {
712 int i;
713 link_t link_values;
714
715 /* Check and see if there is any rsm info!! */
716 if((vm->state).rsm_vtsN == 0) {
717 return 0;
718 }
719
720 (vm->state).domain = VTS_DOMAIN;
721 ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN);
722 set_PGC(vm, (vm->state).rsm_pgcN);
723
724 /* These should never be set in SystemSpace and/or MenuSpace */
725 /* (vm->state).TTN_REG = (vm->state).rsm_tt; */
726 /* (vm->state).TT_PGCN_REG = (vm->state).rsm_pgcN; */
727 /* (vm->state).HL_BTNN_REG = (vm->state).rsm_btnn; */
728 for(i = 0; i < 5; i++) {
729 (vm->state).registers.SPRM[4 + i] = (vm->state).rsm_regs[i];
730 }
731
732 if((vm->state).rsm_cellN == 0) {
733 assert((vm->state).cellN); /* Checking if this ever happens */
734 (vm->state).pgN = 1;
735 link_values = play_PG(vm);
736 link_values = process_command(vm, link_values);
737 assert(link_values.command == PlayThis);
738 (vm->state).blockN = link_values.data1;
739 #ifdef TRACE
740 fprintf(MSG_OUT, "libdvdnav: vm_resume1: blockN set to 0x%x\n", (vm->state).blockN);
741 #endif
742 assert( (vm->state).blockN == 0 );
743 } else {
744 (vm->state).cellN = (vm->state).rsm_cellN;
745 (vm->state).blockN = (vm->state).rsm_blockN;
746 #ifdef TRACE
747 fprintf(MSG_OUT, "libdvdnav: vm_resume2: blockN set to 0x%x\n", (vm->state).blockN);
748 #endif
749 /* (vm->state).pgN = ?? does this gets the righ value in play_Cell, no! */
750 if(set_PGN(vm)) {
751 /* Were at or past the end of the PGC, should not happen for a RSM */
752 assert(0);
753 play_PGC_post(vm);
754 }
755 }
756
757 return 1; /* Jump */
758 }
759
760 /**
761 * Return the substream id for 'logical' audio stream audioN.
762 * 0 <= audioN < 8
763 */
764 int vm_get_audio_stream(vm_t *vm, int audioN)
765 {
766 int streamN = -1; 573 int streamN = -1;
574
767 #ifdef TRACE 575 #ifdef TRACE
768 fprintf(MSG_OUT, "libdvdnav: vm.c:get_audio_stream audioN=%d\n",audioN); 576 fprintf(MSG_OUT, "libdvdnav: vm.c:get_audio_stream audioN=%d\n",audioN);
769 #endif 577 #endif
770 if((vm->state).domain == VTSM_DOMAIN 578
771 || (vm->state).domain == VMGM_DOMAIN 579 if((vm->state).domain != VTS_DOMAIN)
772 || (vm->state).domain == FP_DOMAIN) {
773 audioN = 0; 580 audioN = 0;
774 }
775 581
776 if(audioN < 8) { 582 if(audioN < 8) {
777 /* Is there any contol info for this logical stream */ 583 /* Is there any contol info for this logical stream */
778 if((vm->state).pgc->audio_control[audioN] & (1<<15)) { 584 if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
779 streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07; 585 streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07;
780 } 586 }
781 } 587 }
782 588
783 if((vm->state).domain == VTSM_DOMAIN 589 if((vm->state).domain != VTS_DOMAIN && streamN == -1)
784 || (vm->state).domain == VMGM_DOMAIN 590 streamN = 0;
785 || (vm->state).domain == FP_DOMAIN) { 591
786 if(streamN == -1) 592 /* FIXME: Should also check in vtsi/vmgi status what kind of stream
787 streamN = 0;
788 }
789
790 /* Should also check in vtsi/vmgi status that what kind of stream
791 * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */ 593 * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */
792 return streamN; 594 return streamN;
793 } 595 }
794 596
795 /** 597 /* Return the substream id for 'logical' subpicture stream subpN and given mode.
796 * Return the substream id for 'logical' subpicture stream subpN and given mode.
797 * 0 <= subpN < 32 598 * 0 <= subpN < 32
798 * mode == 0 - widescreen 599 * mode == 0 - widescreen
799 * mode == 1 - letterbox 600 * mode == 1 - letterbox
800 * mode == 2 - pan&scan 601 * mode == 2 - pan&scan
801 */ 602 */
802 int vm_get_subp_stream(vm_t *vm, int subpN, int mode) 603 int vm_get_subp_stream(vm_t *vm, int subpN, int mode) {
803 {
804 int streamN = -1; 604 int streamN = -1;
805 int source_aspect = vm_get_video_aspect(vm); 605 int source_aspect = vm_get_video_aspect(vm);
806 606
807 if((vm->state).domain == VTSM_DOMAIN 607 if((vm->state).domain != VTS_DOMAIN)
808 || (vm->state).domain == VMGM_DOMAIN
809 || (vm->state).domain == FP_DOMAIN) {
810 subpN = 0; 608 subpN = 0;
811 }
812 609
813 if(subpN < 32) { /* a valid logical stream */ 610 if(subpN < 32) { /* a valid logical stream */
814 /* Is this logical stream present */ 611 /* Is this logical stream present */
815 if((vm->state).pgc->subp_control[subpN] & (1<<31)) { 612 if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
816 if(source_aspect == 0) /* 4:3 */ 613 if(source_aspect == 0) /* 4:3 */
827 streamN = (vm->state).pgc->subp_control[subpN] & 0x1f; 624 streamN = (vm->state).pgc->subp_control[subpN] & 0x1f;
828 } 625 }
829 } 626 }
830 } 627 }
831 628
832 /* Paranoia.. if no stream select 0 anyway */ 629 if((vm->state).domain != VTS_DOMAIN && streamN == -1)
833 /* I am not paranoid */ 630 streamN = 0;
834 /* if((vm->state).domain == VTSM_DOMAIN 631
835 || (vm->state).domain == VMGM_DOMAIN 632 /* FIXME: Should also check in vtsi/vmgi status what kind of stream it is. */
836 || (vm->state).domain == FP_DOMAIN) {
837 if(streamN == -1)
838 streamN = 0;
839 }
840 */
841 /* Should also check in vtsi/vmgi status that what kind of stream it is. */
842 return streamN; 633 return streamN;
843 } 634 }
844 635
845 int vm_get_subp_active_stream(vm_t *vm, int mode) 636 int vm_get_audio_active_stream(vm_t *vm) {
846 { 637 int audioN;
638 int streamN;
639 audioN = (vm->state).AST_REG ;
640 streamN = vm_get_audio_stream(vm, audioN);
641
642 /* If no such stream, then select the first one that exists. */
643 if(streamN == -1) {
644 for(audioN = 0; audioN < 8; audioN++) {
645 if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
646 if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0)
647 break;
648 }
649 }
650 }
651
652 return streamN;
653 }
654
655 int vm_get_subp_active_stream(vm_t *vm, int mode) {
847 int subpN; 656 int subpN;
848 int streamN; 657 int streamN;
849 subpN = (vm->state).SPST_REG & ~0x40; 658 subpN = (vm->state).SPST_REG & ~0x40;
850 streamN = vm_get_subp_stream(vm, subpN, mode); 659 streamN = vm_get_subp_stream(vm, subpN, mode);
851 660
852 /* If no such stream, then select the first one that exists. */ 661 /* If no such stream, then select the first one that exists. */
853 if(streamN == -1) { 662 if(streamN == -1) {
854 for(subpN = 0; subpN < 32; subpN++) { 663 for(subpN = 0; subpN < 32; subpN++) {
855 if((vm->state).pgc->subp_control[subpN] & (1<<31)) { 664 if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
856 665 if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0)
857 streamN = vm_get_subp_stream(vm, subpN, mode); 666 break;
858 break;
859 } 667 }
860 } 668 }
861 } 669 }
862 670
863 /* We should instead send the on/off status to the spudecoder / mixer */ 671 if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40))
864 /* If we are in the title domain see if the spu mixing is on */ 672 /* Bit 7 set means hide, and only let Forced display show */
865 if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40)) { 673 return (streamN | 0x80);
866 /* Bit 7 set means hide, and only let Forced display show */ 674 else
867 return (streamN | 0x80);
868 } else {
869 return streamN; 675 return streamN;
870 } 676 }
871 } 677
872 678 void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) {
873 int vm_get_audio_active_stream(vm_t *vm)
874 {
875 int audioN;
876 int streamN;
877 audioN = (vm->state).AST_REG ;
878 streamN = vm_get_audio_stream(vm, audioN);
879
880 /* If no such stream, then select the first one that exists. */
881 if(streamN == -1) {
882 for(audioN = 0; audioN < 8; audioN++) {
883 if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
884 streamN = vm_get_audio_stream(vm, audioN);
885 break;
886 }
887 }
888 }
889
890 return streamN;
891 }
892
893
894 void vm_get_angle_info(vm_t *vm, int *num_avail, int *current)
895 {
896 *num_avail = 1; 679 *num_avail = 1;
897 *current = 1; 680 *current = 1;
898 681
899 if((vm->state).domain == VTS_DOMAIN) { 682 if((vm->state).domain == VTS_DOMAIN) {
900 /* TTN_REG does not allways point to the correct title.. */
901 title_info_t *title; 683 title_info_t *title;
684 /* TTN_REG does not allways point to the correct title.. */
902 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) 685 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
903 return; 686 return;
904 title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1]; 687 title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1];
905 if(title->title_set_nr != (vm->state).vtsN || 688 if(title->title_set_nr != (vm->state).vtsN ||
906 title->vts_ttn != (vm->state).VTS_TTN_REG) 689 title->vts_ttn != (vm->state).VTS_TTN_REG)
907 return; 690 return;
908 *num_avail = title->nr_of_angles; 691 *num_avail = title->nr_of_angles;
909 *current = (vm->state).AGL_REG; 692 *current = (vm->state).AGL_REG;
910 if(*current > *num_avail) /* Is this really a good idea? */ 693 }
911 *current = *num_avail; 694 }
912 } 695
913 } 696 #if 0
914 697 /* currently unused */
915 698 void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) {
916 void vm_get_audio_info(vm_t *vm, int *num_avail, int *current) 699 switch ((vm->state).domain) {
917 { 700 case VTS_DOMAIN:
918 if((vm->state).domain == VTS_DOMAIN) {
919 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams; 701 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams;
920 *current = (vm->state).AST_REG; 702 *current = (vm->state).AST_REG;
921 } else if((vm->state).domain == VTSM_DOMAIN) { 703 break;
704 case VTSM_DOMAIN:
922 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */ 705 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */
923 *current = 1; 706 *current = 1;
924 } else if((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN) { 707 break;
708 case VMGM_DOMAIN:
709 case FP_DOMAIN:
925 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */ 710 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */
926 *current = 1; 711 *current = 1;
927 } 712 break;
928 } 713 }
929 714 }
930 void vm_get_subp_info(vm_t *vm, int *num_avail, int *current) 715
931 { 716 /* currently unused */
932 if((vm->state).domain == VTS_DOMAIN) { 717 void vm_get_subp_info(vm_t *vm, int *current, int *num_avail) {
718 switch ((vm->state).domain) {
719 case VTS_DOMAIN:
933 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams; 720 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams;
934 *current = (vm->state).SPST_REG; 721 *current = (vm->state).SPST_REG;
935 } else if((vm->state).domain == VTSM_DOMAIN) { 722 break;
723 case VTSM_DOMAIN:
936 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */ 724 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */
937 *current = 0x41; 725 *current = 0x41;
938 } else if((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN) { 726 break;
727 case VMGM_DOMAIN:
728 case FP_DOMAIN:
939 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */ 729 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */
940 *current = 0x41; 730 *current = 0x41;
941 } 731 break;
942 } 732 }
943 733 }
944 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) 734
945 { 735 /* currently unused */
946 subp_attr_t attr; 736 void vm_get_video_res(vm_t *vm, int *width, int *height) {
947 737 video_attr_t attr = vm_get_video_attr(vm);
948 if((vm->state).domain == VTS_DOMAIN) {
949 attr = vm->vtsi->vtsi_mat->vts_subp_attr[streamN];
950 } else if((vm->state).domain == VTSM_DOMAIN) {
951 attr = vm->vtsi->vtsi_mat->vtsm_subp_attr;
952 } else if((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN) {
953 attr = vm->vmgi->vmgi_mat->vmgm_subp_attr;
954 }
955 return attr;
956 }
957
958 audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN)
959 {
960 audio_attr_t attr;
961
962 if((vm->state).domain == VTS_DOMAIN) {
963 attr = vm->vtsi->vtsi_mat->vts_audio_attr[streamN];
964 } else if((vm->state).domain == VTSM_DOMAIN) {
965 attr = vm->vtsi->vtsi_mat->vtsm_audio_attr;
966 } else if((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN) {
967 attr = vm->vmgi->vmgi_mat->vmgm_audio_attr;
968 }
969 return attr;
970 }
971
972 video_attr_t vm_get_video_attr(vm_t *vm)
973 {
974 video_attr_t attr;
975
976 if((vm->state).domain == VTS_DOMAIN) {
977 attr = vm->vtsi->vtsi_mat->vts_video_attr;
978 } else if((vm->state).domain == VTSM_DOMAIN) {
979 attr = vm->vtsi->vtsi_mat->vtsm_video_attr;
980 } else if((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN) {
981 attr = vm->vmgi->vmgi_mat->vmgm_video_attr;
982 }
983 return attr;
984 }
985
986 void vm_get_video_res(vm_t *vm, int *width, int *height)
987 {
988 video_attr_t attr;
989
990 attr = vm_get_video_attr(vm);
991 738
992 if(attr.video_format != 0) 739 if(attr.video_format != 0)
993 *height = 576; 740 *height = 576;
994 else 741 else
995 *height = 480; 742 *height = 480;
1007 *width = 352; 754 *width = 352;
1008 *height /= 2; 755 *height /= 2;
1009 break; 756 break;
1010 } 757 }
1011 } 758 }
1012 759 #endif
1013 /* Must be called before domain is changed (get_PGCN()) */ 760
1014 static void saveRSMinfo(vm_t *vm, int cellN, int blockN) 761 int vm_get_video_aspect(vm_t *vm) {
1015 { 762 int aspect = vm_get_video_attr(vm).display_aspect_ratio;
1016 int i; 763
1017 764 assert(aspect == 0 || aspect == 3);
1018 if(cellN != 0) { 765 (vm->state).registers.SPRM[14] &= ~(0x3 << 10);
1019 (vm->state).rsm_cellN = cellN; 766 (vm->state).registers.SPRM[14] |= aspect << 10;
1020 (vm->state).rsm_blockN = 0; 767
1021 } else { 768 return aspect;
1022 (vm->state).rsm_cellN = (vm->state).cellN; 769 }
1023 (vm->state).rsm_blockN = blockN; 770
1024 } 771 int vm_get_video_scale_permission(vm_t *vm) {
1025 (vm->state).rsm_vtsN = (vm->state).vtsN; 772 return vm_get_video_attr(vm).permitted_df;
1026 (vm->state).rsm_pgcN = get_PGCN(vm); 773 }
1027 774
1028 /* assert((vm->state).rsm_pgcN == (vm->state).TT_PGCN_REG); for VTS_DOMAIN */ 775 video_attr_t vm_get_video_attr(vm_t *vm) {
1029 776 switch ((vm->state).domain) {
1030 for(i = 0; i < 5; i++) { 777 case VTS_DOMAIN:
1031 (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i]; 778 return vm->vtsi->vtsi_mat->vts_video_attr;
1032 } 779 case VTSM_DOMAIN:
1033 } 780 return vm->vtsi->vtsi_mat->vtsm_video_attr;
1034 781 case VMGM_DOMAIN:
1035 782 case FP_DOMAIN:
1036 783 return vm->vmgi->vmgi_mat->vmgm_video_attr;
1037 /* Figure out the correct pgN from the cell and update (vm->state). */ 784 }
1038 static int set_PGN(vm_t *vm) { 785 assert(0);
1039 int new_pgN = 0; 786 }
1040 787
1041 while(new_pgN < (vm->state).pgc->nr_of_programs 788 audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) {
1042 && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN]) 789 switch ((vm->state).domain) {
1043 new_pgN++; 790 case VTS_DOMAIN:
1044 791 return vm->vtsi->vtsi_mat->vts_audio_attr[streamN];
1045 if(new_pgN == (vm->state).pgc->nr_of_programs) /* We are at the last program */ 792 case VTSM_DOMAIN:
1046 if((vm->state).cellN > (vm->state).pgc->nr_of_cells) 793 return vm->vtsi->vtsi_mat->vtsm_audio_attr;
1047 return 1; /* We are past the last cell */ 794 case VMGM_DOMAIN:
1048 795 case FP_DOMAIN:
1049 (vm->state).pgN = new_pgN; 796 return vm->vmgi->vmgi_mat->vmgm_audio_attr;
1050 797 }
1051 if((vm->state).domain == VTS_DOMAIN) { 798 assert(0);
1052 playback_type_t *pb_ty; 799 }
1053 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) 800
1054 return 0; /* ?? */ 801 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) {
1055 pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty; 802 switch ((vm->state).domain) {
1056 if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) { 803 case VTS_DOMAIN:
1057 #if 0 /* TTN_REG can't be trusted to have a correct value here... */ 804 return vm->vtsi->vtsi_mat->vts_subp_attr[streamN];
1058 vts_ptt_srpt_t *ptt_srpt = vtsi->vts_ptt_srpt; 805 case VTSM_DOMAIN:
1059 assert((vm->state).VTS_TTN_REG <= ptt_srpt->nr_of_srpts); 806 return vm->vtsi->vtsi_mat->vtsm_subp_attr;
1060 assert(get_PGCN() == ptt_srpt->title[(vm->state).VTS_TTN_REG - 1].ptt[0].pgcn); 807 case VMGM_DOMAIN:
1061 assert(1 == ptt_srpt->title[(vm->state).VTS_TTN_REG - 1].ptt[0].pgn); 808 case FP_DOMAIN:
1062 #endif 809 return vm->vmgi->vmgi_mat->vmgm_subp_attr;
1063 (vm->state).PTTN_REG = (vm->state).pgN; 810 }
1064 } else { 811 assert(0);
1065 /* FIXME: Handle RANDOM or SHUFFLE titles. */ 812 }
1066 fprintf(MSG_OUT, "libdvdnav: RANDOM or SHUFFLE titles are NOT handled yet.\n"); 813
1067 } 814
1068 815 /* Playback control */
1069 } 816
1070 817 static link_t play_PGC(vm_t *vm) {
1071 return 0;
1072 }
1073
1074 static link_t play_PGC(vm_t *vm)
1075 {
1076 link_t link_values; 818 link_t link_values;
1077 819
1078 #ifdef TRACE 820 #ifdef TRACE
1079 fprintf(MSG_OUT, "libdvdnav: vm: play_PGC:"); 821 fprintf(MSG_OUT, "libdvdnav: vm: play_PGC:");
1080 if((vm->state).domain != FP_DOMAIN) { 822 if((vm->state).domain != FP_DOMAIN) {
1082 } else { 824 } else {
1083 fprintf(MSG_OUT, " first_play_pgc\n"); 825 fprintf(MSG_OUT, " first_play_pgc\n");
1084 } 826 }
1085 #endif 827 #endif
1086 828
1087 /* This must be set before the pre-commands are executed because they */ 829 /* This must be set before the pre-commands are executed because they
1088 /* might contain a CallSS that will save resume state */ 830 * might contain a CallSS that will save resume state */
1089 831
1090 /* FIXME: This may be only a temporary fix for something... */ 832 /* FIXME: This may be only a temporary fix for something... */
1091 (vm->state).pgN = 1; 833 (vm->state).pgN = 1;
1092 (vm->state).cellN = 0; 834 (vm->state).cellN = 0;
835 (vm->state).blockN = 0;
1093 836
1094 /* eval -> updates the state and returns either 837 /* eval -> updates the state and returns either
1095 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) 838 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)
1096 - just play video i.e first PG 839 - just play video i.e first PG
1097 (This is what happens if you fall of the end of the pre_cmds) 840 (This is what happens if you fall of the end of the pre_cmds)
1098 - or a error (are there more cases?) */ 841 - or an error (are there more cases?) */
1099 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { 842 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
1100 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, 843 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
1101 (vm->state).pgc->command_tbl->nr_of_pre, 844 (vm->state).pgc->command_tbl->nr_of_pre,
1102 &(vm->state).registers, &link_values)) { 845 &(vm->state).registers, &link_values)) {
1103 /* link_values contains the 'jump' return value */ 846 /* link_values contains the 'jump' return value */
1109 } 852 }
1110 } 853 }
1111 return play_PG(vm); 854 return play_PG(vm);
1112 } 855 }
1113 856
1114 static link_t play_PGC_PG(vm_t *vm, int pgN) 857 static link_t play_PGC_PG(vm_t *vm, int pgN) {
1115 {
1116 link_t link_values; 858 link_t link_values;
1117 859
1118 #ifdef TRACE 860 #ifdef TRACE
1119 fprintf(MSG_OUT, "libdvdnav: vm: play_PGC:"); 861 fprintf(MSG_OUT, "libdvdnav: vm: play_PGC:");
1120 if((vm->state).domain != FP_DOMAIN) { 862 if((vm->state).domain != FP_DOMAIN) {
1122 } else { 864 } else {
1123 fprintf(MSG_OUT, " first_play_pgc\n"); 865 fprintf(MSG_OUT, " first_play_pgc\n");
1124 } 866 }
1125 #endif 867 #endif
1126 868
1127 /* This must be set before the pre-commands are executed because they */ 869 /* This must be set before the pre-commands are executed because they
1128 /* might contain a CallSS that will save resume state */ 870 * might contain a CallSS that will save resume state */
1129 871
1130 /* FIXME: This may be only a temporary fix for something... */ 872 /* FIXME: This may be only a temporary fix for something... */
1131 (vm->state).pgN = pgN; 873 (vm->state).pgN = pgN;
1132 (vm->state).cellN = 0; 874 (vm->state).cellN = 0;
875 (vm->state).blockN = 0;
1133 876
1134 /* eval -> updates the state and returns either 877 /* eval -> updates the state and returns either
1135 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) 878 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)
1136 - just play video i.e first PG 879 - just play video i.e first PG
1137 (This is what happens if you fall of the end of the pre_cmds) 880 (This is what happens if you fall of the end of the pre_cmds)
1138 - or a error (are there more cases?) */ 881 - or an error (are there more cases?) */
1139 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { 882 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) {
1140 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, 883 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds,
1141 (vm->state).pgc->command_tbl->nr_of_pre, 884 (vm->state).pgc->command_tbl->nr_of_pre,
1142 &(vm->state).registers, &link_values)) { 885 &(vm->state).registers, &link_values)) {
1143 /* link_values contains the 'jump' return value */ 886 /* link_values contains the 'jump' return value */
1149 } 892 }
1150 } 893 }
1151 return play_PG(vm); 894 return play_PG(vm);
1152 } 895 }
1153 896
1154 static link_t play_PG(vm_t *vm) 897 static link_t play_PGC_post(vm_t *vm) {
1155 { 898 link_t link_values;
899
900 #ifdef TRACE
901 fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n");
902 #endif
903
904 /* FIXME: Implement PGC Stills. Currently only Cell stills work */
905 assert((vm->state).pgc->still_time == 0);
906
907 /* eval -> updates the state and returns either
908 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)
909 - just go to next PGC
910 (This is what happens if you fall of the end of the post_cmds)
911 - or an error (are there more cases?) */
912 if((vm->state).pgc->command_tbl &&
913 vmEval_CMD((vm->state).pgc->command_tbl->post_cmds,
914 (vm->state).pgc->command_tbl->nr_of_post,
915 &(vm->state).registers, &link_values)) {
916 return link_values;
917 }
918
919 #ifdef TRACE
920 fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n");
921 #endif
922 assert((vm->state).pgc->next_pgc_nr != 0);
923 /* Should end up in the STOP_DOMAIN if next_pgc is 0. */
924 if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr))
925 assert(0);
926 return play_PGC(vm);
927 }
928
929 static link_t play_PG(vm_t *vm) {
1156 #ifdef TRACE 930 #ifdef TRACE
1157 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN); 931 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN);
1158 #endif 932 #endif
1159 933
1160 assert((vm->state).pgN > 0); 934 assert((vm->state).pgN > 0);
1170 (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1]; 944 (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1];
1171 945
1172 return play_Cell(vm); 946 return play_Cell(vm);
1173 } 947 }
1174 948
1175 949 static link_t play_Cell(vm_t *vm) {
1176 static link_t play_Cell(vm_t *vm) 950 static const link_t play_this = {PlayThis, /* Block in Cell */ 0, 0, 0};
1177 { 951
1178 #ifdef TRACE 952 #ifdef TRACE
1179 fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN); 953 fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN);
1180 #endif 954 #endif
1181 955
1182 assert((vm->state).cellN > 0); 956 assert((vm->state).cellN > 0);
1187 #endif 961 #endif
1188 assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1); 962 assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1);
1189 return play_PGC_post(vm); 963 return play_PGC_post(vm);
1190 } 964 }
1191 965
1192
1193 /* Multi angle/Interleaved */ 966 /* Multi angle/Interleaved */
1194 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { 967 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
1195 case 0: /* Normal */ 968 case 0: /* Normal */
1196 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); 969 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0);
1197 break; 970 break;
1198 case 1: /* The first cell in the block */ 971 case 1: /* The first cell in the block */
1199 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) { 972 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) {
1200 case 0: /* Not part of a block */ 973 case 0: /* Not part of a block */
1201 assert(0); 974 assert(0);
1202 case 1: /* Angle block */ 975 case 1: /* Angle block */
1203 /* Loop and check each cell instead? So we don't get outsid the block. */ 976 /* Loop and check each cell instead? So we don't get outside the block? */
1204 (vm->state).cellN += (vm->state).AGL_REG - 1; 977 (vm->state).cellN += (vm->state).AGL_REG - 1;
1205 #ifdef STRICT 978 #ifdef STRICT
1206 assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells); 979 assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells);
1207 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0); 980 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0);
1208 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1); 981 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1);
1209 #endif 982 #else
1210 if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) || 983 if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) ||
1211 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) || 984 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) ||
1212 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) { 985 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) {
1213 fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n"); 986 fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n");
1214 (vm->state).cellN -= (vm->state).AGL_REG - 1; 987 (vm->state).cellN -= (vm->state).AGL_REG - 1;
1215 } 988 }
989 #endif
1216 break; 990 break;
1217 case 2: /* ?? */ 991 case 2: /* ?? */
1218 case 3: /* ?? */ 992 case 3: /* ?? */
1219 default: 993 default:
1220 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", 994 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
1221 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, 995 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
1222 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); 996 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
997 assert(0);
1223 } 998 }
1224 break; 999 break;
1225 case 2: /* Cell in the block */ 1000 case 2: /* Cell in the block */
1226 case 3: /* Last cell in the block */ 1001 case 3: /* Last cell in the block */
1227 /* These might perhaps happen for RSM or LinkC commands? */ 1002 /* These might perhaps happen for RSM or LinkC commands? */
1228 default: 1003 default:
1229 fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n"); 1004 fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n");
1230 } 1005 }
1231 1006
1232 /* Updates (vm->state).pgN and PTTN_REG */ 1007 /* Updates (vm->state).pgN and PTTN_REG */
1233 if(set_PGN(vm)) { 1008 if(!set_PGN(vm)) {
1234 /* Should not happen */ 1009 /* Should not happen */
1235 link_t tmp = {LinkTailPGC, /* No Button */ 0, 0, 0};
1236 assert(0); 1010 assert(0);
1237 return tmp; 1011 return play_PGC_post(vm);
1238 } 1012 }
1239 (vm->state).cell_restart++; 1013 (vm->state).cell_restart++;
1014 (vm->state).blockN = 0;
1015 #ifdef TRACE
1240 fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n"); 1016 fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n");
1241 { 1017 #endif
1242 link_t tmp = {PlayThis, /* Block in Cell */ 0, 0, 0}; 1018 return play_this;
1243 return tmp; 1019 }
1244 } 1020
1245 1021 static link_t play_Cell_post(vm_t *vm) {
1246 }
1247
1248 static link_t play_Cell_post(vm_t *vm)
1249 {
1250 cell_playback_t *cell; 1022 cell_playback_t *cell;
1251 1023
1252 #ifdef TRACE 1024 #ifdef TRACE
1253 fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN); 1025 fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN);
1254 #endif 1026 #endif
1277 #endif 1049 #endif
1278 if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1, 1050 if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1,
1279 &(vm->state).registers, &link_values)) { 1051 &(vm->state).registers, &link_values)) {
1280 return link_values; 1052 return link_values;
1281 } else { 1053 } else {
1054 #ifdef TRACE
1282 fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n"); 1055 fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n");
1283 /* Error ?? goto tail? goto next PG? or what? just continue? */ 1056 #endif
1284 } 1057 }
1285 } else { 1058 } else {
1059 #ifdef TRACE
1286 fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n"); 1060 fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n");
1287 1061 #endif
1288 } 1062 }
1289 } 1063 }
1290
1291 1064
1292 /* Where to continue after playing the cell... */ 1065 /* Where to continue after playing the cell... */
1293 /* Multi angle/Interleaved */ 1066 /* Multi angle/Interleaved */
1294 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { 1067 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) {
1295 case 0: /* Normal */ 1068 case 0: /* Normal */
1304 case 0: /* Not part of a block */ 1077 case 0: /* Not part of a block */
1305 assert(0); 1078 assert(0);
1306 case 1: /* Angle block */ 1079 case 1: /* Angle block */
1307 /* Skip the 'other' angles */ 1080 /* Skip the 'other' angles */
1308 (vm->state).cellN++; 1081 (vm->state).cellN++;
1309 while((vm->state).cellN <= (vm->state).pgc->nr_of_cells 1082 while((vm->state).cellN <= (vm->state).pgc->nr_of_cells &&
1310 && (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) { 1083 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) {
1311 (vm->state).cellN++; 1084 (vm->state).cellN++;
1312 } 1085 }
1313 break; 1086 break;
1314 case 2: /* ?? */ 1087 case 2: /* ?? */
1315 case 3: /* ?? */ 1088 case 3: /* ?? */
1316 default: 1089 default:
1317 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", 1090 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n",
1318 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, 1091 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode,
1319 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); 1092 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type);
1320 } 1093 assert(0);
1321 break; 1094 }
1322 } 1095 break;
1323 1096 }
1324 1097
1325 /* Figure out the correct pgN for the new cell */ 1098 /* Figure out the correct pgN for the new cell */
1326 if(set_PGN(vm)) { 1099 if(!set_PGN(vm)) {
1327 #ifdef TRACE 1100 #ifdef TRACE
1328 fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n"); 1101 fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n");
1329 #endif 1102 #endif
1330 return play_PGC_post(vm); 1103 return play_PGC_post(vm);
1331 } 1104 }
1332
1333 return play_Cell(vm); 1105 return play_Cell(vm);
1334 } 1106 }
1335 1107
1336 1108
1337 static link_t play_PGC_post(vm_t *vm) 1109 /* link processing */
1338 { 1110
1339 link_t link_values; 1111 static int process_command(vm_t *vm, link_t link_values) {
1340 1112
1341 #ifdef TRACE
1342 fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n");
1343 #endif
1344
1345 /* FIXME Implement PGC Stills. Currently only Cell stills work */
1346 assert((vm->state).pgc->still_time == 0);
1347
1348 /* eval -> updates the state and returns either
1349 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN)
1350 - or a error (are there more cases?)
1351 - if you got to the end of the post_cmds, then what ?? */
1352 if((vm->state).pgc->command_tbl &&
1353 vmEval_CMD((vm->state).pgc->command_tbl->post_cmds,
1354 (vm->state).pgc->command_tbl->nr_of_post,
1355 &(vm->state).registers, &link_values)) {
1356 return link_values;
1357 }
1358
1359 /* Or perhaps handle it here? */
1360 {
1361 link_t link_next_pgc = {LinkNextPGC, 0, 0, 0};
1362 fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n");
1363 assert((vm->state).pgc->next_pgc_nr != 0);
1364 /* Should end up in the STOP_DOMAIN if next_pgc is 0. */
1365 return link_next_pgc;
1366 }
1367 }
1368
1369
1370 static link_t process_command(vm_t *vm, link_t link_values)
1371 {
1372 /* FIXME $$$ Move this to a separate function? */
1373 vm->badness_counter++;
1374 if (vm->badness_counter > 1) fprintf(MSG_OUT, "libdvdnav: **** WARNING: process_command re-entered %d*****\n",vm->badness_counter);
1375 while(link_values.command != PlayThis) { 1113 while(link_values.command != PlayThis) {
1376 1114
1377 #ifdef TRACE 1115 #ifdef TRACE
1378 fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n"); 1116 fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n");
1379 vmPrint_LINK(link_values); 1117 vmPrint_LINK(link_values);
1380
1381 fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command, 1118 fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command,
1382 link_values.data1, link_values.data2, link_values.data3); 1119 link_values.data1, link_values.data2, link_values.data3);
1383
1384 vm_print_current_domain_state(vm); 1120 vm_print_current_domain_state(vm);
1385 fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n"); 1121 fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n");
1386 #endif 1122 #endif
1387 1123
1388 switch(link_values.command) { 1124 switch(link_values.command) {
1389 case LinkNoLink: 1125 case LinkNoLink:
1390 /* No Link => PlayThis */
1391 /* BUTTON number:data1 */ 1126 /* BUTTON number:data1 */
1392 if(link_values.data1 != 0) 1127 if(link_values.data1 != 0)
1393 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1128 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1394 link_values.command = PlayThis; 1129 return 0; /* no actual jump */
1395 link_values.data1 = (vm->state).blockN; 1130
1396 link_values.data2 = 0; /* no actual jump */
1397 return link_values;
1398
1399 case LinkTopC: 1131 case LinkTopC:
1400 /* Restart playing from the beginning of the current Cell. */ 1132 /* Restart playing from the beginning of the current Cell. */
1401 /* BUTTON number:data1 */ 1133 /* BUTTON number:data1 */
1402 fprintf(MSG_OUT, "libdvdnav: FIXME: LinkTopC. Replay current Cell\n");
1403 if(link_values.data1 != 0) 1134 if(link_values.data1 != 0)
1404 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1135 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1405 link_values = play_Cell(vm); 1136 link_values = play_Cell(vm);
1406 break; 1137 break;
1407 case LinkNextC: 1138 case LinkNextC:
1408 /* Link to Next Cell */ 1139 /* Link to Next Cell */
1409 /* BUTTON number:data1 */ 1140 /* BUTTON number:data1 */
1410 if(link_values.data1 != 0) 1141 if(link_values.data1 != 0)
1411 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1142 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1412 (vm->state).cellN += 1; /* if cellN becomes > nr_of_cells? it is handled in play_Cell() */ 1143 assert((vm->state).cellN > 1);
1144 (vm->state).cellN += 1;
1413 link_values = play_Cell(vm); 1145 link_values = play_Cell(vm);
1414 break; 1146 break;
1415 case LinkPrevC: 1147 case LinkPrevC:
1416 /* Link to Previous Cell */ 1148 /* Link to Previous Cell */
1417 /* BUTTON number:data1 */ 1149 /* BUTTON number:data1 */
1418 if(link_values.data1 != 0) 1150 if(link_values.data1 != 0)
1419 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1151 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1420 (vm->state).cellN -= 1; /* If cellN becomes < 1? it is handled in play_Cell() */ 1152 (vm->state).cellN -= 1;
1421 link_values = play_Cell(vm); 1153 link_values = play_Cell(vm);
1422 break; 1154 break;
1423 1155
1424 case LinkTopPG: 1156 case LinkTopPG:
1425 /* Link to Top Program */ 1157 /* Link to Top of Program */
1426 /* BUTTON number:data1 */ 1158 /* BUTTON number:data1 */
1427 fprintf(MSG_OUT, "libdvdnav: FIXME: LinkTopPG. This should start the current PG again.\n"); 1159 fprintf(MSG_OUT, "libdvdnav: FIXME: LinkTopPG. This should start the current PG again.\n");
1428 if(link_values.data1 != 0) 1160 if(link_values.data1 != 0)
1429 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1161 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1430 /* Does pgN always contain the current value? */
1431 link_values = play_PG(vm); 1162 link_values = play_PG(vm);
1432 break; 1163 break;
1433 case LinkNextPG: 1164 case LinkNextPG:
1434 /* Link to Next Program */ 1165 /* Link to Next Program */
1435 /* BUTTON number:data1 */ 1166 /* BUTTON number:data1 */
1436 if(link_values.data1 != 0) 1167 if(link_values.data1 != 0)
1437 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1168 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1438 /* Does pgN always contain the current value? */ 1169 (vm->state).pgN += 1;
1439 (vm->state).pgN += 1; /* FIXME: What if pgN becomes > pgc.nr_of_programs? */
1440 link_values = play_PG(vm); 1170 link_values = play_PG(vm);
1441 break; 1171 break;
1442 case LinkPrevPG: 1172 case LinkPrevPG:
1443 /* Link to Previous Program */ 1173 /* Link to Previous Program */
1444 /* BUTTON number:data1 */ 1174 /* BUTTON number:data1 */
1445 if(link_values.data1 != 0) 1175 if(link_values.data1 != 0)
1446 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1176 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1447 /* Does pgN always contain the current value? */
1448 assert((vm->state).pgN > 1); 1177 assert((vm->state).pgN > 1);
1449 (vm->state).pgN -= 1; /* FIXME: What if pgN becomes < 1? */ 1178 (vm->state).pgN -= 1;
1450 link_values = play_PG(vm); 1179 link_values = play_PG(vm);
1451 break; 1180 break;
1452 1181
1453 case LinkTopPGC: 1182 case LinkTopPGC:
1454 /* Restart playing from beginning of current Program Chain */ 1183 /* Restart playing from beginning of current Program Chain */
1455 /* BUTTON number:data1 */ 1184 /* BUTTON number:data1 */
1456 fprintf(MSG_OUT, "libdvdnav: FIXME: LinkTopPGC. Restart from beginning of current Program Chain\n");
1457 if(link_values.data1 != 0) 1185 if(link_values.data1 != 0)
1458 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1186 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1459 link_values = play_PGC(vm); 1187 link_values = play_PGC(vm);
1460 break; 1188 break;
1461 case LinkNextPGC: 1189 case LinkNextPGC:
1462 /* Link to Next Program Chain */ 1190 /* Link to Next Program Chain */
1463 /* BUTTON number:data1 */ 1191 /* BUTTON number:data1 */
1464 if(link_values.data1 != 0) 1192 if(link_values.data1 != 0)
1465 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1193 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1466 assert((vm->state).pgc->next_pgc_nr != 0); 1194 assert((vm->state).pgc->next_pgc_nr != 0);
1467 if(set_PGC(vm, (vm->state).pgc->next_pgc_nr)) 1195 if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr))
1468 assert(0); 1196 assert(0);
1469 link_values = play_PGC(vm); 1197 link_values = play_PGC(vm);
1470 break; 1198 break;
1471 case LinkPrevPGC: 1199 case LinkPrevPGC:
1472 /* Link to Previous Program Chain */ 1200 /* Link to Previous Program Chain */
1473 /* BUTTON number:data1 */ 1201 /* BUTTON number:data1 */
1474 if(link_values.data1 != 0) 1202 if(link_values.data1 != 0)
1475 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1203 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1476 assert((vm->state).pgc->prev_pgc_nr != 0); 1204 assert((vm->state).pgc->prev_pgc_nr != 0);
1477 if(set_PGC(vm, (vm->state).pgc->prev_pgc_nr)) 1205 if(!set_PGCN(vm, (vm->state).pgc->prev_pgc_nr))
1478 assert(0); 1206 assert(0);
1479 link_values = play_PGC(vm); 1207 link_values = play_PGC(vm);
1480 break; 1208 break;
1481 case LinkGoUpPGC: 1209 case LinkGoUpPGC:
1482 /* Link to GoUp??? Program Chain */ 1210 /* Link to GoUp Program Chain */
1483 /* BUTTON number:data1 */ 1211 /* BUTTON number:data1 */
1484 if(link_values.data1 != 0) 1212 if(link_values.data1 != 0)
1485 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1213 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1486 assert((vm->state).pgc->goup_pgc_nr != 0); 1214 assert((vm->state).pgc->goup_pgc_nr != 0);
1487 if(set_PGC(vm, (vm->state).pgc->goup_pgc_nr)) 1215 if(!set_PGCN(vm, (vm->state).pgc->goup_pgc_nr))
1488 assert(0); 1216 assert(0);
1489 link_values = play_PGC(vm); 1217 link_values = play_PGC(vm);
1490 break; 1218 break;
1491 case LinkTailPGC: 1219 case LinkTailPGC:
1492 /* Link to Tail??? Program Chain */ 1220 /* Link to Tail of Program Chain */
1493 /* BUTTON number:data1 */ 1221 /* BUTTON number:data1 */
1494 /* fprintf(MSG_OUT, "libdvdnav: FIXME: LinkTailPGC. What is LinkTailPGC?\n"); */
1495 if(link_values.data1 != 0) 1222 if(link_values.data1 != 0)
1496 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1223 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1497 link_values = play_PGC_post(vm); 1224 link_values = play_PGC_post(vm);
1498 break; 1225 break;
1499 1226
1500 case LinkRSM: 1227 case LinkRSM:
1501 { 1228 {
1502 /* Link to Resume */ 1229 /* Link to Resume point */
1503 int i; 1230 int i;
1231
1504 /* Check and see if there is any rsm info!! */ 1232 /* Check and see if there is any rsm info!! */
1233 assert((vm->state).rsm_vtsN);
1505 (vm->state).domain = VTS_DOMAIN; 1234 (vm->state).domain = VTS_DOMAIN;
1506 ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN); 1235 ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN);
1507 set_PGC(vm, (vm->state).rsm_pgcN); 1236 set_PGCN(vm, (vm->state).rsm_pgcN);
1508 1237
1509 /* These should never be set in SystemSpace and/or MenuSpace */ 1238 /* These should never be set in SystemSpace and/or MenuSpace */
1510 /* (vm->state).TTN_REG = rsm_tt; ?? */ 1239 /* (vm->state).TTN_REG = rsm_tt; ?? */
1511 /* (vm->state).TT_PGCN_REG = (vm->state).rsm_pgcN; ?? */ 1240 /* (vm->state).TT_PGCN_REG = (vm->state).rsm_pgcN; ?? */
1512 for(i = 0; i < 5; i++) { 1241 for(i = 0; i < 5; i++) {
1516 if(link_values.data1 != 0) 1245 if(link_values.data1 != 0)
1517 (vm->state).HL_BTNN_REG = link_values.data1 << 10; 1246 (vm->state).HL_BTNN_REG = link_values.data1 << 10;
1518 1247
1519 if((vm->state).rsm_cellN == 0) { 1248 if((vm->state).rsm_cellN == 0) {
1520 assert((vm->state).cellN); /* Checking if this ever happens */ 1249 assert((vm->state).cellN); /* Checking if this ever happens */
1521 /* assert( time/block/vobu is 0 ); */
1522 (vm->state).pgN = 1; 1250 (vm->state).pgN = 1;
1523 link_values = play_PG(vm); 1251 link_values = play_PG(vm);
1524 } else { 1252 } else {
1525 /* assert( time/block/vobu is _not_ 0 ); */ 1253 /* (vm->state).pgN = ?? this gets the righ value in set_PGN() below */
1526 /* play_Cell_at_time */
1527 /* (vm->state).pgN = ?? this gets the righ value in play_Cell */
1528 (vm->state).cellN = (vm->state).rsm_cellN; 1254 (vm->state).cellN = (vm->state).rsm_cellN;
1529 link_values.command = PlayThis; 1255 link_values.command = PlayThis;
1530 link_values.data1 = (vm->state).rsm_blockN; 1256 link_values.data1 = (vm->state).rsm_blockN;
1531 if(set_PGN(vm)) { 1257 if(!set_PGN(vm)) {
1532 /* Were at the end of the PGC, should not happen for a RSM */ 1258 /* Were at the end of the PGC, should not happen for a RSM */
1533 assert(0); 1259 assert(0);
1534 link_values.command = LinkTailPGC; 1260 link_values.command = LinkTailPGC;
1535 link_values.data1 = 0; /* No button */ 1261 link_values.data1 = 0; /* No button */
1536 } 1262 }
1537 } 1263 }
1538 } 1264 }
1539 break; 1265 break;
1540 case LinkPGCN: 1266 case LinkPGCN:
1541 /* Link to Program Chain Number:data1 */ 1267 /* Link to Program Chain Number:data1 */
1542 if(set_PGC(vm, link_values.data1)) 1268 if(!set_PGCN(vm, link_values.data1))
1543 assert(0); 1269 assert(0);
1544 link_values = play_PGC(vm); 1270 link_values = play_PGC(vm);
1545 break; 1271 break;
1546 case LinkPTTN: 1272 case LinkPTTN:
1547 /* Link to Part of this Title Number:data1 */ 1273 /* Link to Part of current Title Number:data1 */
1548 /* BUTTON number:data2 */ 1274 /* BUTTON number:data2 */
1549 assert((vm->state).domain == VTS_DOMAIN); 1275 assert((vm->state).domain == VTS_DOMAIN);
1550 if(link_values.data2 != 0) 1276 if(link_values.data2 != 0)
1551 (vm->state).HL_BTNN_REG = link_values.data2 << 10; 1277 (vm->state).HL_BTNN_REG = link_values.data2 << 10;
1552 if(set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1) == -1) 1278 if(!set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1))
1553 assert(0); 1279 assert(0);
1554 link_values = play_PG(vm); 1280 link_values = play_PG(vm);
1555 break; 1281 break;
1556 case LinkPGN: 1282 case LinkPGN:
1557 /* Link to Program Number:data1 */ 1283 /* Link to Program Number:data1 */
1579 case JumpTT: 1305 case JumpTT:
1580 /* Jump to VTS Title Domain */ 1306 /* Jump to VTS Title Domain */
1581 /* Only allowed from the First Play domain(PGC) */ 1307 /* Only allowed from the First Play domain(PGC) */
1582 /* or the Video Manager domain (VMG) */ 1308 /* or the Video Manager domain (VMG) */
1583 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ 1309 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */
1584 if(set_TT(vm,link_values.data1) == -1) 1310 if(!set_TT(vm, link_values.data1))
1585 assert(0); 1311 assert(0);
1586 link_values = play_PGC(vm); 1312 link_values = play_PGC(vm);
1587 break; 1313 break;
1588 case JumpVTS_TT: 1314 case JumpVTS_TT:
1589 /* Jump to Title:data1 in same VTS Title Domain */ 1315 /* Jump to Title:data1 in same VTS Title Domain */
1590 /* Only allowed from the VTS Menu Domain(VTSM) */ 1316 /* Only allowed from the VTS Menu Domain(VTSM) */
1591 /* or the Video Title Set Domain(VTS) */ 1317 /* or the Video Title Set Domain(VTS) */
1592 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ 1318 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */
1593 fprintf(MSG_OUT, "libdvdnav: FIXME: Should be able to use get_VTS_PTT here.\n"); 1319 if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1))
1594 if(set_VTS_TT(vm,(vm->state).vtsN, link_values.data1) == -1)
1595 assert(0); 1320 assert(0);
1596 link_values = play_PGC(vm); 1321 link_values = play_PGC(vm);
1597 break; 1322 break;
1598 case JumpVTS_PTT: 1323 case JumpVTS_PTT:
1599 /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */ 1324 /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */
1600 /* Only allowed from the VTS Menu Domain(VTSM) */ 1325 /* Only allowed from the VTS Menu Domain(VTSM) */
1601 /* or the Video Title Set Domain(VTS) */ 1326 /* or the Video Title Set Domain(VTS) */
1602 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ 1327 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */
1603 if(set_VTS_PTT(vm,(vm->state).vtsN, link_values.data1, link_values.data2) == -1) 1328 if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2))
1604 assert(0); 1329 assert(0);
1605 link_values = play_PGC_PG( vm, (vm->state).pgN ); 1330 link_values = play_PGC_PG(vm, (vm->state).pgN);
1606 break; 1331 break;
1607 1332
1608 case JumpSS_FP: 1333 case JumpSS_FP:
1609 /* Jump to First Play Domain */ 1334 /* Jump to First Play Domain */
1610 /* Only allowed from the VTS Menu Domain(VTSM) */ 1335 /* Only allowed from the VTS Menu Domain(VTSM) */
1611 /* or the Video Manager domain (VMG) */ 1336 /* or the Video Manager domain (VMG) */
1612 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); /* ?? */ 1337 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); /* ?? */
1613 set_FP_PGC(vm); 1338 if (!set_FP_PGC(vm))
1339 assert(0);
1614 link_values = play_PGC(vm); 1340 link_values = play_PGC(vm);
1615 break; 1341 break;
1616 case JumpSS_VMGM_MENU: 1342 case JumpSS_VMGM_MENU:
1617 /* Jump to Video Manger domain - Title Menu:data1 or any PGC in VMG */ 1343 /* Jump to Video Manger domain - Title Menu:data1 or any PGC in VMG */
1618 /* Allowed from anywhere except the VTS Title domain */ 1344 /* Allowed from anywhere except the VTS Title domain */
1619 assert((vm->state).domain == VMGM_DOMAIN || 1345 assert((vm->state).domain != VTS_DOMAIN); /* ?? */
1620 (vm->state).domain == VTSM_DOMAIN ||
1621 (vm->state).domain == FP_DOMAIN); /* ?? */
1622 (vm->state).domain = VMGM_DOMAIN; 1346 (vm->state).domain = VMGM_DOMAIN;
1623 if(set_MENU(vm,link_values.data1) == -1) 1347 if(!set_MENU(vm, link_values.data1))
1624 assert(0); 1348 assert(0);
1625 link_values = play_PGC(vm); 1349 link_values = play_PGC(vm);
1626 break; 1350 break;
1627 case JumpSS_VTSM: 1351 case JumpSS_VTSM:
1628 /* Jump to a menu in Video Title domain, */ 1352 /* Jump to a menu in Video Title domain, */
1639 link_values.data2, 1363 link_values.data2,
1640 link_values.data3); 1364 link_values.data3);
1641 fprintf(MSG_OUT, "libdvdnav: *******************************************************************\n"); 1365 fprintf(MSG_OUT, "libdvdnav: *******************************************************************\n");
1642 #endif 1366 #endif
1643 1367
1644 if(link_values.data1 !=0) { 1368 if(link_values.data1 != 0) {
1645 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ 1369 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */
1646 (vm->state).domain = VTSM_DOMAIN; 1370 (vm->state).domain = VTSM_DOMAIN;
1647 ifoOpenNewVTSI(vm, vm->dvd, link_values.data1); /* Also sets (vm->state).vtsN */ 1371 ifoOpenNewVTSI(vm, vm->dvd, link_values.data1); /* Also sets (vm->state).vtsN */
1648 } else { 1372 } else {
1649 /* This happens on 'The Fifth Element' region 2. */ 1373 /* This happens on 'The Fifth Element' region 2. */
1651 } 1375 }
1652 /* I don't know what title is supposed to be used for. */ 1376 /* I don't know what title is supposed to be used for. */
1653 /* Alien or Aliens has this != 1, I think. */ 1377 /* Alien or Aliens has this != 1, I think. */
1654 /* assert(link_values.data2 == 1); */ 1378 /* assert(link_values.data2 == 1); */
1655 (vm->state).VTS_TTN_REG = link_values.data2; 1379 (vm->state).VTS_TTN_REG = link_values.data2;
1656 if(set_MENU(vm, link_values.data3) == -1) 1380 if(!set_MENU(vm, link_values.data3))
1657 assert(0); 1381 assert(0);
1658 link_values = play_PGC(vm); 1382 link_values = play_PGC(vm);
1659 break; 1383 break;
1660 case JumpSS_VMGM_PGC: 1384 case JumpSS_VMGM_PGC:
1661 /* get_PGC:data1 */ 1385 /* set_PGCN:data1 */
1662 assert((vm->state).domain == VMGM_DOMAIN || 1386 assert((vm->state).domain != VTS_DOMAIN); /* ?? */
1663 (vm->state).domain == VTSM_DOMAIN ||
1664 (vm->state).domain == FP_DOMAIN); /* ?? */
1665 (vm->state).domain = VMGM_DOMAIN; 1387 (vm->state).domain = VMGM_DOMAIN;
1666 if(set_PGC(vm,link_values.data1) == -1) 1388 if(!set_PGCN(vm, link_values.data1))
1667 assert(0); 1389 assert(0);
1668 link_values = play_PGC(vm); 1390 link_values = play_PGC(vm);
1669 break; 1391 break;
1670 1392
1671 case CallSS_FP: 1393 case CallSS_FP:
1672 /* saveRSMinfo:data1 */ 1394 /* set_RSMinfo:data1 */
1673 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ 1395 assert((vm->state).domain == VTS_DOMAIN); /* ?? */
1674 /* Must be called before domain is changed */ 1396 /* Must be called before domain is changed */
1675 saveRSMinfo(vm, link_values.data1, /* We dont have block info */ 0); 1397 set_RSMinfo(vm, link_values.data1, /* We dont have block info */ 0);
1676 set_FP_PGC(vm); 1398 set_FP_PGC(vm);
1677 link_values = play_PGC(vm); 1399 link_values = play_PGC(vm);
1678 break; 1400 break;
1679 case CallSS_VMGM_MENU: 1401 case CallSS_VMGM_MENU:
1680 /* get_MENU:data1 */ 1402 /* set_MENU:data1 */
1681 /* saveRSMinfo:data2 */ 1403 /* set_RSMinfo:data2 */
1682 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ 1404 assert((vm->state).domain == VTS_DOMAIN); /* ?? */
1683 /* Must be called before domain is changed */ 1405 /* Must be called before domain is changed */
1684 saveRSMinfo(vm,link_values.data2, /* We dont have block info */ 0); 1406 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0);
1685 (vm->state).domain = VMGM_DOMAIN; 1407 (vm->state).domain = VMGM_DOMAIN;
1686 if(set_MENU(vm,link_values.data1) == -1) 1408 if(!set_MENU(vm, link_values.data1))
1687 assert(0); 1409 assert(0);
1688 link_values = play_PGC(vm); 1410 link_values = play_PGC(vm);
1689 break; 1411 break;
1690 case CallSS_VTSM: 1412 case CallSS_VTSM:
1691 /* get_MENU:data1 */ 1413 /* set_MENU:data1 */
1692 /* saveRSMinfo:data2 */ 1414 /* set_RSMinfo:data2 */
1693 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ 1415 assert((vm->state).domain == VTS_DOMAIN); /* ?? */
1694 /* Must be called before domain is changed */ 1416 /* Must be called before domain is changed */
1695 saveRSMinfo(vm,link_values.data2, /* We dont have block info */ 0); 1417 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0);
1696 (vm->state).domain = VTSM_DOMAIN; 1418 (vm->state).domain = VTSM_DOMAIN;
1697 if(set_MENU(vm,link_values.data1) == -1) 1419 if(!set_MENU(vm, link_values.data1))
1698 assert(0); 1420 assert(0);
1699 link_values = play_PGC(vm); 1421 link_values = play_PGC(vm);
1700 break; 1422 break;
1701 case CallSS_VMGM_PGC: 1423 case CallSS_VMGM_PGC:
1702 /* get_PGC:data1 */ 1424 /* set_PGC:data1 */
1703 /* saveRSMinfo:data2 */ 1425 /* set_RSMinfo:data2 */
1704 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ 1426 assert((vm->state).domain == VTS_DOMAIN); /* ?? */
1705 /* Must be called before domain is changed */ 1427 /* Must be called before domain is changed */
1706 saveRSMinfo(vm,link_values.data2, /* We dont have block info */ 0); 1428 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0);
1707 (vm->state).domain = VMGM_DOMAIN; 1429 (vm->state).domain = VMGM_DOMAIN;
1708 if(set_PGC(vm,link_values.data1) == -1) 1430 if(!set_PGCN(vm, link_values.data1))
1709 assert(0); 1431 assert(0);
1710 link_values = play_PGC(vm); 1432 link_values = play_PGC(vm);
1711 break; 1433 break;
1712 case PlayThis: 1434 case PlayThis:
1713 /* Should never happen. */ 1435 /* Should never happen. */
1714 assert(0); 1436 assert(0);
1715 break; 1437 break;
1716 } 1438 }
1717 1439
1718 #ifdef TRACE 1440 #ifdef TRACE
1719 fprintf(MSG_OUT, "libdvdnav: After printout starts:\n"); 1441 fprintf(MSG_OUT, "libdvdnav: After printout starts:\n");
1720 vm_print_current_domain_state(vm); 1442 vm_print_current_domain_state(vm);
1721 fprintf(MSG_OUT, "libdvdnav: After printout ends.\n"); 1443 fprintf(MSG_OUT, "libdvdnav: After printout ends.\n");
1722 #endif 1444 #endif
1723 1445
1724 } 1446 }
1725 link_values.data2 = 1; /* there was actually a jump */ 1447 (vm->state).blockN = link_values.data1;
1726 vm->badness_counter--; 1448 return 1;
1727 return link_values; 1449 }
1728 } 1450
1451
1452 /* Set functions */
1453
1454 static int set_TT(vm_t *vm, int tt) {
1455 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts);
1456 (vm->state).TTN_REG = tt;
1457 return set_VTS_TT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr,
1458 vm->vmgi->tt_srpt->title[tt - 1].vts_ttn);
1459 }
1460
1461 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) {
1462 return set_VTS_PTT(vm, vtsN, vts_ttn, 1);
1463 }
1464
1465 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) {
1466 int pgcN, pgN, res;
1467
1468 (vm->state).domain = VTS_DOMAIN;
1469
1470 if(vtsN != (vm->state).vtsN)
1471 ifoOpenNewVTSI(vm, vm->dvd, vtsN); /* Also sets (vm->state).vtsN */
1472
1473 if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) ||
1474 (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) {
1475 return 0;
1476 }
1477
1478 pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn;
1479 pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn;
1480
1481 (vm->state).TT_PGCN_REG = pgcN;
1482 (vm->state).PTTN_REG = pgN;
1483 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn);
1484 assert( (vm->state.TTN_REG) != 0 );
1485 (vm->state).VTS_TTN_REG = vts_ttn;
1486 (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */
1487 /* Any other registers? */
1488
1489 res = set_PGCN(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */
1490 (vm->state).pgN = pgN;
1491 return res;
1492 }
1493
1494 static int set_FP_PGC(vm_t *vm) {
1495 (vm->state).domain = FP_DOMAIN;
1496 (vm->state).pgc = vm->vmgi->first_play_pgc;
1497 return 1;
1498 }
1499
1500
1501 static int set_MENU(vm_t *vm, int menu) {
1502 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN);
1503 return set_PGCN(vm, get_ID(vm, menu));
1504 }
1505
1506 static int set_PGCN(vm_t *vm, int pgcN) {
1507 pgcit_t *pgcit;
1508
1509 pgcit = get_PGCIT(vm);
1510 assert(pgcit != NULL); /* ?? Make this return -1 instead */
1511
1512 if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) {
1513 #ifdef TRACE
1514 fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN);
1515 #endif
1516 return 0;
1517 }
1518
1519 (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc;
1520 (vm->state).pgN = 1;
1521
1522 if((vm->state).domain == VTS_DOMAIN)
1523 (vm->state).TT_PGCN_REG = pgcN;
1524
1525 return 1;
1526 }
1527
1528 /* Figure out the correct pgN from the cell and update (vm->state). */
1529 static int set_PGN(vm_t *vm) {
1530 int new_pgN = 0;
1531
1532 while(new_pgN < (vm->state).pgc->nr_of_programs
1533 && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN])
1534 new_pgN++;
1535
1536 if(new_pgN == (vm->state).pgc->nr_of_programs) /* We are at the last program */
1537 if((vm->state).cellN > (vm->state).pgc->nr_of_cells)
1538 return 0; /* We are past the last cell */
1539
1540 (vm->state).pgN = new_pgN;
1541
1542 if((vm->state).domain == VTS_DOMAIN) {
1543 playback_type_t *pb_ty;
1544 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
1545 return 0; /* ?? */
1546 pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty;
1547 if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) {
1548 int dummy;
1549 #if 0
1550 /* TTN_REG can't be trusted to have a correct value here... */
1551 vts_ptt_srpt_t *ptt_srpt = vtsi->vts_ptt_srpt;
1552 assert((vm->state).VTS_TTN_REG <= ptt_srpt->nr_of_srpts);
1553 assert(get_PGCN() == ptt_srpt->title[(vm->state).VTS_TTN_REG - 1].ptt[0].pgcn);
1554 assert(1 == ptt_srpt->title[(vm->state).VTS_TTN_REG - 1].ptt[0].pgn);
1555 #endif
1556 vm_get_current_title_part(vm, &dummy, &(vm->state).pgN);
1557 (vm->state).PTTN_REG = (vm->state).pgN;
1558 } else {
1559 /* FIXME: Handle RANDOM or SHUFFLE titles. */
1560 fprintf(MSG_OUT, "libdvdnav: RANDOM or SHUFFLE titles are NOT handled yet.\n");
1561 }
1562 }
1563 return 1;
1564 }
1565
1566 /* Must be called before domain is changed (set_PGCN()) */
1567 static void set_RSMinfo(vm_t *vm, int cellN, int blockN) {
1568 int i;
1569
1570 if(cellN) {
1571 (vm->state).rsm_cellN = cellN;
1572 (vm->state).rsm_blockN = blockN;
1573 } else {
1574 (vm->state).rsm_cellN = (vm->state).cellN;
1575 (vm->state).rsm_blockN = blockN;
1576 }
1577 (vm->state).rsm_vtsN = (vm->state).vtsN;
1578 (vm->state).rsm_pgcN = get_PGCN(vm);
1579
1580 /* assert((vm->state).rsm_pgcN == (vm->state).TT_PGCN_REG); for VTS_DOMAIN */
1581
1582 for(i = 0; i < 5; i++) {
1583 (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i];
1584 }
1585 }
1586
1587
1588 /* Get functions */
1729 1589
1730 /* Searches the TT tables, to find the current TT. 1590 /* Searches the TT tables, to find the current TT.
1731 * returns the current TT. 1591 * returns the current TT.
1732 * returns 0 if not found. 1592 * returns 0 if not found.
1733 */ 1593 */
1734 static int get_TT(vm_t *vm, int vtsN, int vts_ttn) { 1594 static int get_TT(vm_t *vm, int vtsN, int vts_ttn) {
1735 int i; 1595 int i;
1736 int tt=0; 1596 int tt=0;
1597
1737 for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) { 1598 for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) {
1738 if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN && 1599 if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN &&
1739 vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) { 1600 vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) {
1740 tt=i; 1601 tt=i;
1741 break; 1602 break;
1742 } 1603 }
1743 } 1604 }
1744 return tt; 1605 return tt;
1745 }
1746
1747 static int set_TT(vm_t *vm, int tt)
1748 {
1749 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts);
1750
1751 (vm->state).TTN_REG = tt;
1752
1753 return set_VTS_TT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr,
1754 vm->vmgi->tt_srpt->title[tt - 1].vts_ttn);
1755 }
1756
1757
1758 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn)
1759 {
1760 fprintf(MSG_OUT, "libdvdnav: get_VTS_TT called, testing!!! vtsN=%d, vts_ttn=%d\n", vtsN, vts_ttn);
1761 return set_VTS_PTT(vm, vtsN, vts_ttn, 1);
1762 /* pgcN = get_ID(vm, vts_ttn); This might return -1 */
1763 /*
1764 assert(pgcN != -1);
1765
1766 (vm->state).TTN_REG = get_TT(*vm, vtsN, vts_ttn);
1767 (vm->state).VTS_TTN_REG = vts_ttn;
1768 (vm->state).vtsN =
1769 */
1770 /* Any other registers? */
1771
1772 /* return set_PGC(vm, pgcN); */
1773 }
1774
1775
1776 static int set_VTS_PTT(vm_t *vm, int vtsN, int /* is this really */ vts_ttn, int part)
1777 {
1778 int pgcN, pgN, res;
1779
1780 (vm->state).domain = VTS_DOMAIN;
1781 if(vtsN != (vm->state).vtsN)
1782 ifoOpenNewVTSI(vm, vm->dvd, vtsN); /* Also sets (vm->state).vtsN */
1783
1784 if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) ||
1785 (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) {
1786 return S_ERR;
1787 }
1788
1789 pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn;
1790 pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn;
1791
1792 (vm->state).TT_PGCN_REG = pgcN;
1793 (vm->state).PTTN_REG = pgN;
1794
1795 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn);
1796 assert( (vm->state.TTN_REG) != 0 );
1797 (vm->state).VTS_TTN_REG = vts_ttn;
1798 (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */
1799 /* Any other registers? */
1800
1801 res = set_PGC(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */
1802 (vm->state).pgN = pgN; /* Part?? */
1803 return res;
1804 }
1805
1806
1807
1808 static int set_FP_PGC(vm_t *vm)
1809 {
1810 (vm->state).domain = FP_DOMAIN;
1811
1812 (vm->state).pgc = vm->vmgi->first_play_pgc;
1813
1814 return 0;
1815 }
1816
1817
1818 static int set_MENU(vm_t *vm, int menu)
1819 {
1820 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN);
1821 return set_PGC(vm, get_ID(vm, menu));
1822 } 1606 }
1823 1607
1824 /* Search for entry_id match of the PGC Category in the current VTS PGCIT table. 1608 /* Search for entry_id match of the PGC Category in the current VTS PGCIT table.
1825 * Return pgcN based on entry_id match. 1609 * Return pgcN based on entry_id match.
1826 */ 1610 */
1827 static int get_ID(vm_t *vm, int id) 1611 static int get_ID(vm_t *vm, int id) {
1828 {
1829 int pgcN, i; 1612 int pgcN, i;
1830 pgcit_t *pgcit; 1613 pgcit_t *pgcit;
1831 1614
1832 /* Relies on state to get the correct pgcit. */ 1615 /* Relies on state to get the correct pgcit. */
1833 pgcit = get_PGCIT(vm); 1616 pgcit = get_PGCIT(vm);
1834 assert(pgcit != NULL); 1617 assert(pgcit != NULL);
1618 #ifdef TRACE
1835 fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id); 1619 fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id);
1620 #endif
1836 1621
1837 /* Force high bit set. */ 1622 /* Force high bit set. */
1838 id |=0x80; 1623 id |=0x80;
1624
1839 /* Get menu/title */ 1625 /* Get menu/title */
1840 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { 1626 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
1841 if( (pgcit->pgci_srp[i].entry_id) == id) { 1627 if( (pgcit->pgci_srp[i].entry_id) == id) {
1842 pgcN = i + 1; 1628 pgcN = i + 1;
1629 #ifdef TRACE
1843 fprintf(MSG_OUT, "libdvdnav: Found menu.\n"); 1630 fprintf(MSG_OUT, "libdvdnav: Found menu.\n");
1631 #endif
1844 return pgcN; 1632 return pgcN;
1845 } 1633 }
1846 } 1634 }
1635 #ifdef TRACE
1847 fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f); 1636 fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f);
1848 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { 1637 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) {
1849 if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) { 1638 if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) {
1850 fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n", 1639 fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n",
1851 pgcit->pgci_srp[i].entry_id & 0x7f); 1640 pgcit->pgci_srp[i].entry_id & 0x7f);
1852 } 1641 }
1853 } 1642 }
1854 return -1; /* error */ 1643 #endif
1855 } 1644 return 0; /* error */
1856 1645 }
1857 /* Set the vm->state to pgcN. 1646
1858 * Returns success/failure. 1647 static int get_PGCN(vm_t *vm) {
1859 */
1860 static int set_PGC(vm_t *vm, int pgcN)
1861 {
1862 /* FIXME: Keep this up to date with the ogle people */
1863 pgcit_t *pgcit;
1864
1865 pgcit = get_PGCIT(vm);
1866
1867 assert(pgcit != NULL); /* ?? Make this return -1 instead */
1868 if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) {
1869 fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN);
1870 return -1; /* error */
1871 }
1872
1873 /* (vm->state).pgcN = pgcN; */
1874 (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc;
1875 (vm->state).pgN = 1;
1876
1877 if((vm->state).domain == VTS_DOMAIN)
1878 (vm->state).TT_PGCN_REG = pgcN;
1879
1880 return 0;
1881 }
1882
1883 static int get_PGCN(vm_t *vm)
1884 {
1885 pgcit_t *pgcit; 1648 pgcit_t *pgcit;
1886 int pgcN = 1; 1649 int pgcN = 1;
1887 1650
1888 pgcit = get_PGCIT(vm); 1651 pgcit = get_PGCIT(vm);
1889
1890 assert(pgcit != NULL); 1652 assert(pgcit != NULL);
1891 1653
1892 while(pgcN <= pgcit->nr_of_pgci_srp) { 1654 while(pgcN <= pgcit->nr_of_pgci_srp) {
1893 if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) 1655 if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc)
1894 return pgcN; 1656 return pgcN;
1895 pgcN++; 1657 pgcN++;
1896 } 1658 }
1897 fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Trying to find pgcN in domain %d \n", 1659 fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n",
1898 (vm->state).domain); 1660 (vm->state).domain);
1899 /* assert(0);*/ 1661 /* assert(0);*/
1900 return -1; /* error */ 1662 return 0; /* error */
1901 } 1663 }
1902 1664
1903 int vm_get_video_aspect(vm_t *vm) 1665 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) {
1904 {
1905 int aspect = 0;
1906
1907 switch ((vm->state).domain) {
1908 case VTS_DOMAIN:
1909 aspect = vm->vtsi->vtsi_mat->vts_video_attr.display_aspect_ratio;
1910 break;
1911 case VTSM_DOMAIN:
1912 aspect = vm->vtsi->vtsi_mat->vtsm_video_attr.display_aspect_ratio;
1913 break;
1914 case VMGM_DOMAIN:
1915 aspect = vm->vmgi->vmgi_mat->vmgm_video_attr.display_aspect_ratio;
1916 break;
1917 default:
1918 fprintf(MSG_OUT, "libdvdnav: vm_get_video_aspect failed. Unknown domain %d\n",
1919 (vm->state).domain);
1920 assert(0);
1921 break;
1922 }
1923 #ifdef TRACE
1924 fprintf(MSG_OUT, "libdvdnav: get_video_aspect:aspect=%d\n",aspect);
1925 #endif
1926 assert(aspect == 0 || aspect == 3);
1927 (vm->state).registers.SPRM[14] &= ~(0x3 << 10);
1928 (vm->state).registers.SPRM[14] |= aspect << 10;
1929
1930 return aspect;
1931 }
1932
1933 int vm_get_video_scale_permission(vm_t *vm)
1934 {
1935 int permission = 0;
1936
1937 if((vm->state).domain == VTS_DOMAIN) {
1938 permission = vm->vtsi->vtsi_mat->vts_video_attr.permitted_df;
1939 } else if((vm->state).domain == VTSM_DOMAIN) {
1940 permission = vm->vtsi->vtsi_mat->vtsm_video_attr.permitted_df;
1941 } else if((vm->state).domain == VMGM_DOMAIN) {
1942 permission = vm->vmgi->vmgi_mat->vmgm_video_attr.permitted_df;
1943 }
1944 #ifdef TRACE
1945 fprintf(MSG_OUT, "libdvdnav: get_video_scale_permission:permission=%d\n",permission);
1946 #endif
1947
1948 return permission;
1949 }
1950
1951 static void ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN)
1952 {
1953 if((vm->state).vtsN == vtsN) {
1954 return; /* We alread have it */
1955 }
1956
1957 if(vm->vtsi != NULL)
1958 ifoClose(vm->vtsi);
1959
1960 vm->vtsi = ifoOpenVTSI(dvd, vtsN);
1961 if(vm->vtsi == NULL) {
1962 fprintf(MSG_OUT, "libdvdnav: ifoOpenVTSI failed - CRASHING!!!\n");
1963 assert(0);
1964 }
1965 if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) {
1966 fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed - CRASHING!!!\n");
1967 assert(0);
1968 }
1969 if(!ifoRead_PGCIT(vm->vtsi)) {
1970 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed - CRASHING!!!\n");
1971 assert(0);
1972 }
1973 if(!ifoRead_PGCI_UT(vm->vtsi)) {
1974 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed - CRASHING!!!\n");
1975 assert(0);
1976 }
1977 if(!ifoRead_VOBU_ADMAP(vm->vtsi)) {
1978 fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed - CRASHING\n");
1979 assert(0);
1980 }
1981 if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) {
1982 fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed - CRASHING\n");
1983 assert(0);
1984 }
1985 (vm->state).vtsN = vtsN;
1986 }
1987
1988 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang)
1989 {
1990 int i; 1666 int i;
1991 1667
1992 if(h == NULL || h->pgci_ut == NULL) { 1668 if(h == NULL || h->pgci_ut == NULL) {
1993 fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n"); 1669 fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n");
1994 return NULL; /* error? */ 1670 return NULL; /* error? */
2002 fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n", 1678 fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n",
2003 (char)(lang >> 8), (char)(lang & 0xff), 1679 (char)(lang >> 8), (char)(lang & 0xff),
2004 (char)(h->pgci_ut->lu[0].lang_code >> 8), 1680 (char)(h->pgci_ut->lu[0].lang_code >> 8),
2005 (char)(h->pgci_ut->lu[0].lang_code & 0xff)); 1681 (char)(h->pgci_ut->lu[0].lang_code & 0xff));
2006 fprintf(MSG_OUT, "libdvdnav: Menu Languages available: "); 1682 fprintf(MSG_OUT, "libdvdnav: Menu Languages available: ");
2007 for(i=0;i< h->pgci_ut->nr_of_lus;i++) { 1683 for(i = 0; i < h->pgci_ut->nr_of_lus; i++) {
2008 fprintf(MSG_OUT, "%c%c ", 1684 fprintf(MSG_OUT, "%c%c ",
2009 (char)(h->pgci_ut->lu[0].lang_code >> 8), 1685 (char)(h->pgci_ut->lu[i].lang_code >> 8),
2010 (char)(h->pgci_ut->lu[0].lang_code & 0xff)); 1686 (char)(h->pgci_ut->lu[i].lang_code & 0xff));
2011 } 1687 }
2012 fprintf(MSG_OUT, "\n"); 1688 fprintf(MSG_OUT, "\n");
2013
2014 i = 0; /* error? */ 1689 i = 0; /* error? */
2015 } 1690 }
2016 1691
2017 return h->pgci_ut->lu[i].pgcit; 1692 return h->pgci_ut->lu[i].pgcit;
2018 } 1693 }
2041 } 1716 }
2042 1717
2043 return pgcit; 1718 return pgcit;
2044 } 1719 }
2045 1720
1721
1722 /* Debug functions */
1723
1724 #ifdef TRACE
1725 void vm_position_print(vm_t *vm, vm_position_t *position) {
1726 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",
1727 position->button,
1728 position->spu_channel,
1729 position->audio_channel,
1730 position->angle_channel,
1731 position->hop_channel,
1732 position->vts,
1733 position->domain,
1734 position->cell,
1735 position->cell_restart,
1736 position->cell_start,
1737 position->still,
1738 position->block);
1739 }
1740 #endif
1741
1742
2046 /* 1743 /*
2047 * $Log$ 1744 * $Log$
1745 * Revision 1.43 2003/02/20 15:32:19 mroi
1746 * big libdvdnav cleanup, quoting the ChangeLog:
1747 * * some bugfixes
1748 * * code cleanup
1749 * * build process polishing
1750 * * more sensible event order in get_next_block to ensure useful event delivery
1751 * * VOBU level resume
1752 * * fixed: seeking in a multiangle feature briefly showed the wrong angle
1753 *
2048 * Revision 1.42 2003/01/13 13:33:45 mroi 1754 * Revision 1.42 2003/01/13 13:33:45 mroi
2049 * slightly improved logic of program skipping: 1755 * slightly improved logic of program skipping:
2050 * previous program: 1756 * previous program:
2051 * -> if PG > 1, jump to PG - 1 1757 * -> if PG > 1, jump to PG - 1
2052 * -> otherwise, if prev_PGC is set, jump to last PG of prev_PGC 1758 * -> otherwise, if prev_PGC is set, jump to last PG of prev_PGC