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