Mercurial > libdvdnav.hg
annotate vm/vm.c @ 404:d16ee5945580 src
Prevent display of garbage volume label when the file being scanned is
not a dvd. This is a simple movement of the code that logs the volume
name to after the point that some basic validation of the disc has been
performed.
Patch by John Stebbins of Handbrake
author | nicodvb |
---|---|
date | Tue, 01 Jun 2010 10:01:33 +0000 |
parents | 1ce807c12563 |
children | 7923e813ec61 |
rev | line source |
---|---|
225 | 1 /* |
390 | 2 * Copyright (C) 2000, 2001 HÃ¥kan Hjort |
225 | 3 * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net> |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
4 * 2002-2004 the dvdnav project |
388 | 5 * |
225 | 6 * This file is part of libdvdnav, a DVD navigation library. It is modified |
7 * from a file originally part of the Ogle DVD player. | |
388 | 8 * |
225 | 9 * libdvdnav is free software; you can redistribute it and/or modify |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
388 | 13 * |
225 | 14 * libdvdnav is distributed in the hope that it will be useful, |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
388 | 18 * |
389
d3c273ced49c
Use consistent license headers everywhere: Fix wrong FSF address.
diego
parents:
388
diff
changeset
|
19 * You should have received a copy of the GNU General Public License along |
d3c273ced49c
Use consistent license headers everywhere: Fix wrong FSF address.
diego
parents:
388
diff
changeset
|
20 * with libdvdnav; if not, write to the Free Software Foundation, Inc., |
d3c273ced49c
Use consistent license headers everywhere: Fix wrong FSF address.
diego
parents:
388
diff
changeset
|
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
225 | 22 */ |
23 | |
24 #ifdef HAVE_CONFIG_H | |
25 #include "config.h" | |
26 #endif | |
27 | |
28 #include <stdio.h> | |
29 #include <string.h> | |
30 #include <stdlib.h> | |
31 #include <unistd.h> | |
32 #include <inttypes.h> | |
294
2146ff691bcd
include limits.h; it was included in the previous dvdnav_internal.h and without it players segfault
nicodvb
parents:
290
diff
changeset
|
33 #include <limits.h> |
225 | 34 #include <assert.h> |
35 #include <sys/types.h> | |
36 #include <sys/stat.h> | |
290 | 37 #include <sys/time.h> |
225 | 38 #include <fcntl.h> |
39 | |
386 | 40 #include <dvdread/nav_types.h> |
41 #include <dvdread/ifo_types.h> | |
42 #include <dvdread/ifo_read.h> | |
395
9c5aef10d165
Move dvd_types.h, dvdnav_events.h and dvdnav.h into a dvdnav directory.
reimar
parents:
394
diff
changeset
|
43 #include "dvdnav/dvdnav.h" |
225 | 44 |
285
52877d182e96
moved all header inclusions from .h to .c files; my word, I've never seen such a horrible entanglement as in this mess
nicodvb
parents:
260
diff
changeset
|
45 #include "decoder.h" |
52877d182e96
moved all header inclusions from .h to .c files; my word, I've never seen such a horrible entanglement as in this mess
nicodvb
parents:
260
diff
changeset
|
46 #include "remap.h" |
52877d182e96
moved all header inclusions from .h to .c files; my word, I've never seen such a horrible entanglement as in this mess
nicodvb
parents:
260
diff
changeset
|
47 #include "vm.h" |
225 | 48 #include "dvdnav_internal.h" |
49 | |
50 #ifdef _MSC_VER | |
51 #include <io.h> /* read() */ | |
52 #endif /* _MSC_VER */ | |
53 | |
394 | 54 #ifdef __OS2__ |
55 #define INCL_DOS | |
56 #include <os2.h> | |
399 | 57 #include <io.h> /* setmode() */ |
58 #include <fcntl.h> /* O_BINARY */ | |
394 | 59 #endif |
60 | |
225 | 61 /* |
62 #define STRICT | |
63 */ | |
64 | |
65 /* Local prototypes */ | |
66 | |
67 /* get_XYZ returns a value. | |
68 * set_XYZ sets state using passed parameters. | |
69 * returns success/failure. | |
70 */ | |
71 | |
72 /* Play */ | |
73 static link_t play_PGC(vm_t *vm); | |
74 static link_t play_PGC_PG(vm_t *vm, int pgN); | |
75 static link_t play_PGC_post(vm_t *vm); | |
76 static link_t play_PG(vm_t *vm); | |
77 static link_t play_Cell(vm_t *vm); | |
78 static link_t play_Cell_post(vm_t *vm); | |
79 | |
80 /* Process link - returns 1 if a hop has been performed */ | |
81 static int process_command(vm_t *vm,link_t link_values); | |
82 | |
83 /* Set */ | |
84 static int set_TT(vm_t *vm, int tt); | |
85 static int set_PTT(vm_t *vm, int tt, int ptt); | |
86 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn); | |
87 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part); | |
88 static int set_FP_PGC(vm_t *vm); | |
89 static int set_MENU(vm_t *vm, int menu); | |
90 static int set_PGCN(vm_t *vm, int pgcN); | |
91 static int set_PGN(vm_t *vm); /* Set PGN based on (vm->state).CellN */ | |
92 static void set_RSMinfo(vm_t *vm, int cellN, int blockN); | |
93 | |
94 /* Get */ | |
95 static int get_TT(vm_t *vm, int vtsN, int vts_ttn); | |
96 static int get_ID(vm_t *vm, int id); | |
97 static int get_PGCN(vm_t *vm); | |
98 | |
99 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang); | |
100 static pgcit_t* get_PGCIT(vm_t *vm); | |
101 | |
102 | |
103 /* Helper functions */ | |
104 | |
105 #ifdef TRACE | |
106 static void vm_print_current_domain_state(vm_t *vm) { | |
107 switch((vm->state).domain) { | |
108 case VTS_DOMAIN: | |
109 fprintf(MSG_OUT, "libdvdnav: Video Title Domain: -\n"); | |
110 break; | |
111 | |
112 case VTSM_DOMAIN: | |
113 fprintf(MSG_OUT, "libdvdnav: Video Title Menu Domain: -\n"); | |
114 break; | |
115 | |
116 case VMGM_DOMAIN: | |
117 fprintf(MSG_OUT, "libdvdnav: Video Manager Menu Domain: -\n"); | |
118 break; | |
119 | |
388 | 120 case FP_DOMAIN: |
225 | 121 fprintf(MSG_OUT, "libdvdnav: First Play Domain: -\n"); |
122 break; | |
123 | |
124 default: | |
125 fprintf(MSG_OUT, "libdvdnav: Unknown Domain: -\n"); | |
126 break; | |
127 } | |
388 | 128 fprintf(MSG_OUT, "libdvdnav: VTS:%d PGC:%d PG:%u CELL:%u BLOCK:%u VTS_TTN:%u TTN:%u TT_PGCN:%u\n", |
225 | 129 (vm->state).vtsN, |
130 get_PGCN(vm), | |
131 (vm->state).pgN, | |
132 (vm->state).cellN, | |
133 (vm->state).blockN, | |
134 (vm->state).VTS_TTN_REG, | |
135 (vm->state).TTN_REG, | |
136 (vm->state).TT_PGCN_REG); | |
137 } | |
138 #endif | |
139 | |
394 | 140 #ifdef __OS2__ |
141 #define open os2_open | |
142 | |
143 static int os2_open(const char *name, int oflag) | |
144 { | |
400 | 145 HFILE hfile; |
146 ULONG ulAction; | |
147 ULONG rc; | |
394 | 148 |
400 | 149 rc = DosOpenL(name, &hfile, &ulAction, 0, FILE_NORMAL, |
150 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, | |
151 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_DASD, | |
152 NULL); | |
394 | 153 |
400 | 154 if(rc) |
155 return -1; | |
394 | 156 |
400 | 157 setmode(hfile, O_BINARY); |
399 | 158 |
400 | 159 return (int)hfile; |
394 | 160 } |
161 #endif | |
162 | |
397
a70f79850e5f
implement and export dvdnav_get_serial_string(); patch by Matthew Wire devel - mrwire - co - uk. Fixed by Erik
nicodvb
parents:
395
diff
changeset
|
163 static void dvd_read_name(char *name, char *serial, const char *device) { |
229 | 164 /* Because we are compiling with _FILE_OFFSET_BITS=64 |
165 * all off_t are 64bit. | |
166 */ | |
167 off_t off; | |
225 | 168 int fd, i; |
169 uint8_t data[DVD_VIDEO_LB_LEN]; | |
170 | |
171 /* Read DVD name */ | |
244
a27c81078c3c
removing O_EXCL, since it does not work with DVD images
mroi
parents:
243
diff
changeset
|
172 fd = open(device, O_RDONLY); |
388 | 173 if (fd > 0) { |
229 | 174 off = lseek( fd, 32 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET ); |
175 if( off == ( 32 * (off_t) DVD_VIDEO_LB_LEN ) ) { | |
388 | 176 off = read( fd, data, DVD_VIDEO_LB_LEN ); |
225 | 177 close(fd); |
229 | 178 if (off == ( (off_t) DVD_VIDEO_LB_LEN )) { |
225 | 179 fprintf(MSG_OUT, "libdvdnav: DVD Title: "); |
180 for(i=25; i < 73; i++ ) { | |
181 if((data[i] == 0)) break; | |
182 if((data[i] > 32) && (data[i] < 127)) { | |
183 fprintf(MSG_OUT, "%c", data[i]); | |
184 } else { | |
185 fprintf(MSG_OUT, " "); | |
186 } | |
187 } | |
377
9a9d15ed0599
(char*) typecase to silence gcc; patch by Erik Hovland org
nicodvb
parents:
345
diff
changeset
|
188 strncpy(name, (char*) &data[25], 48); |
225 | 189 name[48] = 0; |
190 fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: "); | |
191 for(i=73; i < 89; i++ ) { | |
192 if((data[i] == 0)) break; | |
193 if((data[i] > 32) && (data[i] < 127)) { | |
194 fprintf(MSG_OUT, "%c", data[i]); | |
195 } else { | |
196 fprintf(MSG_OUT, " "); | |
388 | 197 } |
225 | 198 } |
397
a70f79850e5f
implement and export dvdnav_get_serial_string(); patch by Matthew Wire devel - mrwire - co - uk. Fixed by Erik
nicodvb
parents:
395
diff
changeset
|
199 strncpy(serial, (char*) &data[73], (i-73)); |
a70f79850e5f
implement and export dvdnav_get_serial_string(); patch by Matthew Wire devel - mrwire - co - uk. Fixed by Erik
nicodvb
parents:
395
diff
changeset
|
200 serial[14] = 0; |
225 | 201 fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): "); |
202 for(i=89; i < 128; i++ ) { | |
203 if((data[i] == 0)) break; | |
204 if((data[i] > 32) && (data[i] < 127)) { | |
205 fprintf(MSG_OUT, "%c", data[i]); | |
206 } else { | |
207 fprintf(MSG_OUT, " "); | |
208 } | |
209 } | |
210 fprintf(MSG_OUT, "\n"); | |
211 } else { | |
212 fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a DVD-ROM device.\n"); | |
213 } | |
214 } else { | |
215 fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 ); | |
216 } | |
217 close(fd); | |
218 } else { | |
219 fprintf(MSG_OUT, "NAME OPEN FAILED\n"); | |
220 } | |
221 } | |
222 | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
223 static int ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) { |
225 | 224 if((vm->state).vtsN == vtsN) { |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
225 return 1; /* We alread have it */ |
225 | 226 } |
388 | 227 |
225 | 228 if(vm->vtsi != NULL) |
229 ifoClose(vm->vtsi); | |
388 | 230 |
225 | 231 vm->vtsi = ifoOpenVTSI(dvd, vtsN); |
232 if(vm->vtsi == NULL) { | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
233 fprintf(MSG_OUT, "libdvdnav: ifoOpenVTSI failed\n"); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
234 return 0; |
225 | 235 } |
236 if(!ifoRead_VTS_PTT_SRPT(vm->vtsi)) { | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
237 fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_PTT_SRPT failed\n"); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
238 return 0; |
225 | 239 } |
240 if(!ifoRead_PGCIT(vm->vtsi)) { | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
241 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCIT failed\n"); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
242 return 0; |
225 | 243 } |
244 if(!ifoRead_PGCI_UT(vm->vtsi)) { | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
245 fprintf(MSG_OUT, "libdvdnav: ifoRead_PGCI_UT failed\n"); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
246 return 0; |
225 | 247 } |
248 if(!ifoRead_VOBU_ADMAP(vm->vtsi)) { | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
249 fprintf(MSG_OUT, "libdvdnav: ifoRead_VOBU_ADMAP vtsi failed\n"); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
250 return 0; |
225 | 251 } |
252 if(!ifoRead_TITLE_VOBU_ADMAP(vm->vtsi)) { | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
253 fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed\n"); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
254 return 0; |
225 | 255 } |
256 (vm->state).vtsN = vtsN; | |
388 | 257 |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
258 return 1; |
225 | 259 } |
260 | |
261 | |
262 /* Initialisation & Destruction */ | |
263 | |
264 vm_t* vm_new_vm() { | |
265 return (vm_t*)calloc(sizeof(vm_t), sizeof(char)); | |
266 } | |
267 | |
268 void vm_free_vm(vm_t *vm) { | |
269 vm_stop(vm); | |
270 free(vm); | |
271 } | |
272 | |
273 | |
274 /* IFO Access */ | |
275 | |
276 ifo_handle_t *vm_get_vmgi(vm_t *vm) { | |
277 return vm->vmgi; | |
278 } | |
279 | |
280 ifo_handle_t *vm_get_vtsi(vm_t *vm) { | |
281 return vm->vtsi; | |
282 } | |
283 | |
284 | |
285 /* Reader Access */ | |
286 | |
287 dvd_reader_t *vm_get_dvd_reader(vm_t *vm) { | |
288 return vm->dvd; | |
289 } | |
290 | |
291 | |
292 /* Basic Handling */ | |
293 | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
294 int vm_start(vm_t *vm) { |
225 | 295 /* Set pgc to FP (First Play) pgc */ |
296 set_FP_PGC(vm); | |
297 process_command(vm, play_PGC(vm)); | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
298 return !vm->stopped; |
225 | 299 } |
300 | |
301 void vm_stop(vm_t *vm) { | |
302 if(vm->vmgi) { | |
303 ifoClose(vm->vmgi); | |
304 vm->vmgi=NULL; | |
305 } | |
306 if(vm->vtsi) { | |
307 ifoClose(vm->vtsi); | |
308 vm->vtsi=NULL; | |
309 } | |
310 if(vm->dvd) { | |
311 DVDClose(vm->dvd); | |
312 vm->dvd=NULL; | |
313 } | |
314 vm->stopped = 1; | |
315 } | |
388 | 316 |
225 | 317 int vm_reset(vm_t *vm, const char *dvdroot) { |
318 /* Setup State */ | |
319 memset((vm->state).registers.SPRM, 0, sizeof((vm->state).registers.SPRM)); | |
320 memset((vm->state).registers.GPRM, 0, sizeof((vm->state).registers.GPRM)); | |
321 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode)); | |
322 memset((vm->state).registers.GPRM_mode, 0, sizeof((vm->state).registers.GPRM_mode)); | |
323 memset((vm->state).registers.GPRM_time, 0, sizeof((vm->state).registers.GPRM_time)); | |
324 (vm->state).registers.SPRM[0] = ('e'<<8)|'n'; /* Player Menu Languange code */ | |
325 (vm->state).AST_REG = 15; /* 15 why? */ | |
326 (vm->state).SPST_REG = 62; /* 62 why? */ | |
327 (vm->state).AGL_REG = 1; | |
328 (vm->state).TTN_REG = 1; | |
329 (vm->state).VTS_TTN_REG = 1; | |
330 /* (vm->state).TT_PGCN_REG = 0 */ | |
331 (vm->state).PTTN_REG = 1; | |
332 (vm->state).HL_BTNN_REG = 1 << 10; | |
333 (vm->state).PTL_REG = 15; /* Parental Level */ | |
334 (vm->state).registers.SPRM[12] = ('U'<<8)|'S'; /* Parental Management Country Code */ | |
335 (vm->state).registers.SPRM[16] = ('e'<<8)|'n'; /* Initial Language Code for Audio */ | |
336 (vm->state).registers.SPRM[18] = ('e'<<8)|'n'; /* Initial Language Code for Spu */ | |
337 (vm->state).registers.SPRM[20] = 0x1; /* Player Regional Code Mask. Region free! */ | |
338 (vm->state).registers.SPRM[14] = 0x100; /* Try Pan&Scan */ | |
388 | 339 |
225 | 340 (vm->state).pgN = 0; |
341 (vm->state).cellN = 0; | |
342 (vm->state).cell_restart = 0; | |
343 | |
344 (vm->state).domain = FP_DOMAIN; | |
345 (vm->state).rsm_vtsN = 0; | |
346 (vm->state).rsm_cellN = 0; | |
347 (vm->state).rsm_blockN = 0; | |
388 | 348 |
225 | 349 (vm->state).vtsN = -1; |
388 | 350 |
225 | 351 if (vm->dvd && dvdroot) { |
352 /* a new dvd device has been requested */ | |
353 vm_stop(vm); | |
354 } | |
355 if (!vm->dvd) { | |
356 vm->dvd = DVDOpen(dvdroot); | |
357 if(!vm->dvd) { | |
260 | 358 fprintf(MSG_OUT, "libdvdnav: vm: failed to open/read the DVD\n"); |
225 | 359 return 0; |
360 } | |
361 vm->vmgi = ifoOpenVMGI(vm->dvd); | |
362 if(!vm->vmgi) { | |
260 | 363 fprintf(MSG_OUT, "libdvdnav: vm: failed to read VIDEO_TS.IFO\n"); |
225 | 364 return 0; |
365 } | |
366 if(!ifoRead_FP_PGC(vm->vmgi)) { | |
367 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_FP_PGC failed\n"); | |
368 return 0; | |
369 } | |
370 if(!ifoRead_TT_SRPT(vm->vmgi)) { | |
371 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_TT_SRPT failed\n"); | |
372 return 0; | |
373 } | |
374 if(!ifoRead_PGCI_UT(vm->vmgi)) { | |
375 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PGCI_UT failed\n"); | |
376 return 0; | |
377 } | |
378 if(!ifoRead_PTL_MAIT(vm->vmgi)) { | |
379 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_PTL_MAIT failed\n"); | |
380 /* return 0; Not really used for now.. */ | |
381 } | |
382 if(!ifoRead_VTS_ATRT(vm->vmgi)) { | |
383 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VTS_ATRT failed\n"); | |
384 /* return 0; Not really used for now.. */ | |
385 } | |
386 if(!ifoRead_VOBU_ADMAP(vm->vmgi)) { | |
387 fprintf(MSG_OUT, "libdvdnav: vm: ifoRead_VOBU_ADMAP vgmi failed\n"); | |
388 /* return 0; Not really used for now.. */ | |
389 } | |
390 /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */ | |
404
d16ee5945580
Prevent display of garbage volume label when the file being scanned is
nicodvb
parents:
403
diff
changeset
|
391 dvd_read_name(vm->dvd_name, vm->dvd_serial, dvdroot); |
d16ee5945580
Prevent display of garbage volume label when the file being scanned is
nicodvb
parents:
403
diff
changeset
|
392 vm->map = remap_loadmap(vm->dvd_name); |
225 | 393 } |
394 if (vm->vmgi) { | |
395 int i, mask; | |
396 fprintf(MSG_OUT, "libdvdnav: DVD disk reports itself with Region mask 0x%08x. Regions:", | |
397 vm->vmgi->vmgi_mat->vmg_category); | |
398 for (i = 1, mask = 1; i <= 8; i++, mask <<= 1) | |
399 if (((vm->vmgi->vmgi_mat->vmg_category >> 16) & mask) == 0) | |
400 fprintf(MSG_OUT, " %d", i); | |
401 fprintf(MSG_OUT, "\n"); | |
402 } | |
403 return 1; | |
404 } | |
405 | |
406 | |
407 /* copying and merging */ | |
408 | |
409 vm_t *vm_new_copy(vm_t *source) { | |
410 vm_t *target = vm_new_vm(); | |
411 int vtsN; | |
412 int pgcN = get_PGCN(source); | |
413 int pgN = (source->state).pgN; | |
388 | 414 |
225 | 415 assert(pgcN); |
388 | 416 |
225 | 417 memcpy(target, source, sizeof(vm_t)); |
388 | 418 |
225 | 419 /* open a new vtsi handle, because the copy might switch to another VTS */ |
420 target->vtsi = NULL; | |
421 vtsN = (target->state).vtsN; | |
422 if (vtsN > 0) { | |
423 (target->state).vtsN = 0; | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
424 if (!ifoOpenNewVTSI(target, target->dvd, vtsN)) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
425 assert(0); |
388 | 426 |
225 | 427 /* restore pgc pointer into the new vtsi */ |
428 if (!set_PGCN(target, pgcN)) | |
429 assert(0); | |
430 (target->state).pgN = pgN; | |
431 } | |
388 | 432 |
225 | 433 return target; |
434 } | |
435 | |
436 void vm_merge(vm_t *target, vm_t *source) { | |
437 if(target->vtsi) | |
438 ifoClose(target->vtsi); | |
439 memcpy(target, source, sizeof(vm_t)); | |
440 memset(source, 0, sizeof(vm_t)); | |
441 } | |
442 | |
443 void vm_free_copy(vm_t *vm) { | |
444 if(vm->vtsi) | |
445 ifoClose(vm->vtsi); | |
446 free(vm); | |
447 } | |
448 | |
449 | |
450 /* regular playback */ | |
451 | |
452 void vm_position_get(vm_t *vm, vm_position_t *position) { | |
453 position->button = (vm->state).HL_BTNN_REG >> 10; | |
388 | 454 position->vts = (vm->state).vtsN; |
455 position->domain = (vm->state).domain; | |
225 | 456 position->spu_channel = (vm->state).SPST_REG; |
457 position->audio_channel = (vm->state).AST_REG; | |
458 position->angle_channel = (vm->state).AGL_REG; | |
459 position->hop_channel = vm->hop_channel; /* Increases by one on each hop */ | |
460 position->cell = (vm->state).cellN; | |
461 position->cell_restart = (vm->state).cell_restart; | |
462 position->cell_start = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector; | |
463 position->still = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].still_time; | |
464 position->block = (vm->state).blockN; | |
465 | |
466 /* handle PGC stills at PGC end */ | |
467 if ((vm->state).cellN == (vm->state).pgc->nr_of_cells) | |
468 position->still += (vm->state).pgc->still_time; | |
469 /* still already determined */ | |
470 if (position->still) | |
471 return; | |
472 /* This is a rough fix for some strange still situations on some strange DVDs. | |
473 * There are discs (like the German "Back to the Future" RC2) where the only | |
474 * indication of a still is a cell playback time higher than the time the frames | |
475 * in this cell actually take to play (like 1 frame with 1 minute playback time). | |
476 * On the said BTTF disc, for these cells last_sector and last_vobu_start_sector | |
477 * are equal and the cells are very short, so we abuse these conditions to | |
478 * detect such discs. I consider these discs broken, so the fix is somewhat | |
479 * broken, too. */ | |
480 if (((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector == | |
481 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_vobu_start_sector) && | |
482 ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector - | |
483 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector < 1024)) { | |
484 int time; | |
485 int size = (vm->state).pgc->cell_playback[(vm->state).cellN - 1].last_sector - | |
486 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].first_sector; | |
487 time = ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour >> 4 ) * 36000; | |
488 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.hour & 0x0f) * 3600; | |
489 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute >> 4 ) * 600; | |
490 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.minute & 0x0f) * 60; | |
491 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second >> 4 ) * 10; | |
492 time += ((vm->state).pgc->cell_playback[(vm->state).cellN - 1].playback_time.second & 0x0f) * 1; | |
246 | 493 if (!time || size / time > 30) |
225 | 494 /* datarate is too high, it might be a very short, but regular cell */ |
495 return; | |
496 if (time > 0xff) time = 0xff; | |
497 position->still = time; | |
498 } | |
499 } | |
500 | |
501 void vm_get_next_cell(vm_t *vm) { | |
502 process_command(vm, play_Cell_post(vm)); | |
503 } | |
504 | |
505 | |
506 /* Jumping */ | |
507 | |
508 int vm_jump_pg(vm_t *vm, int pg) { | |
509 (vm->state).pgN = pg; | |
510 process_command(vm, play_PG(vm)); | |
511 return 1; | |
512 } | |
513 | |
514 int vm_jump_cell_block(vm_t *vm, int cell, int block) { | |
515 (vm->state).cellN = cell; | |
516 process_command(vm, play_Cell(vm)); | |
517 /* play_Cell can jump to a different cell in case of angles */ | |
518 if ((vm->state).cellN == cell) | |
519 (vm->state).blockN = block; | |
520 return 1; | |
521 } | |
522 | |
523 int vm_jump_title_part(vm_t *vm, int title, int part) { | |
524 link_t link; | |
388 | 525 |
225 | 526 if(!set_PTT(vm, title, part)) |
527 return 0; | |
528 /* Some DVDs do not want us to jump directly into a title and have | |
529 * PGC pre commands taking us back to some menu. Since we do not like that, | |
530 * we do not execute PGC pre commands that would do a jump. */ | |
531 /* process_command(vm, play_PGC_PG(vm, (vm->state).pgN)); */ | |
532 link = play_PGC_PG(vm, (vm->state).pgN); | |
533 if (link.command != PlayThis) | |
534 /* jump occured -> ignore it and play the PG anyway */ | |
535 process_command(vm, play_PG(vm)); | |
536 else | |
537 process_command(vm, link); | |
538 return 1; | |
539 } | |
540 | |
541 int vm_jump_top_pg(vm_t *vm) { | |
542 process_command(vm, play_PG(vm)); | |
543 return 1; | |
544 } | |
545 | |
546 int vm_jump_next_pg(vm_t *vm) { | |
547 if((vm->state).pgN >= (vm->state).pgc->nr_of_programs) { | |
548 /* last program -> move to TailPGC */ | |
549 process_command(vm, play_PGC_post(vm)); | |
550 return 1; | |
551 } else { | |
552 vm_jump_pg(vm, (vm->state).pgN + 1); | |
553 return 1; | |
554 } | |
555 } | |
556 | |
557 int vm_jump_prev_pg(vm_t *vm) { | |
558 if ((vm->state).pgN <= 1) { | |
559 /* first program -> move to last program of previous PGC */ | |
560 if ((vm->state).pgc->prev_pgc_nr && set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) { | |
561 process_command(vm, play_PGC(vm)); | |
562 vm_jump_pg(vm, (vm->state).pgc->nr_of_programs); | |
563 return 1; | |
564 } | |
565 return 0; | |
566 } else { | |
567 vm_jump_pg(vm, (vm->state).pgN - 1); | |
568 return 1; | |
569 } | |
570 } | |
571 | |
572 int vm_jump_up(vm_t *vm) { | |
573 if((vm->state).pgc->goup_pgc_nr && set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) { | |
574 process_command(vm, play_PGC(vm)); | |
575 return 1; | |
576 } | |
577 return 0; | |
578 } | |
579 | |
580 int vm_jump_menu(vm_t *vm, DVDMenuID_t menuid) { | |
581 domain_t old_domain = (vm->state).domain; | |
388 | 582 |
225 | 583 switch ((vm->state).domain) { |
584 case VTS_DOMAIN: | |
585 set_RSMinfo(vm, 0, (vm->state).blockN); | |
586 /* FALL THROUGH */ | |
587 case VTSM_DOMAIN: | |
588 case VMGM_DOMAIN: | |
589 switch(menuid) { | |
590 case DVD_MENU_Title: | |
591 case DVD_MENU_Escape: | |
592 (vm->state).domain = VMGM_DOMAIN; | |
593 break; | |
594 case DVD_MENU_Root: | |
595 case DVD_MENU_Subpicture: | |
596 case DVD_MENU_Audio: | |
597 case DVD_MENU_Angle: | |
598 case DVD_MENU_Part: | |
599 (vm->state).domain = VTSM_DOMAIN; | |
600 break; | |
601 } | |
602 if(get_PGCIT(vm) && set_MENU(vm, menuid)) { | |
603 process_command(vm, play_PGC(vm)); | |
604 return 1; /* Jump */ | |
605 } else { | |
606 (vm->state).domain = old_domain; | |
607 } | |
608 break; | |
609 case FP_DOMAIN: /* FIXME XXX $$$ What should we do here? */ | |
610 break; | |
611 } | |
388 | 612 |
225 | 613 return 0; |
614 } | |
615 | |
616 int vm_jump_resume(vm_t *vm) { | |
617 link_t link_values = { LinkRSM, 0, 0, 0 }; | |
618 | |
619 if (!(vm->state).rsm_vtsN) /* Do we have resume info? */ | |
620 return 0; | |
621 if (!process_command(vm, link_values)) | |
622 return 0; | |
623 return 1; | |
624 } | |
625 | |
626 int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd) { | |
627 link_t link_values; | |
388 | 628 |
225 | 629 if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values)) |
630 return process_command(vm, link_values); | |
631 else | |
632 return 0; /* It updated some state thats all... */ | |
633 } | |
634 | |
635 | |
636 /* getting information */ | |
637 | |
638 int vm_get_current_menu(vm_t *vm, int *menuid) { | |
639 pgcit_t* pgcit; | |
640 int pgcn; | |
641 pgcn = (vm->state).pgcN; | |
642 pgcit = get_PGCIT(vm); | |
345
f051b111ef50
10l to me: in vm_get_current_menu() I forgot to attach
nicodvb
parents:
344
diff
changeset
|
643 if(pgcit==NULL) return 0; |
225 | 644 *menuid = pgcit->pgci_srp[pgcn - 1].entry_id & 0xf ; |
645 return 1; | |
646 } | |
647 | |
648 int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) { | |
649 vts_ptt_srpt_t *vts_ptt_srpt; | |
650 int title, part = 0, vts_ttn; | |
651 int found; | |
652 int16_t pgcN, pgN; | |
653 | |
654 vts_ptt_srpt = vm->vtsi->vts_ptt_srpt; | |
655 pgcN = get_PGCN(vm); | |
656 pgN = vm->state.pgN; | |
657 | |
658 found = 0; | |
659 for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) { | |
660 for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) { | |
661 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) { | |
662 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN) { | |
663 found = 1; | |
664 break; | |
665 } | |
666 if (part > 0 && vts_ptt_srpt->title[vts_ttn].ptt[part].pgn > pgN && | |
667 vts_ptt_srpt->title[vts_ttn].ptt[part - 1].pgn < pgN) { | |
668 part--; | |
669 found = 1; | |
670 break; | |
671 } | |
672 } | |
673 } | |
674 if (found) break; | |
675 } | |
676 vts_ttn++; | |
677 part++; | |
388 | 678 |
225 | 679 if (!found) { |
680 fprintf(MSG_OUT, "libdvdnav: chapter NOT FOUND!\n"); | |
681 return 0; | |
682 } | |
683 | |
684 title = get_TT(vm, vm->state.vtsN, vts_ttn); | |
685 | |
686 #ifdef TRACE | |
687 if (title) { | |
688 fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n"); | |
689 fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n", | |
690 title, part, | |
691 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgcn , | |
692 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgn ); | |
693 } | |
694 #endif | |
695 *title_result = title; | |
696 *part_result = part; | |
697 return 1; | |
698 } | |
699 | |
700 /* Return the substream id for 'logical' audio stream audioN. | |
701 * 0 <= audioN < 8 | |
702 */ | |
703 int vm_get_audio_stream(vm_t *vm, int audioN) { | |
704 int streamN = -1; | |
705 | |
706 if((vm->state).domain != VTS_DOMAIN) | |
707 audioN = 0; | |
388 | 708 |
225 | 709 if(audioN < 8) { |
388 | 710 /* Is there any control info for this logical stream */ |
225 | 711 if((vm->state).pgc->audio_control[audioN] & (1<<15)) { |
388 | 712 streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07; |
225 | 713 } |
714 } | |
388 | 715 |
225 | 716 if((vm->state).domain != VTS_DOMAIN && streamN == -1) |
717 streamN = 0; | |
388 | 718 |
225 | 719 /* FIXME: Should also check in vtsi/vmgi status what kind of stream |
720 * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */ | |
721 return streamN; | |
722 } | |
723 | |
724 /* Return the substream id for 'logical' subpicture stream subpN and given mode. | |
725 * 0 <= subpN < 32 | |
726 * mode == 0 - widescreen | |
727 * mode == 1 - letterbox | |
728 * mode == 2 - pan&scan | |
729 */ | |
730 int vm_get_subp_stream(vm_t *vm, int subpN, int mode) { | |
731 int streamN = -1; | |
732 int source_aspect = vm_get_video_aspect(vm); | |
388 | 733 |
225 | 734 if((vm->state).domain != VTS_DOMAIN) |
735 subpN = 0; | |
388 | 736 |
225 | 737 if(subpN < 32) { /* a valid logical stream */ |
388 | 738 /* Is this logical stream present */ |
225 | 739 if((vm->state).pgc->subp_control[subpN] & (1<<31)) { |
388 | 740 if(source_aspect == 0) /* 4:3 */ |
741 streamN = ((vm->state).pgc->subp_control[subpN] >> 24) & 0x1f; | |
225 | 742 if(source_aspect == 3) /* 16:9 */ |
743 switch (mode) { | |
744 case 0: | |
745 streamN = ((vm->state).pgc->subp_control[subpN] >> 16) & 0x1f; | |
746 break; | |
747 case 1: | |
748 streamN = ((vm->state).pgc->subp_control[subpN] >> 8) & 0x1f; | |
749 break; | |
750 case 2: | |
751 streamN = (vm->state).pgc->subp_control[subpN] & 0x1f; | |
752 } | |
753 } | |
754 } | |
388 | 755 |
247 | 756 if((vm->state).domain != VTS_DOMAIN && streamN == -1) |
757 streamN = 0; | |
225 | 758 |
759 /* FIXME: Should also check in vtsi/vmgi status what kind of stream it is. */ | |
760 return streamN; | |
761 } | |
762 | |
763 int vm_get_audio_active_stream(vm_t *vm) { | |
764 int audioN; | |
765 int streamN; | |
766 audioN = (vm->state).AST_REG ; | |
767 streamN = vm_get_audio_stream(vm, audioN); | |
388 | 768 |
225 | 769 /* If no such stream, then select the first one that exists. */ |
770 if(streamN == -1) { | |
771 for(audioN = 0; audioN < 8; audioN++) { | |
772 if((vm->state).pgc->audio_control[audioN] & (1<<15)) { | |
773 if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0) | |
774 break; | |
775 } | |
776 } | |
777 } | |
778 | |
779 return streamN; | |
780 } | |
781 | |
782 int vm_get_subp_active_stream(vm_t *vm, int mode) { | |
783 int subpN; | |
784 int streamN; | |
785 subpN = (vm->state).SPST_REG & ~0x40; | |
786 streamN = vm_get_subp_stream(vm, subpN, mode); | |
388 | 787 |
225 | 788 /* If no such stream, then select the first one that exists. */ |
789 if(streamN == -1) { | |
790 for(subpN = 0; subpN < 32; subpN++) { | |
791 if((vm->state).pgc->subp_control[subpN] & (1<<31)) { | |
792 if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0) | |
793 break; | |
794 } | |
795 } | |
796 } | |
797 | |
798 if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40)) | |
799 /* Bit 7 set means hide, and only let Forced display show */ | |
800 return (streamN | 0x80); | |
801 else | |
802 return streamN; | |
803 } | |
804 | |
805 void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) { | |
806 *num_avail = 1; | |
807 *current = 1; | |
388 | 808 |
225 | 809 if((vm->state).domain == VTS_DOMAIN) { |
810 title_info_t *title; | |
811 /* TTN_REG does not allways point to the correct title.. */ | |
812 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) | |
813 return; | |
814 title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1]; | |
388 | 815 if(title->title_set_nr != (vm->state).vtsN || |
225 | 816 title->vts_ttn != (vm->state).VTS_TTN_REG) |
388 | 817 return; |
225 | 818 *num_avail = title->nr_of_angles; |
819 *current = (vm->state).AGL_REG; | |
820 } | |
821 } | |
822 | |
823 #if 0 | |
824 /* currently unused */ | |
825 void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) { | |
826 switch ((vm->state).domain) { | |
827 case VTS_DOMAIN: | |
828 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams; | |
829 *current = (vm->state).AST_REG; | |
830 break; | |
831 case VTSM_DOMAIN: | |
832 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */ | |
833 *current = 1; | |
834 break; | |
835 case VMGM_DOMAIN: | |
836 case FP_DOMAIN: | |
837 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */ | |
838 *current = 1; | |
839 break; | |
840 } | |
841 } | |
842 | |
843 /* currently unused */ | |
844 void vm_get_subp_info(vm_t *vm, int *current, int *num_avail) { | |
845 switch ((vm->state).domain) { | |
846 case VTS_DOMAIN: | |
847 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams; | |
848 *current = (vm->state).SPST_REG; | |
849 break; | |
850 case VTSM_DOMAIN: | |
851 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */ | |
852 *current = 0x41; | |
853 break; | |
854 case VMGM_DOMAIN: | |
855 case FP_DOMAIN: | |
856 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */ | |
857 *current = 0x41; | |
858 break; | |
859 } | |
860 } | |
401 | 861 #endif |
225 | 862 |
863 void vm_get_video_res(vm_t *vm, int *width, int *height) { | |
864 video_attr_t attr = vm_get_video_attr(vm); | |
388 | 865 |
866 if(attr.video_format != 0) | |
225 | 867 *height = 576; |
868 else | |
869 *height = 480; | |
870 switch(attr.picture_size) { | |
871 case 0: | |
872 *width = 720; | |
873 break; | |
874 case 1: | |
875 *width = 704; | |
876 break; | |
877 case 2: | |
878 *width = 352; | |
879 break; | |
880 case 3: | |
881 *width = 352; | |
882 *height /= 2; | |
883 break; | |
884 } | |
885 } | |
886 | |
887 int vm_get_video_aspect(vm_t *vm) { | |
888 int aspect = vm_get_video_attr(vm).display_aspect_ratio; | |
388 | 889 |
225 | 890 assert(aspect == 0 || aspect == 3); |
891 (vm->state).registers.SPRM[14] &= ~(0x3 << 10); | |
892 (vm->state).registers.SPRM[14] |= aspect << 10; | |
388 | 893 |
225 | 894 return aspect; |
895 } | |
896 | |
897 int vm_get_video_scale_permission(vm_t *vm) { | |
898 return vm_get_video_attr(vm).permitted_df; | |
899 } | |
900 | |
901 video_attr_t vm_get_video_attr(vm_t *vm) { | |
902 switch ((vm->state).domain) { | |
903 case VTS_DOMAIN: | |
904 return vm->vtsi->vtsi_mat->vts_video_attr; | |
905 case VTSM_DOMAIN: | |
906 return vm->vtsi->vtsi_mat->vtsm_video_attr; | |
907 case VMGM_DOMAIN: | |
908 case FP_DOMAIN: | |
909 return vm->vmgi->vmgi_mat->vmgm_video_attr; | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
910 default: |
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
911 abort(); |
225 | 912 } |
913 } | |
914 | |
915 audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) { | |
916 switch ((vm->state).domain) { | |
917 case VTS_DOMAIN: | |
918 return vm->vtsi->vtsi_mat->vts_audio_attr[streamN]; | |
919 case VTSM_DOMAIN: | |
920 return vm->vtsi->vtsi_mat->vtsm_audio_attr; | |
921 case VMGM_DOMAIN: | |
922 case FP_DOMAIN: | |
923 return vm->vmgi->vmgi_mat->vmgm_audio_attr; | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
924 default: |
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
925 abort(); |
225 | 926 } |
927 } | |
928 | |
929 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) { | |
930 switch ((vm->state).domain) { | |
931 case VTS_DOMAIN: | |
932 return vm->vtsi->vtsi_mat->vts_subp_attr[streamN]; | |
933 case VTSM_DOMAIN: | |
934 return vm->vtsi->vtsi_mat->vtsm_subp_attr; | |
935 case VMGM_DOMAIN: | |
936 case FP_DOMAIN: | |
937 return vm->vmgi->vmgi_mat->vmgm_subp_attr; | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
938 default: |
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
939 abort(); |
225 | 940 } |
941 } | |
942 | |
943 | |
944 /* Playback control */ | |
945 | |
946 static link_t play_PGC(vm_t *vm) { | |
947 link_t link_values; | |
388 | 948 |
225 | 949 #ifdef TRACE |
950 fprintf(MSG_OUT, "libdvdnav: play_PGC:"); | |
951 if((vm->state).domain != FP_DOMAIN) { | |
952 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm)); | |
953 } else { | |
954 fprintf(MSG_OUT, " first_play_pgc\n"); | |
955 } | |
956 #endif | |
957 | |
958 /* This must be set before the pre-commands are executed because they | |
959 * might contain a CallSS that will save resume state */ | |
960 | |
961 /* FIXME: This may be only a temporary fix for something... */ | |
962 (vm->state).pgN = 1; | |
963 (vm->state).cellN = 0; | |
964 (vm->state).blockN = 0; | |
965 | |
388 | 966 /* eval -> updates the state and returns either |
225 | 967 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) |
968 - just play video i.e first PG | |
969 (This is what happens if you fall of the end of the pre_cmds) | |
970 - or an error (are there more cases?) */ | |
971 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { | |
388 | 972 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, |
973 (vm->state).pgc->command_tbl->nr_of_pre, | |
225 | 974 &(vm->state).registers, &link_values)) { |
975 /* link_values contains the 'jump' return value */ | |
976 return link_values; | |
977 } else { | |
978 #ifdef TRACE | |
979 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n"); | |
980 #endif | |
981 } | |
982 } | |
983 return play_PG(vm); | |
388 | 984 } |
225 | 985 |
388 | 986 static link_t play_PGC_PG(vm_t *vm, int pgN) { |
225 | 987 link_t link_values; |
388 | 988 |
225 | 989 #ifdef TRACE |
990 fprintf(MSG_OUT, "libdvdnav: play_PGC_PG:"); | |
991 if((vm->state).domain != FP_DOMAIN) { | |
992 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm)); | |
993 } else { | |
994 fprintf(MSG_OUT, " first_play_pgc\n"); | |
995 } | |
996 #endif | |
997 | |
998 /* This must be set before the pre-commands are executed because they | |
999 * might contain a CallSS that will save resume state */ | |
1000 | |
1001 /* FIXME: This may be only a temporary fix for something... */ | |
1002 (vm->state).pgN = pgN; | |
1003 (vm->state).cellN = 0; | |
1004 (vm->state).blockN = 0; | |
1005 | |
388 | 1006 /* eval -> updates the state and returns either |
225 | 1007 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) |
1008 - just play video i.e first PG | |
1009 (This is what happens if you fall of the end of the pre_cmds) | |
1010 - or an error (are there more cases?) */ | |
1011 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { | |
388 | 1012 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, |
1013 (vm->state).pgc->command_tbl->nr_of_pre, | |
225 | 1014 &(vm->state).registers, &link_values)) { |
1015 /* link_values contains the 'jump' return value */ | |
1016 return link_values; | |
1017 } else { | |
1018 #ifdef TRACE | |
1019 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n"); | |
1020 #endif | |
1021 } | |
1022 } | |
1023 return play_PG(vm); | |
388 | 1024 } |
225 | 1025 |
1026 static link_t play_PGC_post(vm_t *vm) { | |
1027 link_t link_values; | |
1028 | |
1029 #ifdef TRACE | |
1030 fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n"); | |
1031 #endif | |
388 | 1032 |
1033 /* eval -> updates the state and returns either | |
225 | 1034 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) |
1035 - just go to next PGC | |
1036 (This is what happens if you fall of the end of the post_cmds) | |
1037 - or an error (are there more cases?) */ | |
1038 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_post && | |
1039 vmEval_CMD((vm->state).pgc->command_tbl->post_cmds, | |
388 | 1040 (vm->state).pgc->command_tbl->nr_of_post, |
225 | 1041 &(vm->state).registers, &link_values)) { |
1042 return link_values; | |
1043 } | |
388 | 1044 |
225 | 1045 #ifdef TRACE |
1046 fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n"); | |
1047 #endif | |
1048 /* Should end up in the STOP_DOMAIN if next_pgc is 0. */ | |
1049 if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) { | |
1050 link_values.command = Exit; | |
1051 return link_values; | |
1052 } | |
1053 return play_PGC(vm); | |
1054 } | |
1055 | |
1056 static link_t play_PG(vm_t *vm) { | |
1057 #ifdef TRACE | |
1058 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN); | |
1059 #endif | |
388 | 1060 |
225 | 1061 assert((vm->state).pgN > 0); |
1062 if((vm->state).pgN > (vm->state).pgc->nr_of_programs) { | |
1063 #ifdef TRACE | |
388 | 1064 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i) > pgc->nr_of_programs (%i)\n", |
225 | 1065 (vm->state).pgN, (vm->state).pgc->nr_of_programs ); |
1066 #endif | |
388 | 1067 assert((vm->state).pgN == (vm->state).pgc->nr_of_programs + 1); |
225 | 1068 return play_PGC_post(vm); |
1069 } | |
388 | 1070 |
225 | 1071 (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1]; |
388 | 1072 |
225 | 1073 return play_Cell(vm); |
1074 } | |
1075 | |
1076 static link_t play_Cell(vm_t *vm) { | |
1077 static const link_t play_this = {PlayThis, /* Block in Cell */ 0, 0, 0}; | |
1078 | |
1079 #ifdef TRACE | |
1080 fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN); | |
1081 #endif | |
388 | 1082 |
225 | 1083 assert((vm->state).cellN > 0); |
1084 if((vm->state).cellN > (vm->state).pgc->nr_of_cells) { | |
1085 #ifdef TRACE | |
388 | 1086 fprintf(MSG_OUT, "libdvdnav: (vm->state).cellN (%i) > pgc->nr_of_cells (%i)\n", |
225 | 1087 (vm->state).cellN, (vm->state).pgc->nr_of_cells ); |
1088 #endif | |
388 | 1089 assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1); |
225 | 1090 return play_PGC_post(vm); |
1091 } | |
388 | 1092 |
225 | 1093 /* Multi angle/Interleaved */ |
1094 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { | |
1095 case 0: /* Normal */ | |
1096 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); | |
1097 break; | |
1098 case 1: /* The first cell in the block */ | |
1099 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) { | |
1100 case 0: /* Not part of a block */ | |
1101 assert(0); | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
1102 break; |
225 | 1103 case 1: /* Angle block */ |
1104 /* Loop and check each cell instead? So we don't get outside the block? */ | |
1105 (vm->state).cellN += (vm->state).AGL_REG - 1; | |
1106 #ifdef STRICT | |
1107 assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells); | |
1108 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0); | |
1109 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1); | |
1110 #else | |
1111 if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) || | |
1112 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) || | |
1113 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) { | |
1114 fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n"); | |
1115 (vm->state).cellN -= (vm->state).AGL_REG - 1; | |
1116 } | |
1117 #endif | |
1118 break; | |
1119 case 2: /* ?? */ | |
1120 case 3: /* ?? */ | |
1121 default: | |
1122 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", | |
1123 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, | |
1124 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); | |
1125 assert(0); | |
1126 } | |
1127 break; | |
1128 case 2: /* Cell in the block */ | |
1129 case 3: /* Last cell in the block */ | |
1130 /* These might perhaps happen for RSM or LinkC commands? */ | |
1131 default: | |
1132 fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n"); | |
1133 } | |
388 | 1134 |
225 | 1135 /* Updates (vm->state).pgN and PTTN_REG */ |
1136 if(!set_PGN(vm)) { | |
1137 /* Should not happen */ | |
1138 assert(0); | |
1139 return play_PGC_post(vm); | |
1140 } | |
1141 (vm->state).cell_restart++; | |
1142 (vm->state).blockN = 0; | |
1143 #ifdef TRACE | |
1144 fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n"); | |
1145 #endif | |
1146 return play_this; | |
1147 } | |
1148 | |
1149 static link_t play_Cell_post(vm_t *vm) { | |
1150 cell_playback_t *cell; | |
388 | 1151 |
225 | 1152 #ifdef TRACE |
1153 fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN); | |
1154 #endif | |
388 | 1155 |
225 | 1156 cell = &(vm->state).pgc->cell_playback[(vm->state).cellN - 1]; |
388 | 1157 |
225 | 1158 /* Still time is already taken care of before we get called. */ |
388 | 1159 |
225 | 1160 /* Deal with a Cell command, if any */ |
1161 if(cell->cell_cmd_nr != 0) { | |
1162 link_t link_values; | |
388 | 1163 |
225 | 1164 /* These asserts are now not needed. |
1165 * Some DVDs have no cell commands listed in the PGC, | |
1166 * but the Cell itself points to a cell command that does not exist. | |
1167 * For this situation, just ignore the cell command and continue. | |
1168 * | |
1169 * assert((vm->state).pgc->command_tbl != NULL); | |
1170 * assert((vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr); | |
1171 */ | |
1172 | |
1173 if ((vm->state).pgc->command_tbl != NULL && | |
1174 (vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr) { | |
1175 #ifdef TRACE | |
1176 fprintf(MSG_OUT, "libdvdnav: Cell command present, executing\n"); | |
1177 #endif | |
1178 if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1, | |
1179 &(vm->state).registers, &link_values)) { | |
1180 return link_values; | |
1181 } else { | |
1182 #ifdef TRACE | |
1183 fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n"); | |
1184 #endif | |
1185 } | |
1186 } else { | |
1187 #ifdef TRACE | |
1188 fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n"); | |
1189 #endif | |
1190 } | |
1191 } | |
388 | 1192 |
225 | 1193 /* Where to continue after playing the cell... */ |
1194 /* Multi angle/Interleaved */ | |
1195 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { | |
1196 case 0: /* Normal */ | |
1197 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); | |
1198 (vm->state).cellN++; | |
1199 break; | |
1200 case 1: /* The first cell in the block */ | |
1201 case 2: /* A cell in the block */ | |
1202 case 3: /* The last cell in the block */ | |
1203 default: | |
1204 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) { | |
1205 case 0: /* Not part of a block */ | |
1206 assert(0); | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
1207 break; |
225 | 1208 case 1: /* Angle block */ |
1209 /* Skip the 'other' angles */ | |
1210 (vm->state).cellN++; | |
1211 while((vm->state).cellN <= (vm->state).pgc->nr_of_cells && | |
1212 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) { | |
1213 (vm->state).cellN++; | |
1214 } | |
1215 break; | |
1216 case 2: /* ?? */ | |
1217 case 3: /* ?? */ | |
1218 default: | |
1219 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", | |
1220 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, | |
1221 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); | |
1222 assert(0); | |
1223 } | |
1224 break; | |
1225 } | |
388 | 1226 |
1227 /* Figure out the correct pgN for the new cell */ | |
225 | 1228 if(!set_PGN(vm)) { |
1229 #ifdef TRACE | |
1230 fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n"); | |
1231 #endif | |
1232 return play_PGC_post(vm); | |
1233 } | |
1234 return play_Cell(vm); | |
1235 } | |
1236 | |
1237 | |
1238 /* link processing */ | |
1239 | |
1240 static int process_command(vm_t *vm, link_t link_values) { | |
388 | 1241 |
225 | 1242 while(link_values.command != PlayThis) { |
388 | 1243 |
225 | 1244 #ifdef TRACE |
1245 fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n"); | |
1246 vm_print_link(link_values); | |
388 | 1247 fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command, |
225 | 1248 link_values.data1, link_values.data2, link_values.data3); |
1249 vm_print_current_domain_state(vm); | |
1250 fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n"); | |
1251 #endif | |
388 | 1252 |
225 | 1253 switch(link_values.command) { |
1254 case LinkNoLink: | |
1255 /* BUTTON number:data1 */ | |
1256 if(link_values.data1 != 0) | |
1257 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1258 return 0; /* no actual jump */ | |
1259 | |
1260 case LinkTopC: | |
1261 /* Restart playing from the beginning of the current Cell. */ | |
1262 /* BUTTON number:data1 */ | |
1263 if(link_values.data1 != 0) | |
1264 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1265 link_values = play_Cell(vm); | |
1266 break; | |
1267 case LinkNextC: | |
1268 /* Link to Next Cell */ | |
1269 /* BUTTON number:data1 */ | |
1270 if(link_values.data1 != 0) | |
1271 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1272 (vm->state).cellN += 1; | |
1273 link_values = play_Cell(vm); | |
1274 break; | |
1275 case LinkPrevC: | |
1276 /* Link to Previous Cell */ | |
1277 /* BUTTON number:data1 */ | |
1278 if(link_values.data1 != 0) | |
1279 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1280 assert((vm->state).cellN > 1); | |
1281 (vm->state).cellN -= 1; | |
1282 link_values = play_Cell(vm); | |
1283 break; | |
388 | 1284 |
225 | 1285 case LinkTopPG: |
1286 /* Link to Top of current Program */ | |
1287 /* BUTTON number:data1 */ | |
1288 if(link_values.data1 != 0) | |
1289 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1290 link_values = play_PG(vm); | |
1291 break; | |
1292 case LinkNextPG: | |
1293 /* Link to Next Program */ | |
1294 /* BUTTON number:data1 */ | |
1295 if(link_values.data1 != 0) | |
1296 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1297 (vm->state).pgN += 1; | |
1298 link_values = play_PG(vm); | |
1299 break; | |
1300 case LinkPrevPG: | |
1301 /* Link to Previous Program */ | |
1302 /* BUTTON number:data1 */ | |
1303 if(link_values.data1 != 0) | |
1304 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1305 assert((vm->state).pgN > 1); | |
1306 (vm->state).pgN -= 1; | |
1307 link_values = play_PG(vm); | |
1308 break; | |
1309 | |
1310 case LinkTopPGC: | |
1311 /* Restart playing from beginning of current Program Chain */ | |
1312 /* BUTTON number:data1 */ | |
1313 if(link_values.data1 != 0) | |
1314 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1315 link_values = play_PGC(vm); | |
1316 break; | |
1317 case LinkNextPGC: | |
1318 /* Link to Next Program Chain */ | |
1319 /* BUTTON number:data1 */ | |
1320 if(link_values.data1 != 0) | |
1321 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1322 assert((vm->state).pgc->next_pgc_nr != 0); | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1323 if(set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1324 link_values = play_PGC(vm); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1325 else |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1326 link_values.command = Exit; |
225 | 1327 break; |
1328 case LinkPrevPGC: | |
1329 /* Link to Previous Program Chain */ | |
1330 /* BUTTON number:data1 */ | |
1331 if(link_values.data1 != 0) | |
1332 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1333 assert((vm->state).pgc->prev_pgc_nr != 0); | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1334 if(set_PGCN(vm, (vm->state).pgc->prev_pgc_nr)) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1335 link_values = play_PGC(vm); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1336 else |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1337 link_values.command = Exit; |
225 | 1338 break; |
1339 case LinkGoUpPGC: | |
1340 /* Link to GoUp Program Chain */ | |
1341 /* BUTTON number:data1 */ | |
1342 if(link_values.data1 != 0) | |
1343 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1344 assert((vm->state).pgc->goup_pgc_nr != 0); | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1345 if(set_PGCN(vm, (vm->state).pgc->goup_pgc_nr)) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1346 link_values = play_PGC(vm); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1347 else |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1348 link_values.command = Exit; |
225 | 1349 break; |
1350 case LinkTailPGC: | |
1351 /* Link to Tail of Program Chain */ | |
1352 /* BUTTON number:data1 */ | |
1353 if(link_values.data1 != 0) | |
1354 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1355 link_values = play_PGC_post(vm); | |
1356 break; | |
1357 | |
1358 case LinkRSM: | |
1359 { | |
1360 /* Link to Resume point */ | |
1361 int i; | |
388 | 1362 |
225 | 1363 /* Check and see if there is any rsm info!! */ |
1364 if (!(vm->state).rsm_vtsN) { | |
1365 fprintf(MSG_OUT, "libdvdnav: trying to resume without any resume info set\n"); | |
1366 link_values.command = Exit; | |
1367 break; | |
1368 } | |
388 | 1369 |
225 | 1370 (vm->state).domain = VTS_DOMAIN; |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1371 if (!ifoOpenNewVTSI(vm, vm->dvd, (vm->state).rsm_vtsN)) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1372 assert(0); |
225 | 1373 set_PGCN(vm, (vm->state).rsm_pgcN); |
388 | 1374 |
1375 /* These should never be set in SystemSpace and/or MenuSpace */ | |
225 | 1376 /* (vm->state).TTN_REG = rsm_tt; ?? */ |
1377 /* (vm->state).TT_PGCN_REG = (vm->state).rsm_pgcN; ?? */ | |
1378 for(i = 0; i < 5; i++) { | |
1379 (vm->state).registers.SPRM[4 + i] = (vm->state).rsm_regs[i]; | |
1380 } | |
388 | 1381 |
225 | 1382 if(link_values.data1 != 0) |
1383 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
388 | 1384 |
225 | 1385 if((vm->state).rsm_cellN == 0) { |
1386 assert((vm->state).cellN); /* Checking if this ever happens */ | |
1387 (vm->state).pgN = 1; | |
1388 link_values = play_PG(vm); | |
388 | 1389 } else { |
252
aee8af592d66
fix a long-standing problem: sometimes, hitting Escape in the movie and then
mroi
parents:
247
diff
changeset
|
1390 /* (vm->state).pgN = ?? this gets the right value in set_PGN() below */ |
225 | 1391 (vm->state).cellN = (vm->state).rsm_cellN; |
1392 link_values.command = PlayThis; | |
252
aee8af592d66
fix a long-standing problem: sometimes, hitting Escape in the movie and then
mroi
parents:
247
diff
changeset
|
1393 link_values.data1 = (vm->state).rsm_blockN & 0xffff; |
aee8af592d66
fix a long-standing problem: sometimes, hitting Escape in the movie and then
mroi
parents:
247
diff
changeset
|
1394 link_values.data2 = (vm->state).rsm_blockN >> 16; |
225 | 1395 if(!set_PGN(vm)) { |
1396 /* Were at the end of the PGC, should not happen for a RSM */ | |
1397 assert(0); | |
1398 link_values.command = LinkTailPGC; | |
1399 link_values.data1 = 0; /* No button */ | |
1400 } | |
1401 } | |
1402 } | |
1403 break; | |
1404 case LinkPGCN: | |
1405 /* Link to Program Chain Number:data1 */ | |
1406 if(!set_PGCN(vm, link_values.data1)) | |
1407 assert(0); | |
1408 link_values = play_PGC(vm); | |
1409 break; | |
1410 case LinkPTTN: | |
1411 /* Link to Part of current Title Number:data1 */ | |
1412 /* BUTTON number:data2 */ | |
1413 /* PGC Pre-Commands are not executed */ | |
1414 assert((vm->state).domain == VTS_DOMAIN); | |
1415 if(link_values.data2 != 0) | |
1416 (vm->state).HL_BTNN_REG = link_values.data2 << 10; | |
1417 if(!set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1)) | |
1418 assert(0); | |
1419 link_values = play_PG(vm); | |
1420 break; | |
1421 case LinkPGN: | |
1422 /* Link to Program Number:data1 */ | |
1423 /* BUTTON number:data2 */ | |
1424 if(link_values.data2 != 0) | |
1425 (vm->state).HL_BTNN_REG = link_values.data2 << 10; | |
1426 /* Update any other state, PTTN perhaps? */ | |
1427 (vm->state).pgN = link_values.data1; | |
1428 link_values = play_PG(vm); | |
1429 break; | |
1430 case LinkCN: | |
1431 /* Link to Cell Number:data1 */ | |
1432 /* BUTTON number:data2 */ | |
1433 if(link_values.data2 != 0) | |
1434 (vm->state).HL_BTNN_REG = link_values.data2 << 10; | |
1435 /* Update any other state, pgN, PTTN perhaps? */ | |
1436 (vm->state).cellN = link_values.data1; | |
1437 link_values = play_Cell(vm); | |
1438 break; | |
388 | 1439 |
225 | 1440 case Exit: |
1441 vm->stopped = 1; | |
1442 return 0; | |
388 | 1443 |
225 | 1444 case JumpTT: |
1445 /* Jump to VTS Title Domain */ | |
1446 /* Only allowed from the First Play domain(PGC) */ | |
1447 /* or the Video Manager domain (VMG) */ | |
1448 /* Stop SPRM9 Timer */ | |
1449 /* Set SPRM1 and SPRM2 */ | |
1450 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1451 if(set_TT(vm, link_values.data1)) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1452 link_values = play_PGC(vm); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1453 else |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1454 link_values.command = Exit; |
225 | 1455 break; |
1456 case JumpVTS_TT: | |
1457 /* Jump to Title:data1 in same VTS Title Domain */ | |
1458 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1459 /* or the Video Title Set Domain(VTS) */ | |
1460 /* Stop SPRM9 Timer */ | |
1461 /* Set SPRM1 and SPRM2 */ | |
1462 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1463 if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1)) | |
1464 assert(0); | |
1465 link_values = play_PGC(vm); | |
1466 break; | |
1467 case JumpVTS_PTT: | |
1468 /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */ | |
1469 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1470 /* or the Video Title Set Domain(VTS) */ | |
1471 /* Stop SPRM9 Timer */ | |
1472 /* Set SPRM1 and SPRM2 */ | |
1473 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1474 if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2)) | |
1475 assert(0); | |
1476 link_values = play_PGC_PG(vm, (vm->state).pgN); | |
1477 break; | |
388 | 1478 |
225 | 1479 case JumpSS_FP: |
1480 /* Jump to First Play Domain */ | |
1481 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1482 /* or the Video Manager domain (VMG) */ | |
1483 /* Stop SPRM9 Timer and any GPRM counters */ | |
1484 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); /* ?? */ | |
1485 if (!set_FP_PGC(vm)) | |
1486 assert(0); | |
1487 link_values = play_PGC(vm); | |
1488 break; | |
1489 case JumpSS_VMGM_MENU: | |
1490 /* Jump to Video Manger domain - Title Menu:data1 or any PGC in VMG */ | |
1491 /* Allowed from anywhere except the VTS Title domain */ | |
1492 /* Stop SPRM9 Timer and any GPRM counters */ | |
1493 assert((vm->state).domain != VTS_DOMAIN); /* ?? */ | |
1494 (vm->state).domain = VMGM_DOMAIN; | |
1495 if(!set_MENU(vm, link_values.data1)) | |
1496 assert(0); | |
1497 link_values = play_PGC(vm); | |
1498 break; | |
1499 case JumpSS_VTSM: | |
1500 /* Jump to a menu in Video Title domain, */ | |
1501 /* or to a Menu is the current VTS */ | |
1502 /* Stop SPRM9 Timer and any GPRM counters */ | |
1503 /* ifoOpenNewVTSI:data1 */ | |
1504 /* VTS_TTN_REG:data2 */ | |
388 | 1505 /* get_MENU:data3 */ |
225 | 1506 if(link_values.data1 != 0) { |
1507 if (link_values.data1 != (vm->state).vtsN) { | |
1508 /* the normal case */ | |
1509 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ | |
1510 (vm->state).domain = VTSM_DOMAIN; | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1511 if (!ifoOpenNewVTSI(vm, vm->dvd, link_values.data1)) /* Also sets (vm->state).vtsN */ |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1512 assert(0); |
225 | 1513 } else { |
1514 /* This happens on some discs like "Captain Scarlet & the Mysterons" or | |
1515 * the German RC2 of "Anatomie" in VTSM. */ | |
1516 assert((vm->state).domain == VTSM_DOMAIN || | |
1517 (vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ | |
1518 (vm->state).domain = VTSM_DOMAIN; | |
1519 } | |
1520 } else { | |
1521 /* This happens on 'The Fifth Element' region 2. */ | |
1522 assert((vm->state).domain == VTSM_DOMAIN); | |
1523 } | |
1524 /* I don't know what title is supposed to be used for. */ | |
1525 /* Alien or Aliens has this != 1, I think. */ | |
1526 /* assert(link_values.data2 == 1); */ | |
1527 (vm->state).VTS_TTN_REG = link_values.data2; | |
1528 /* TTN_REG (SPRM4), VTS_TTN_REG (SPRM5), TT_PGCN_REG (SPRM6) are linked, */ | |
1529 /* so if one changes, the others must change to match it. */ | |
1530 (vm->state).TTN_REG = get_TT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG); | |
1531 if(!set_MENU(vm, link_values.data3)) | |
1532 assert(0); | |
1533 link_values = play_PGC(vm); | |
1534 break; | |
1535 case JumpSS_VMGM_PGC: | |
1536 /* set_PGCN:data1 */ | |
1537 /* Stop SPRM9 Timer and any GPRM counters */ | |
1538 assert((vm->state).domain != VTS_DOMAIN); /* ?? */ | |
1539 (vm->state).domain = VMGM_DOMAIN; | |
1540 if(!set_PGCN(vm, link_values.data1)) | |
1541 assert(0); | |
1542 link_values = play_PGC(vm); | |
1543 break; | |
388 | 1544 |
225 | 1545 case CallSS_FP: |
1546 /* set_RSMinfo:data1 */ | |
1547 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1548 /* Must be called before domain is changed */ | |
1549 set_RSMinfo(vm, link_values.data1, /* We dont have block info */ 0); | |
1550 set_FP_PGC(vm); | |
1551 link_values = play_PGC(vm); | |
1552 break; | |
1553 case CallSS_VMGM_MENU: | |
388 | 1554 /* set_MENU:data1 */ |
225 | 1555 /* set_RSMinfo:data2 */ |
1556 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1557 /* Must be called before domain is changed */ | |
388 | 1558 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); |
225 | 1559 (vm->state).domain = VMGM_DOMAIN; |
1560 if(!set_MENU(vm, link_values.data1)) | |
1561 assert(0); | |
1562 link_values = play_PGC(vm); | |
1563 break; | |
1564 case CallSS_VTSM: | |
388 | 1565 /* set_MENU:data1 */ |
225 | 1566 /* set_RSMinfo:data2 */ |
1567 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1568 /* Must be called before domain is changed */ | |
1569 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); | |
1570 (vm->state).domain = VTSM_DOMAIN; | |
1571 if(!set_MENU(vm, link_values.data1)) | |
1572 assert(0); | |
1573 link_values = play_PGC(vm); | |
1574 break; | |
1575 case CallSS_VMGM_PGC: | |
1576 /* set_PGC:data1 */ | |
1577 /* set_RSMinfo:data2 */ | |
1578 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1579 /* Must be called before domain is changed */ | |
1580 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); | |
1581 (vm->state).domain = VMGM_DOMAIN; | |
1582 if(!set_PGCN(vm, link_values.data1)) | |
1583 assert(0); | |
1584 link_values = play_PGC(vm); | |
1585 break; | |
1586 case PlayThis: | |
1587 /* Should never happen. */ | |
1588 assert(0); | |
1589 break; | |
1590 } | |
1591 | |
1592 #ifdef TRACE | |
1593 fprintf(MSG_OUT, "libdvdnav: After printout starts:\n"); | |
1594 vm_print_current_domain_state(vm); | |
1595 fprintf(MSG_OUT, "libdvdnav: After printout ends.\n"); | |
1596 #endif | |
388 | 1597 |
225 | 1598 } |
252
aee8af592d66
fix a long-standing problem: sometimes, hitting Escape in the movie and then
mroi
parents:
247
diff
changeset
|
1599 (vm->state).blockN = link_values.data1 | (link_values.data2 << 16); |
225 | 1600 return 1; |
1601 } | |
1602 | |
1603 | |
1604 /* Set functions */ | |
1605 | |
388 | 1606 static int set_TT(vm_t *vm, int tt) { |
225 | 1607 return set_PTT(vm, tt, 1); |
1608 } | |
1609 | |
1610 static int set_PTT(vm_t *vm, int tt, int ptt) { | |
1611 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts); | |
1612 return set_VTS_PTT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr, | |
1613 vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, ptt); | |
1614 } | |
1615 | |
1616 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) { | |
1617 return set_VTS_PTT(vm, vtsN, vts_ttn, 1); | |
1618 } | |
1619 | |
1620 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) { | |
1621 int pgcN, pgN, res; | |
388 | 1622 |
225 | 1623 (vm->state).domain = VTS_DOMAIN; |
1624 | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1625 if (vtsN != (vm->state).vtsN) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1626 if (!ifoOpenNewVTSI(vm, vm->dvd, vtsN)) /* Also sets (vm->state).vtsN */ |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1627 return 0; |
388 | 1628 |
225 | 1629 if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) || |
1630 (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) { | |
1631 return 0; | |
1632 } | |
388 | 1633 |
225 | 1634 pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn; |
1635 pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn; | |
388 | 1636 |
225 | 1637 (vm->state).TT_PGCN_REG = pgcN; |
1638 (vm->state).PTTN_REG = part; | |
1639 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn); | |
1640 assert( (vm->state.TTN_REG) != 0 ); | |
1641 (vm->state).VTS_TTN_REG = vts_ttn; | |
1642 (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */ | |
1643 /* Any other registers? */ | |
388 | 1644 |
225 | 1645 res = set_PGCN(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */ |
1646 (vm->state).pgN = pgN; | |
1647 return res; | |
1648 } | |
1649 | |
388 | 1650 static int set_FP_PGC(vm_t *vm) { |
225 | 1651 (vm->state).domain = FP_DOMAIN; |
254
f78669338b49
Fix segfault if the DVD does not contain a FP_PGC.
jcdutton
parents:
252
diff
changeset
|
1652 if (!vm->vmgi->first_play_pgc) { |
f78669338b49
Fix segfault if the DVD does not contain a FP_PGC.
jcdutton
parents:
252
diff
changeset
|
1653 return set_PGCN(vm, 1); |
f78669338b49
Fix segfault if the DVD does not contain a FP_PGC.
jcdutton
parents:
252
diff
changeset
|
1654 } |
225 | 1655 (vm->state).pgc = vm->vmgi->first_play_pgc; |
1656 (vm->state).pgcN = vm->vmgi->vmgi_mat->first_play_pgc; | |
1657 return 1; | |
1658 } | |
1659 | |
1660 | |
1661 static int set_MENU(vm_t *vm, int menu) { | |
1662 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); | |
1663 return set_PGCN(vm, get_ID(vm, menu)); | |
1664 } | |
1665 | |
1666 static int set_PGCN(vm_t *vm, int pgcN) { | |
1667 pgcit_t *pgcit; | |
388 | 1668 |
225 | 1669 pgcit = get_PGCIT(vm); |
1670 assert(pgcit != NULL); /* ?? Make this return -1 instead */ | |
1671 | |
1672 if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) { | |
1673 #ifdef TRACE | |
1674 fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN); | |
1675 #endif | |
1676 return 0; | |
1677 } | |
388 | 1678 |
225 | 1679 (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc; |
1680 (vm->state).pgcN = pgcN; | |
1681 (vm->state).pgN = 1; | |
388 | 1682 |
225 | 1683 if((vm->state).domain == VTS_DOMAIN) |
1684 (vm->state).TT_PGCN_REG = pgcN; | |
1685 | |
1686 return 1; | |
1687 } | |
1688 | |
388 | 1689 /* Figure out the correct pgN from the cell and update (vm->state). */ |
225 | 1690 static int set_PGN(vm_t *vm) { |
1691 int new_pgN = 0; | |
403
1ce807c12563
in vm:c set_PGN removed restriction that didn't play multi-PGC titles; patch by John Stebbins
nicodvb
parents:
401
diff
changeset
|
1692 int dummy, part; |
388 | 1693 |
1694 while(new_pgN < (vm->state).pgc->nr_of_programs | |
225 | 1695 && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN]) |
1696 new_pgN++; | |
388 | 1697 |
225 | 1698 if(new_pgN == (vm->state).pgc->nr_of_programs) /* We are at the last program */ |
1699 if((vm->state).cellN > (vm->state).pgc->nr_of_cells) | |
1700 return 0; /* We are past the last cell */ | |
388 | 1701 |
225 | 1702 (vm->state).pgN = new_pgN; |
388 | 1703 |
225 | 1704 if((vm->state).domain == VTS_DOMAIN) { |
1705 playback_type_t *pb_ty; | |
1706 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) | |
1707 return 0; /* ?? */ | |
1708 pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty; | |
1709 vm_get_current_title_part(vm, &dummy, &part); | |
1710 (vm->state).PTTN_REG = part; | |
1711 } | |
1712 return 1; | |
1713 } | |
1714 | |
1715 /* Must be called before domain is changed (set_PGCN()) */ | |
1716 static void set_RSMinfo(vm_t *vm, int cellN, int blockN) { | |
1717 int i; | |
388 | 1718 |
225 | 1719 if(cellN) { |
1720 (vm->state).rsm_cellN = cellN; | |
1721 (vm->state).rsm_blockN = blockN; | |
1722 } else { | |
1723 (vm->state).rsm_cellN = (vm->state).cellN; | |
1724 (vm->state).rsm_blockN = blockN; | |
1725 } | |
1726 (vm->state).rsm_vtsN = (vm->state).vtsN; | |
1727 (vm->state).rsm_pgcN = get_PGCN(vm); | |
388 | 1728 |
225 | 1729 /* assert((vm->state).rsm_pgcN == (vm->state).TT_PGCN_REG); for VTS_DOMAIN */ |
388 | 1730 |
225 | 1731 for(i = 0; i < 5; i++) { |
1732 (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i]; | |
1733 } | |
1734 } | |
1735 | |
1736 | |
1737 /* Get functions */ | |
1738 | |
1739 /* Searches the TT tables, to find the current TT. | |
1740 * returns the current TT. | |
1741 * returns 0 if not found. | |
1742 */ | |
1743 static int get_TT(vm_t *vm, int vtsN, int vts_ttn) { | |
1744 int i; | |
1745 int tt=0; | |
1746 | |
1747 for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) { | |
388 | 1748 if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN && |
225 | 1749 vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) { |
1750 tt=i; | |
1751 break; | |
1752 } | |
1753 } | |
1754 return tt; | |
1755 } | |
1756 | |
1757 /* Search for entry_id match of the PGC Category in the current VTS PGCIT table. | |
1758 * Return pgcN based on entry_id match. | |
1759 */ | |
1760 static int get_ID(vm_t *vm, int id) { | |
1761 int pgcN, i; | |
1762 pgcit_t *pgcit; | |
388 | 1763 |
225 | 1764 /* Relies on state to get the correct pgcit. */ |
1765 pgcit = get_PGCIT(vm); | |
1766 assert(pgcit != NULL); | |
1767 #ifdef TRACE | |
1768 fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id); | |
1769 #endif | |
1770 | |
1771 /* Force high bit set. */ | |
1772 id |=0x80; | |
1773 | |
1774 /* Get menu/title */ | |
1775 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { | |
1776 if( (pgcit->pgci_srp[i].entry_id) == id) { | |
1777 pgcN = i + 1; | |
1778 #ifdef TRACE | |
1779 fprintf(MSG_OUT, "libdvdnav: Found menu.\n"); | |
1780 #endif | |
1781 return pgcN; | |
1782 } | |
1783 } | |
1784 #ifdef TRACE | |
1785 fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f); | |
1786 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { | |
1787 if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) { | |
1788 fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n", | |
1789 pgcit->pgci_srp[i].entry_id & 0x7f); | |
1790 } | |
1791 } | |
1792 #endif | |
1793 return 0; /* error */ | |
1794 } | |
1795 | |
1796 /* FIXME: we have a pgcN member in the vm's state now, so this should be obsolete */ | |
1797 static int get_PGCN(vm_t *vm) { | |
1798 pgcit_t *pgcit; | |
1799 int pgcN = 1; | |
1800 | |
1801 pgcit = get_PGCIT(vm); | |
388 | 1802 |
225 | 1803 if (pgcit) { |
1804 while(pgcN <= pgcit->nr_of_pgci_srp) { | |
1805 if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) { | |
1806 assert((vm->state).pgcN == pgcN); | |
1807 return pgcN; | |
1808 } | |
1809 pgcN++; | |
1810 } | |
1811 } | |
388 | 1812 fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n", |
225 | 1813 (vm->state).domain); |
1814 return 0; /* error */ | |
1815 } | |
1816 | |
1817 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) { | |
1818 int i; | |
388 | 1819 |
225 | 1820 if(h == NULL || h->pgci_ut == NULL) { |
1821 fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n"); | |
1822 return NULL; /* error? */ | |
1823 } | |
388 | 1824 |
225 | 1825 i = 0; |
1826 while(i < h->pgci_ut->nr_of_lus | |
1827 && h->pgci_ut->lu[i].lang_code != lang) | |
1828 i++; | |
1829 if(i == h->pgci_ut->nr_of_lus) { | |
1830 fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n", | |
1831 (char)(lang >> 8), (char)(lang & 0xff), | |
1832 (char)(h->pgci_ut->lu[0].lang_code >> 8), | |
1833 (char)(h->pgci_ut->lu[0].lang_code & 0xff)); | |
1834 fprintf(MSG_OUT, "libdvdnav: Menu Languages available: "); | |
1835 for(i = 0; i < h->pgci_ut->nr_of_lus; i++) { | |
1836 fprintf(MSG_OUT, "%c%c ", | |
1837 (char)(h->pgci_ut->lu[i].lang_code >> 8), | |
1838 (char)(h->pgci_ut->lu[i].lang_code & 0xff)); | |
1839 } | |
1840 fprintf(MSG_OUT, "\n"); | |
1841 i = 0; /* error? */ | |
1842 } | |
388 | 1843 |
225 | 1844 return h->pgci_ut->lu[i].pgcit; |
1845 } | |
1846 | |
1847 /* Uses state to decide what to return */ | |
1848 static pgcit_t* get_PGCIT(vm_t *vm) { | |
344
fb2fbd4cfbf6
in get_PGCIT() check the validity of vm->vtsi before risking to dereference NULL;
nicodvb
parents:
332
diff
changeset
|
1849 pgcit_t *pgcit = NULL; |
388 | 1850 |
225 | 1851 switch ((vm->state).domain) { |
1852 case VTS_DOMAIN: | |
344
fb2fbd4cfbf6
in get_PGCIT() check the validity of vm->vtsi before risking to dereference NULL;
nicodvb
parents:
332
diff
changeset
|
1853 if(!vm->vtsi) return NULL; |
225 | 1854 pgcit = vm->vtsi->vts_pgcit; |
1855 break; | |
1856 case VTSM_DOMAIN: | |
344
fb2fbd4cfbf6
in get_PGCIT() check the validity of vm->vtsi before risking to dereference NULL;
nicodvb
parents:
332
diff
changeset
|
1857 if(!vm->vtsi) return NULL; |
225 | 1858 pgcit = get_MENU_PGCIT(vm, vm->vtsi, (vm->state).registers.SPRM[0]); |
1859 break; | |
1860 case VMGM_DOMAIN: | |
1861 case FP_DOMAIN: | |
1862 pgcit = get_MENU_PGCIT(vm, vm->vmgi, (vm->state).registers.SPRM[0]); | |
1863 break; | |
1864 default: | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
1865 abort(); |
225 | 1866 } |
388 | 1867 |
225 | 1868 return pgcit; |
1869 } | |
1870 | |
388 | 1871 //return the ifo_handle_t describing required title, used to |
312
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1872 //identify chapters |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1873 ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title) |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1874 { |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1875 ifo_handle_t *ifo = NULL; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1876 uint8_t titleset_nr; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1877 if((title < 1) || (title > vm->vmgi->tt_srpt->nr_of_srpts)) |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1878 return NULL; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1879 titleset_nr = vm->vmgi->tt_srpt->title[title-1].title_set_nr; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1880 ifo = ifoOpen(vm->dvd, titleset_nr); |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1881 return ifo; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1882 } |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1883 |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1884 void vm_ifo_close(ifo_handle_t *ifo) |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1885 { |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1886 ifoClose(ifo); |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1887 } |
225 | 1888 |
1889 /* Debug functions */ | |
1890 | |
1891 #ifdef TRACE | |
1892 void vm_position_print(vm_t *vm, vm_position_t *position) { | |
1893 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", | |
1894 position->button, | |
1895 position->spu_channel, | |
1896 position->audio_channel, | |
1897 position->angle_channel, | |
1898 position->hop_channel, | |
1899 position->vts, | |
1900 position->domain, | |
1901 position->cell, | |
1902 position->cell_restart, | |
1903 position->cell_start, | |
1904 position->still, | |
1905 position->block); | |
1906 } | |
1907 #endif | |
1908 |