Mercurial > libdvdnav.hg
annotate vm/vm.c @ 411:ce9b314b6e43 src
If there is no VMGI or PGCI return instead of try to get them
If there is no menu there isn't much point in trying to jump to them.
author | erik |
---|---|
date | Fri, 30 Jul 2010 23:34:24 +0000 |
parents | 799f85209145 |
children | 34e632fb6a39 |
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: | |
612 (vm->state).domain = VMGM_DOMAIN; | |
613 break; | |
614 case DVD_MENU_Root: | |
615 case DVD_MENU_Subpicture: | |
616 case DVD_MENU_Audio: | |
617 case DVD_MENU_Angle: | |
618 case DVD_MENU_Part: | |
619 (vm->state).domain = VTSM_DOMAIN; | |
620 break; | |
621 } | |
411
ce9b314b6e43
If there is no VMGI or PGCI return instead of try to get them
erik
parents:
410
diff
changeset
|
622 if(vm->vmgi == NULL || vm->vmgi->pgci_ut == NULL) |
ce9b314b6e43
If there is no VMGI or PGCI return instead of try to get them
erik
parents:
410
diff
changeset
|
623 return 0; |
ce9b314b6e43
If there is no VMGI or PGCI return instead of try to get them
erik
parents:
410
diff
changeset
|
624 else if(get_PGCIT(vm) && set_MENU(vm, menuid)) { |
225 | 625 process_command(vm, play_PGC(vm)); |
626 return 1; /* Jump */ | |
627 } else { | |
628 (vm->state).domain = old_domain; | |
629 } | |
630 break; | |
631 case FP_DOMAIN: /* FIXME XXX $$$ What should we do here? */ | |
632 break; | |
633 } | |
388 | 634 |
225 | 635 return 0; |
636 } | |
637 | |
638 int vm_jump_resume(vm_t *vm) { | |
639 link_t link_values = { LinkRSM, 0, 0, 0 }; | |
640 | |
641 if (!(vm->state).rsm_vtsN) /* Do we have resume info? */ | |
642 return 0; | |
643 if (!process_command(vm, link_values)) | |
644 return 0; | |
645 return 1; | |
646 } | |
647 | |
648 int vm_exec_cmd(vm_t *vm, vm_cmd_t *cmd) { | |
649 link_t link_values; | |
388 | 650 |
225 | 651 if(vmEval_CMD(cmd, 1, &(vm->state).registers, &link_values)) |
652 return process_command(vm, link_values); | |
653 else | |
654 return 0; /* It updated some state thats all... */ | |
655 } | |
656 | |
657 | |
658 /* getting information */ | |
659 | |
660 int vm_get_current_menu(vm_t *vm, int *menuid) { | |
661 pgcit_t* pgcit; | |
662 int pgcn; | |
663 pgcn = (vm->state).pgcN; | |
664 pgcit = get_PGCIT(vm); | |
345
f051b111ef50
10l to me: in vm_get_current_menu() I forgot to attach
nicodvb
parents:
344
diff
changeset
|
665 if(pgcit==NULL) return 0; |
225 | 666 *menuid = pgcit->pgci_srp[pgcn - 1].entry_id & 0xf ; |
667 return 1; | |
668 } | |
669 | |
670 int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) { | |
671 vts_ptt_srpt_t *vts_ptt_srpt; | |
672 int title, part = 0, vts_ttn; | |
673 int found; | |
674 int16_t pgcN, pgN; | |
675 | |
676 vts_ptt_srpt = vm->vtsi->vts_ptt_srpt; | |
677 pgcN = get_PGCN(vm); | |
678 pgN = vm->state.pgN; | |
679 | |
680 found = 0; | |
681 for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) { | |
682 for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) { | |
683 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) { | |
684 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN) { | |
685 found = 1; | |
686 break; | |
687 } | |
688 if (part > 0 && vts_ptt_srpt->title[vts_ttn].ptt[part].pgn > pgN && | |
689 vts_ptt_srpt->title[vts_ttn].ptt[part - 1].pgn < pgN) { | |
690 part--; | |
691 found = 1; | |
692 break; | |
693 } | |
694 } | |
695 } | |
696 if (found) break; | |
697 } | |
698 vts_ttn++; | |
699 part++; | |
388 | 700 |
225 | 701 if (!found) { |
702 fprintf(MSG_OUT, "libdvdnav: chapter NOT FOUND!\n"); | |
703 return 0; | |
704 } | |
705 | |
706 title = get_TT(vm, vm->state.vtsN, vts_ttn); | |
707 | |
708 #ifdef TRACE | |
709 if (title) { | |
710 fprintf(MSG_OUT, "libdvdnav: ************ this chapter FOUND!\n"); | |
711 fprintf(MSG_OUT, "libdvdnav: VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i\n", | |
712 title, part, | |
713 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgcn , | |
714 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgn ); | |
715 } | |
716 #endif | |
717 *title_result = title; | |
718 *part_result = part; | |
719 return 1; | |
720 } | |
721 | |
722 /* Return the substream id for 'logical' audio stream audioN. | |
723 * 0 <= audioN < 8 | |
724 */ | |
725 int vm_get_audio_stream(vm_t *vm, int audioN) { | |
726 int streamN = -1; | |
727 | |
728 if((vm->state).domain != VTS_DOMAIN) | |
729 audioN = 0; | |
388 | 730 |
225 | 731 if(audioN < 8) { |
388 | 732 /* Is there any control info for this logical stream */ |
225 | 733 if((vm->state).pgc->audio_control[audioN] & (1<<15)) { |
388 | 734 streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07; |
225 | 735 } |
736 } | |
388 | 737 |
225 | 738 if((vm->state).domain != VTS_DOMAIN && streamN == -1) |
739 streamN = 0; | |
388 | 740 |
225 | 741 /* FIXME: Should also check in vtsi/vmgi status what kind of stream |
742 * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */ | |
743 return streamN; | |
744 } | |
745 | |
746 /* Return the substream id for 'logical' subpicture stream subpN and given mode. | |
747 * 0 <= subpN < 32 | |
748 * mode == 0 - widescreen | |
749 * mode == 1 - letterbox | |
750 * mode == 2 - pan&scan | |
751 */ | |
752 int vm_get_subp_stream(vm_t *vm, int subpN, int mode) { | |
753 int streamN = -1; | |
754 int source_aspect = vm_get_video_aspect(vm); | |
388 | 755 |
225 | 756 if((vm->state).domain != VTS_DOMAIN) |
757 subpN = 0; | |
388 | 758 |
225 | 759 if(subpN < 32) { /* a valid logical stream */ |
388 | 760 /* Is this logical stream present */ |
225 | 761 if((vm->state).pgc->subp_control[subpN] & (1<<31)) { |
388 | 762 if(source_aspect == 0) /* 4:3 */ |
763 streamN = ((vm->state).pgc->subp_control[subpN] >> 24) & 0x1f; | |
225 | 764 if(source_aspect == 3) /* 16:9 */ |
765 switch (mode) { | |
766 case 0: | |
767 streamN = ((vm->state).pgc->subp_control[subpN] >> 16) & 0x1f; | |
768 break; | |
769 case 1: | |
770 streamN = ((vm->state).pgc->subp_control[subpN] >> 8) & 0x1f; | |
771 break; | |
772 case 2: | |
773 streamN = (vm->state).pgc->subp_control[subpN] & 0x1f; | |
774 } | |
775 } | |
776 } | |
388 | 777 |
247 | 778 if((vm->state).domain != VTS_DOMAIN && streamN == -1) |
779 streamN = 0; | |
225 | 780 |
781 /* FIXME: Should also check in vtsi/vmgi status what kind of stream it is. */ | |
782 return streamN; | |
783 } | |
784 | |
785 int vm_get_audio_active_stream(vm_t *vm) { | |
786 int audioN; | |
787 int streamN; | |
788 audioN = (vm->state).AST_REG ; | |
789 streamN = vm_get_audio_stream(vm, audioN); | |
388 | 790 |
225 | 791 /* If no such stream, then select the first one that exists. */ |
792 if(streamN == -1) { | |
793 for(audioN = 0; audioN < 8; audioN++) { | |
794 if((vm->state).pgc->audio_control[audioN] & (1<<15)) { | |
795 if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0) | |
796 break; | |
797 } | |
798 } | |
799 } | |
800 | |
801 return streamN; | |
802 } | |
803 | |
804 int vm_get_subp_active_stream(vm_t *vm, int mode) { | |
805 int subpN; | |
806 int streamN; | |
807 subpN = (vm->state).SPST_REG & ~0x40; | |
808 streamN = vm_get_subp_stream(vm, subpN, mode); | |
388 | 809 |
225 | 810 /* If no such stream, then select the first one that exists. */ |
811 if(streamN == -1) { | |
812 for(subpN = 0; subpN < 32; subpN++) { | |
813 if((vm->state).pgc->subp_control[subpN] & (1<<31)) { | |
814 if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0) | |
815 break; | |
816 } | |
817 } | |
818 } | |
819 | |
820 if((vm->state).domain == VTS_DOMAIN && !((vm->state).SPST_REG & 0x40)) | |
821 /* Bit 7 set means hide, and only let Forced display show */ | |
822 return (streamN | 0x80); | |
823 else | |
824 return streamN; | |
825 } | |
826 | |
827 void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) { | |
828 *num_avail = 1; | |
829 *current = 1; | |
388 | 830 |
225 | 831 if((vm->state).domain == VTS_DOMAIN) { |
832 title_info_t *title; | |
833 /* TTN_REG does not allways point to the correct title.. */ | |
834 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) | |
835 return; | |
836 title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1]; | |
388 | 837 if(title->title_set_nr != (vm->state).vtsN || |
225 | 838 title->vts_ttn != (vm->state).VTS_TTN_REG) |
388 | 839 return; |
225 | 840 *num_avail = title->nr_of_angles; |
841 *current = (vm->state).AGL_REG; | |
842 } | |
843 } | |
844 | |
845 #if 0 | |
846 /* currently unused */ | |
847 void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) { | |
848 switch ((vm->state).domain) { | |
849 case VTS_DOMAIN: | |
850 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams; | |
851 *current = (vm->state).AST_REG; | |
852 break; | |
853 case VTSM_DOMAIN: | |
854 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */ | |
855 *current = 1; | |
856 break; | |
857 case VMGM_DOMAIN: | |
858 case FP_DOMAIN: | |
859 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */ | |
860 *current = 1; | |
861 break; | |
862 } | |
863 } | |
864 | |
865 /* currently unused */ | |
866 void vm_get_subp_info(vm_t *vm, int *current, int *num_avail) { | |
867 switch ((vm->state).domain) { | |
868 case VTS_DOMAIN: | |
869 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams; | |
870 *current = (vm->state).SPST_REG; | |
871 break; | |
872 case VTSM_DOMAIN: | |
873 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */ | |
874 *current = 0x41; | |
875 break; | |
876 case VMGM_DOMAIN: | |
877 case FP_DOMAIN: | |
878 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */ | |
879 *current = 0x41; | |
880 break; | |
881 } | |
882 } | |
401 | 883 #endif |
225 | 884 |
885 void vm_get_video_res(vm_t *vm, int *width, int *height) { | |
886 video_attr_t attr = vm_get_video_attr(vm); | |
388 | 887 |
888 if(attr.video_format != 0) | |
225 | 889 *height = 576; |
890 else | |
891 *height = 480; | |
892 switch(attr.picture_size) { | |
893 case 0: | |
894 *width = 720; | |
895 break; | |
896 case 1: | |
897 *width = 704; | |
898 break; | |
899 case 2: | |
900 *width = 352; | |
901 break; | |
902 case 3: | |
903 *width = 352; | |
904 *height /= 2; | |
905 break; | |
906 } | |
907 } | |
908 | |
909 int vm_get_video_aspect(vm_t *vm) { | |
910 int aspect = vm_get_video_attr(vm).display_aspect_ratio; | |
388 | 911 |
225 | 912 assert(aspect == 0 || aspect == 3); |
913 (vm->state).registers.SPRM[14] &= ~(0x3 << 10); | |
914 (vm->state).registers.SPRM[14] |= aspect << 10; | |
388 | 915 |
225 | 916 return aspect; |
917 } | |
918 | |
919 int vm_get_video_scale_permission(vm_t *vm) { | |
920 return vm_get_video_attr(vm).permitted_df; | |
921 } | |
922 | |
923 video_attr_t vm_get_video_attr(vm_t *vm) { | |
924 switch ((vm->state).domain) { | |
925 case VTS_DOMAIN: | |
926 return vm->vtsi->vtsi_mat->vts_video_attr; | |
927 case VTSM_DOMAIN: | |
928 return vm->vtsi->vtsi_mat->vtsm_video_attr; | |
929 case VMGM_DOMAIN: | |
930 case FP_DOMAIN: | |
931 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
|
932 default: |
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
933 abort(); |
225 | 934 } |
935 } | |
936 | |
937 audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) { | |
938 switch ((vm->state).domain) { | |
939 case VTS_DOMAIN: | |
940 return vm->vtsi->vtsi_mat->vts_audio_attr[streamN]; | |
941 case VTSM_DOMAIN: | |
942 return vm->vtsi->vtsi_mat->vtsm_audio_attr; | |
943 case VMGM_DOMAIN: | |
944 case FP_DOMAIN: | |
945 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
|
946 default: |
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
947 abort(); |
225 | 948 } |
949 } | |
950 | |
951 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) { | |
952 switch ((vm->state).domain) { | |
953 case VTS_DOMAIN: | |
954 return vm->vtsi->vtsi_mat->vts_subp_attr[streamN]; | |
955 case VTSM_DOMAIN: | |
956 return vm->vtsi->vtsi_mat->vtsm_subp_attr; | |
957 case VMGM_DOMAIN: | |
958 case FP_DOMAIN: | |
959 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
|
960 default: |
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
961 abort(); |
225 | 962 } |
963 } | |
964 | |
965 | |
966 /* Playback control */ | |
967 | |
968 static link_t play_PGC(vm_t *vm) { | |
969 link_t link_values; | |
388 | 970 |
225 | 971 #ifdef TRACE |
972 fprintf(MSG_OUT, "libdvdnav: play_PGC:"); | |
973 if((vm->state).domain != FP_DOMAIN) { | |
974 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm)); | |
975 } else { | |
976 fprintf(MSG_OUT, " first_play_pgc\n"); | |
977 } | |
978 #endif | |
979 | |
980 /* This must be set before the pre-commands are executed because they | |
981 * might contain a CallSS that will save resume state */ | |
982 | |
983 /* FIXME: This may be only a temporary fix for something... */ | |
984 (vm->state).pgN = 1; | |
985 (vm->state).cellN = 0; | |
986 (vm->state).blockN = 0; | |
987 | |
388 | 988 /* eval -> updates the state and returns either |
225 | 989 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) |
990 - just play video i.e first PG | |
991 (This is what happens if you fall of the end of the pre_cmds) | |
992 - or an error (are there more cases?) */ | |
993 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { | |
388 | 994 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, |
995 (vm->state).pgc->command_tbl->nr_of_pre, | |
225 | 996 &(vm->state).registers, &link_values)) { |
997 /* link_values contains the 'jump' return value */ | |
998 return link_values; | |
999 } else { | |
1000 #ifdef TRACE | |
1001 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n"); | |
1002 #endif | |
1003 } | |
1004 } | |
1005 return play_PG(vm); | |
388 | 1006 } |
225 | 1007 |
388 | 1008 static link_t play_PGC_PG(vm_t *vm, int pgN) { |
225 | 1009 link_t link_values; |
388 | 1010 |
225 | 1011 #ifdef TRACE |
1012 fprintf(MSG_OUT, "libdvdnav: play_PGC_PG:"); | |
1013 if((vm->state).domain != FP_DOMAIN) { | |
1014 fprintf(MSG_OUT, " (vm->state).pgcN (%i)\n", get_PGCN(vm)); | |
1015 } else { | |
1016 fprintf(MSG_OUT, " first_play_pgc\n"); | |
1017 } | |
1018 #endif | |
1019 | |
1020 /* This must be set before the pre-commands are executed because they | |
1021 * might contain a CallSS that will save resume state */ | |
1022 | |
1023 /* FIXME: This may be only a temporary fix for something... */ | |
1024 (vm->state).pgN = pgN; | |
1025 (vm->state).cellN = 0; | |
1026 (vm->state).blockN = 0; | |
1027 | |
388 | 1028 /* eval -> updates the state and returns either |
225 | 1029 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) |
1030 - just play video i.e first PG | |
1031 (This is what happens if you fall of the end of the pre_cmds) | |
1032 - or an error (are there more cases?) */ | |
1033 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_pre) { | |
388 | 1034 if(vmEval_CMD((vm->state).pgc->command_tbl->pre_cmds, |
1035 (vm->state).pgc->command_tbl->nr_of_pre, | |
225 | 1036 &(vm->state).registers, &link_values)) { |
1037 /* link_values contains the 'jump' return value */ | |
1038 return link_values; | |
1039 } else { | |
1040 #ifdef TRACE | |
1041 fprintf(MSG_OUT, "libdvdnav: PGC pre commands didn't do a Jump, Link or Call\n"); | |
1042 #endif | |
1043 } | |
1044 } | |
1045 return play_PG(vm); | |
388 | 1046 } |
225 | 1047 |
1048 static link_t play_PGC_post(vm_t *vm) { | |
1049 link_t link_values; | |
1050 | |
1051 #ifdef TRACE | |
1052 fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n"); | |
1053 #endif | |
388 | 1054 |
1055 /* eval -> updates the state and returns either | |
225 | 1056 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) |
1057 - just go to next PGC | |
1058 (This is what happens if you fall of the end of the post_cmds) | |
1059 - or an error (are there more cases?) */ | |
1060 if((vm->state).pgc->command_tbl && (vm->state).pgc->command_tbl->nr_of_post && | |
1061 vmEval_CMD((vm->state).pgc->command_tbl->post_cmds, | |
388 | 1062 (vm->state).pgc->command_tbl->nr_of_post, |
225 | 1063 &(vm->state).registers, &link_values)) { |
1064 return link_values; | |
1065 } | |
388 | 1066 |
225 | 1067 #ifdef TRACE |
1068 fprintf(MSG_OUT, "libdvdnav: ** Fell of the end of the pgc, continuing in NextPGC\n"); | |
1069 #endif | |
1070 /* Should end up in the STOP_DOMAIN if next_pgc is 0. */ | |
1071 if(!set_PGCN(vm, (vm->state).pgc->next_pgc_nr)) { | |
1072 link_values.command = Exit; | |
1073 return link_values; | |
1074 } | |
1075 return play_PGC(vm); | |
1076 } | |
1077 | |
1078 static link_t play_PG(vm_t *vm) { | |
1079 #ifdef TRACE | |
1080 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i)\n", (vm->state).pgN); | |
1081 #endif | |
388 | 1082 |
225 | 1083 assert((vm->state).pgN > 0); |
1084 if((vm->state).pgN > (vm->state).pgc->nr_of_programs) { | |
1085 #ifdef TRACE | |
388 | 1086 fprintf(MSG_OUT, "libdvdnav: play_PG: (vm->state).pgN (%i) > pgc->nr_of_programs (%i)\n", |
225 | 1087 (vm->state).pgN, (vm->state).pgc->nr_of_programs ); |
1088 #endif | |
388 | 1089 assert((vm->state).pgN == (vm->state).pgc->nr_of_programs + 1); |
225 | 1090 return play_PGC_post(vm); |
1091 } | |
388 | 1092 |
225 | 1093 (vm->state).cellN = (vm->state).pgc->program_map[(vm->state).pgN - 1]; |
388 | 1094 |
225 | 1095 return play_Cell(vm); |
1096 } | |
1097 | |
1098 static link_t play_Cell(vm_t *vm) { | |
1099 static const link_t play_this = {PlayThis, /* Block in Cell */ 0, 0, 0}; | |
1100 | |
1101 #ifdef TRACE | |
1102 fprintf(MSG_OUT, "libdvdnav: play_Cell: (vm->state).cellN (%i)\n", (vm->state).cellN); | |
1103 #endif | |
388 | 1104 |
225 | 1105 assert((vm->state).cellN > 0); |
1106 if((vm->state).cellN > (vm->state).pgc->nr_of_cells) { | |
1107 #ifdef TRACE | |
388 | 1108 fprintf(MSG_OUT, "libdvdnav: (vm->state).cellN (%i) > pgc->nr_of_cells (%i)\n", |
225 | 1109 (vm->state).cellN, (vm->state).pgc->nr_of_cells ); |
1110 #endif | |
388 | 1111 assert((vm->state).cellN == (vm->state).pgc->nr_of_cells + 1); |
225 | 1112 return play_PGC_post(vm); |
1113 } | |
388 | 1114 |
225 | 1115 /* Multi angle/Interleaved */ |
1116 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { | |
1117 case 0: /* Normal */ | |
1118 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); | |
1119 break; | |
1120 case 1: /* The first cell in the block */ | |
1121 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) { | |
1122 case 0: /* Not part of a block */ | |
1123 assert(0); | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
1124 break; |
225 | 1125 case 1: /* Angle block */ |
1126 /* Loop and check each cell instead? So we don't get outside the block? */ | |
1127 (vm->state).cellN += (vm->state).AGL_REG - 1; | |
1128 #ifdef STRICT | |
1129 assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells); | |
1130 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0); | |
1131 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1); | |
1132 #else | |
1133 if (!((vm->state).cellN <= (vm->state).pgc->nr_of_cells) || | |
1134 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode != 0) || | |
1135 !((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 1)) { | |
1136 fprintf(MSG_OUT, "libdvdnav: Invalid angle block\n"); | |
1137 (vm->state).cellN -= (vm->state).AGL_REG - 1; | |
1138 } | |
1139 #endif | |
1140 break; | |
1141 case 2: /* ?? */ | |
1142 case 3: /* ?? */ | |
1143 default: | |
1144 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", | |
1145 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, | |
1146 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); | |
1147 assert(0); | |
1148 } | |
1149 break; | |
1150 case 2: /* Cell in the block */ | |
1151 case 3: /* Last cell in the block */ | |
1152 /* These might perhaps happen for RSM or LinkC commands? */ | |
1153 default: | |
1154 fprintf(MSG_OUT, "libdvdnav: Cell is in block but did not enter at first cell!\n"); | |
1155 } | |
388 | 1156 |
225 | 1157 /* Updates (vm->state).pgN and PTTN_REG */ |
1158 if(!set_PGN(vm)) { | |
1159 /* Should not happen */ | |
1160 assert(0); | |
1161 return play_PGC_post(vm); | |
1162 } | |
1163 (vm->state).cell_restart++; | |
1164 (vm->state).blockN = 0; | |
1165 #ifdef TRACE | |
1166 fprintf(MSG_OUT, "libdvdnav: Cell should restart here\n"); | |
1167 #endif | |
1168 return play_this; | |
1169 } | |
1170 | |
1171 static link_t play_Cell_post(vm_t *vm) { | |
1172 cell_playback_t *cell; | |
388 | 1173 |
225 | 1174 #ifdef TRACE |
1175 fprintf(MSG_OUT, "libdvdnav: play_Cell_post: (vm->state).cellN (%i)\n", (vm->state).cellN); | |
1176 #endif | |
388 | 1177 |
225 | 1178 cell = &(vm->state).pgc->cell_playback[(vm->state).cellN - 1]; |
388 | 1179 |
225 | 1180 /* Still time is already taken care of before we get called. */ |
388 | 1181 |
225 | 1182 /* Deal with a Cell command, if any */ |
1183 if(cell->cell_cmd_nr != 0) { | |
1184 link_t link_values; | |
388 | 1185 |
225 | 1186 /* These asserts are now not needed. |
1187 * Some DVDs have no cell commands listed in the PGC, | |
1188 * but the Cell itself points to a cell command that does not exist. | |
1189 * For this situation, just ignore the cell command and continue. | |
1190 * | |
1191 * assert((vm->state).pgc->command_tbl != NULL); | |
1192 * assert((vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr); | |
1193 */ | |
1194 | |
1195 if ((vm->state).pgc->command_tbl != NULL && | |
1196 (vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr) { | |
1197 #ifdef TRACE | |
1198 fprintf(MSG_OUT, "libdvdnav: Cell command present, executing\n"); | |
1199 #endif | |
1200 if(vmEval_CMD(&(vm->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1, | |
1201 &(vm->state).registers, &link_values)) { | |
1202 return link_values; | |
1203 } else { | |
1204 #ifdef TRACE | |
1205 fprintf(MSG_OUT, "libdvdnav: Cell command didn't do a Jump, Link or Call\n"); | |
1206 #endif | |
1207 } | |
1208 } else { | |
1209 #ifdef TRACE | |
1210 fprintf(MSG_OUT, "libdvdnav: Invalid Cell command\n"); | |
1211 #endif | |
1212 } | |
1213 } | |
388 | 1214 |
225 | 1215 /* Where to continue after playing the cell... */ |
1216 /* Multi angle/Interleaved */ | |
1217 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode) { | |
1218 case 0: /* Normal */ | |
1219 assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type == 0); | |
1220 (vm->state).cellN++; | |
1221 break; | |
1222 case 1: /* The first cell in the block */ | |
1223 case 2: /* A cell in the block */ | |
1224 case 3: /* The last cell in the block */ | |
1225 default: | |
1226 switch((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type) { | |
1227 case 0: /* Not part of a block */ | |
1228 assert(0); | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
1229 break; |
225 | 1230 case 1: /* Angle block */ |
1231 /* Skip the 'other' angles */ | |
1232 (vm->state).cellN++; | |
1233 while((vm->state).cellN <= (vm->state).pgc->nr_of_cells && | |
1234 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode >= 2) { | |
1235 (vm->state).cellN++; | |
1236 } | |
1237 break; | |
1238 case 2: /* ?? */ | |
1239 case 3: /* ?? */ | |
1240 default: | |
1241 fprintf(MSG_OUT, "libdvdnav: Invalid? Cell block_mode (%d), block_type (%d)\n", | |
1242 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode, | |
1243 (vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type); | |
1244 assert(0); | |
1245 } | |
1246 break; | |
1247 } | |
388 | 1248 |
1249 /* Figure out the correct pgN for the new cell */ | |
225 | 1250 if(!set_PGN(vm)) { |
1251 #ifdef TRACE | |
1252 fprintf(MSG_OUT, "libdvdnav: last cell in this PGC\n"); | |
1253 #endif | |
1254 return play_PGC_post(vm); | |
1255 } | |
1256 return play_Cell(vm); | |
1257 } | |
1258 | |
1259 | |
1260 /* link processing */ | |
1261 | |
1262 static int process_command(vm_t *vm, link_t link_values) { | |
388 | 1263 |
225 | 1264 while(link_values.command != PlayThis) { |
388 | 1265 |
225 | 1266 #ifdef TRACE |
1267 fprintf(MSG_OUT, "libdvdnav: Before printout starts:\n"); | |
1268 vm_print_link(link_values); | |
388 | 1269 fprintf(MSG_OUT, "libdvdnav: Link values %i %i %i %i\n", link_values.command, |
225 | 1270 link_values.data1, link_values.data2, link_values.data3); |
1271 vm_print_current_domain_state(vm); | |
1272 fprintf(MSG_OUT, "libdvdnav: Before printout ends.\n"); | |
1273 #endif | |
388 | 1274 |
225 | 1275 switch(link_values.command) { |
1276 case LinkNoLink: | |
1277 /* BUTTON number:data1 */ | |
1278 if(link_values.data1 != 0) | |
1279 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1280 return 0; /* no actual jump */ | |
1281 | |
1282 case LinkTopC: | |
1283 /* Restart playing from the beginning of the current Cell. */ | |
1284 /* BUTTON number:data1 */ | |
1285 if(link_values.data1 != 0) | |
1286 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1287 link_values = play_Cell(vm); | |
1288 break; | |
1289 case LinkNextC: | |
1290 /* Link to Next Cell */ | |
1291 /* BUTTON number:data1 */ | |
1292 if(link_values.data1 != 0) | |
1293 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1294 (vm->state).cellN += 1; | |
1295 link_values = play_Cell(vm); | |
1296 break; | |
1297 case LinkPrevC: | |
1298 /* Link to Previous Cell */ | |
1299 /* BUTTON number:data1 */ | |
1300 if(link_values.data1 != 0) | |
1301 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1302 assert((vm->state).cellN > 1); | |
1303 (vm->state).cellN -= 1; | |
1304 link_values = play_Cell(vm); | |
1305 break; | |
388 | 1306 |
225 | 1307 case LinkTopPG: |
1308 /* Link to Top of current Program */ | |
1309 /* BUTTON number:data1 */ | |
1310 if(link_values.data1 != 0) | |
1311 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1312 link_values = play_PG(vm); | |
1313 break; | |
1314 case LinkNextPG: | |
1315 /* Link to Next Program */ | |
1316 /* BUTTON number:data1 */ | |
1317 if(link_values.data1 != 0) | |
1318 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1319 (vm->state).pgN += 1; | |
1320 link_values = play_PG(vm); | |
1321 break; | |
1322 case LinkPrevPG: | |
1323 /* Link to Previous Program */ | |
1324 /* BUTTON number:data1 */ | |
1325 if(link_values.data1 != 0) | |
1326 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1327 assert((vm->state).pgN > 1); | |
1328 (vm->state).pgN -= 1; | |
1329 link_values = play_PG(vm); | |
1330 break; | |
1331 | |
1332 case LinkTopPGC: | |
1333 /* Restart playing from beginning of current Program Chain */ | |
1334 /* BUTTON number:data1 */ | |
1335 if(link_values.data1 != 0) | |
1336 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1337 link_values = play_PGC(vm); | |
1338 break; | |
1339 case LinkNextPGC: | |
1340 /* Link to Next 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->next_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->next_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 LinkPrevPGC: | |
1351 /* Link to Previous Program Chain */ | |
1352 /* BUTTON number:data1 */ | |
1353 if(link_values.data1 != 0) | |
1354 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1355 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
|
1356 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
|
1357 link_values = play_PGC(vm); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1358 else |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1359 link_values.command = Exit; |
225 | 1360 break; |
1361 case LinkGoUpPGC: | |
1362 /* Link to GoUp Program Chain */ | |
1363 /* BUTTON number:data1 */ | |
1364 if(link_values.data1 != 0) | |
1365 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1366 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
|
1367 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
|
1368 link_values = play_PGC(vm); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1369 else |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1370 link_values.command = Exit; |
225 | 1371 break; |
1372 case LinkTailPGC: | |
1373 /* Link to Tail of Program Chain */ | |
1374 /* BUTTON number:data1 */ | |
1375 if(link_values.data1 != 0) | |
1376 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
1377 link_values = play_PGC_post(vm); | |
1378 break; | |
1379 | |
1380 case LinkRSM: | |
1381 { | |
1382 /* Link to Resume point */ | |
1383 int i; | |
388 | 1384 |
225 | 1385 /* Check and see if there is any rsm info!! */ |
1386 if (!(vm->state).rsm_vtsN) { | |
1387 fprintf(MSG_OUT, "libdvdnav: trying to resume without any resume info set\n"); | |
1388 link_values.command = Exit; | |
1389 break; | |
1390 } | |
388 | 1391 |
225 | 1392 (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
|
1393 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
|
1394 assert(0); |
225 | 1395 set_PGCN(vm, (vm->state).rsm_pgcN); |
388 | 1396 |
1397 /* These should never be set in SystemSpace and/or MenuSpace */ | |
225 | 1398 /* (vm->state).TTN_REG = rsm_tt; ?? */ |
1399 /* (vm->state).TT_PGCN_REG = (vm->state).rsm_pgcN; ?? */ | |
1400 for(i = 0; i < 5; i++) { | |
1401 (vm->state).registers.SPRM[4 + i] = (vm->state).rsm_regs[i]; | |
1402 } | |
388 | 1403 |
225 | 1404 if(link_values.data1 != 0) |
1405 (vm->state).HL_BTNN_REG = link_values.data1 << 10; | |
388 | 1406 |
225 | 1407 if((vm->state).rsm_cellN == 0) { |
1408 assert((vm->state).cellN); /* Checking if this ever happens */ | |
1409 (vm->state).pgN = 1; | |
1410 link_values = play_PG(vm); | |
388 | 1411 } else { |
252
aee8af592d66
fix a long-standing problem: sometimes, hitting Escape in the movie and then
mroi
parents:
247
diff
changeset
|
1412 /* (vm->state).pgN = ?? this gets the right value in set_PGN() below */ |
225 | 1413 (vm->state).cellN = (vm->state).rsm_cellN; |
1414 link_values.command = PlayThis; | |
252
aee8af592d66
fix a long-standing problem: sometimes, hitting Escape in the movie and then
mroi
parents:
247
diff
changeset
|
1415 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
|
1416 link_values.data2 = (vm->state).rsm_blockN >> 16; |
225 | 1417 if(!set_PGN(vm)) { |
1418 /* Were at the end of the PGC, should not happen for a RSM */ | |
1419 assert(0); | |
1420 link_values.command = LinkTailPGC; | |
1421 link_values.data1 = 0; /* No button */ | |
1422 } | |
1423 } | |
1424 } | |
1425 break; | |
1426 case LinkPGCN: | |
1427 /* Link to Program Chain Number:data1 */ | |
1428 if(!set_PGCN(vm, link_values.data1)) | |
1429 assert(0); | |
1430 link_values = play_PGC(vm); | |
1431 break; | |
1432 case LinkPTTN: | |
1433 /* Link to Part of current Title Number:data1 */ | |
1434 /* BUTTON number:data2 */ | |
1435 /* PGC Pre-Commands are not executed */ | |
1436 assert((vm->state).domain == VTS_DOMAIN); | |
1437 if(link_values.data2 != 0) | |
1438 (vm->state).HL_BTNN_REG = link_values.data2 << 10; | |
1439 if(!set_VTS_PTT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG, link_values.data1)) | |
1440 assert(0); | |
1441 link_values = play_PG(vm); | |
1442 break; | |
1443 case LinkPGN: | |
1444 /* Link to Program Number:data1 */ | |
1445 /* BUTTON number:data2 */ | |
1446 if(link_values.data2 != 0) | |
1447 (vm->state).HL_BTNN_REG = link_values.data2 << 10; | |
1448 /* Update any other state, PTTN perhaps? */ | |
1449 (vm->state).pgN = link_values.data1; | |
1450 link_values = play_PG(vm); | |
1451 break; | |
1452 case LinkCN: | |
1453 /* Link to Cell Number:data1 */ | |
1454 /* BUTTON number:data2 */ | |
1455 if(link_values.data2 != 0) | |
1456 (vm->state).HL_BTNN_REG = link_values.data2 << 10; | |
1457 /* Update any other state, pgN, PTTN perhaps? */ | |
1458 (vm->state).cellN = link_values.data1; | |
1459 link_values = play_Cell(vm); | |
1460 break; | |
388 | 1461 |
225 | 1462 case Exit: |
1463 vm->stopped = 1; | |
1464 return 0; | |
388 | 1465 |
225 | 1466 case JumpTT: |
1467 /* Jump to VTS Title Domain */ | |
1468 /* Only allowed from the First Play domain(PGC) */ | |
1469 /* or the Video Manager domain (VMG) */ | |
1470 /* Stop SPRM9 Timer */ | |
1471 /* Set SPRM1 and SPRM2 */ | |
1472 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
|
1473 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
|
1474 link_values = play_PGC(vm); |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1475 else |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1476 link_values.command = Exit; |
225 | 1477 break; |
1478 case JumpVTS_TT: | |
1479 /* Jump to Title:data1 in same VTS Title Domain */ | |
1480 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1481 /* or the Video Title Set Domain(VTS) */ | |
1482 /* Stop SPRM9 Timer */ | |
1483 /* Set SPRM1 and SPRM2 */ | |
1484 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1485 if(!set_VTS_TT(vm, (vm->state).vtsN, link_values.data1)) | |
1486 assert(0); | |
1487 link_values = play_PGC(vm); | |
1488 break; | |
1489 case JumpVTS_PTT: | |
1490 /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */ | |
1491 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1492 /* or the Video Title Set Domain(VTS) */ | |
1493 /* Stop SPRM9 Timer */ | |
1494 /* Set SPRM1 and SPRM2 */ | |
1495 assert((vm->state).domain == VTSM_DOMAIN || (vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1496 if(!set_VTS_PTT(vm, (vm->state).vtsN, link_values.data1, link_values.data2)) | |
1497 assert(0); | |
1498 link_values = play_PGC_PG(vm, (vm->state).pgN); | |
1499 break; | |
388 | 1500 |
225 | 1501 case JumpSS_FP: |
1502 /* Jump to First Play Domain */ | |
1503 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1504 /* or the Video Manager domain (VMG) */ | |
1505 /* Stop SPRM9 Timer and any GPRM counters */ | |
1506 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); /* ?? */ | |
1507 if (!set_FP_PGC(vm)) | |
1508 assert(0); | |
1509 link_values = play_PGC(vm); | |
1510 break; | |
1511 case JumpSS_VMGM_MENU: | |
410 | 1512 /* Jump to Video Manager domain - Title Menu:data1 or any PGC in VMG */ |
225 | 1513 /* Allowed from anywhere except the VTS Title domain */ |
1514 /* Stop SPRM9 Timer and any GPRM counters */ | |
1515 assert((vm->state).domain != VTS_DOMAIN); /* ?? */ | |
1516 (vm->state).domain = VMGM_DOMAIN; | |
1517 if(!set_MENU(vm, link_values.data1)) | |
1518 assert(0); | |
1519 link_values = play_PGC(vm); | |
1520 break; | |
1521 case JumpSS_VTSM: | |
1522 /* Jump to a menu in Video Title domain, */ | |
1523 /* or to a Menu is the current VTS */ | |
1524 /* Stop SPRM9 Timer and any GPRM counters */ | |
1525 /* ifoOpenNewVTSI:data1 */ | |
1526 /* VTS_TTN_REG:data2 */ | |
388 | 1527 /* get_MENU:data3 */ |
225 | 1528 if(link_values.data1 != 0) { |
1529 if (link_values.data1 != (vm->state).vtsN) { | |
1530 /* the normal case */ | |
1531 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ | |
1532 (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
|
1533 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
|
1534 assert(0); |
225 | 1535 } else { |
1536 /* This happens on some discs like "Captain Scarlet & the Mysterons" or | |
1537 * the German RC2 of "Anatomie" in VTSM. */ | |
1538 assert((vm->state).domain == VTSM_DOMAIN || | |
1539 (vm->state).domain == VMGM_DOMAIN || (vm->state).domain == FP_DOMAIN); /* ?? */ | |
1540 (vm->state).domain = VTSM_DOMAIN; | |
1541 } | |
1542 } else { | |
1543 /* This happens on 'The Fifth Element' region 2. */ | |
1544 assert((vm->state).domain == VTSM_DOMAIN); | |
1545 } | |
1546 /* I don't know what title is supposed to be used for. */ | |
1547 /* Alien or Aliens has this != 1, I think. */ | |
1548 /* assert(link_values.data2 == 1); */ | |
1549 (vm->state).VTS_TTN_REG = link_values.data2; | |
1550 /* TTN_REG (SPRM4), VTS_TTN_REG (SPRM5), TT_PGCN_REG (SPRM6) are linked, */ | |
1551 /* so if one changes, the others must change to match it. */ | |
1552 (vm->state).TTN_REG = get_TT(vm, (vm->state).vtsN, (vm->state).VTS_TTN_REG); | |
1553 if(!set_MENU(vm, link_values.data3)) | |
1554 assert(0); | |
1555 link_values = play_PGC(vm); | |
1556 break; | |
1557 case JumpSS_VMGM_PGC: | |
1558 /* set_PGCN:data1 */ | |
1559 /* Stop SPRM9 Timer and any GPRM counters */ | |
1560 assert((vm->state).domain != VTS_DOMAIN); /* ?? */ | |
1561 (vm->state).domain = VMGM_DOMAIN; | |
1562 if(!set_PGCN(vm, link_values.data1)) | |
1563 assert(0); | |
1564 link_values = play_PGC(vm); | |
1565 break; | |
388 | 1566 |
225 | 1567 case CallSS_FP: |
1568 /* set_RSMinfo:data1 */ | |
1569 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1570 /* Must be called before domain is changed */ | |
1571 set_RSMinfo(vm, link_values.data1, /* We dont have block info */ 0); | |
1572 set_FP_PGC(vm); | |
1573 link_values = play_PGC(vm); | |
1574 break; | |
1575 case CallSS_VMGM_MENU: | |
388 | 1576 /* set_MENU:data1 */ |
225 | 1577 /* set_RSMinfo:data2 */ |
1578 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1579 /* Must be called before domain is changed */ | |
388 | 1580 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); |
225 | 1581 (vm->state).domain = VMGM_DOMAIN; |
1582 if(!set_MENU(vm, link_values.data1)) | |
1583 assert(0); | |
1584 link_values = play_PGC(vm); | |
1585 break; | |
1586 case CallSS_VTSM: | |
388 | 1587 /* set_MENU:data1 */ |
225 | 1588 /* set_RSMinfo:data2 */ |
1589 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1590 /* Must be called before domain is changed */ | |
1591 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); | |
1592 (vm->state).domain = VTSM_DOMAIN; | |
1593 if(!set_MENU(vm, link_values.data1)) | |
1594 assert(0); | |
1595 link_values = play_PGC(vm); | |
1596 break; | |
1597 case CallSS_VMGM_PGC: | |
1598 /* set_PGC:data1 */ | |
1599 /* set_RSMinfo:data2 */ | |
1600 assert((vm->state).domain == VTS_DOMAIN); /* ?? */ | |
1601 /* Must be called before domain is changed */ | |
1602 set_RSMinfo(vm, link_values.data2, /* We dont have block info */ 0); | |
1603 (vm->state).domain = VMGM_DOMAIN; | |
1604 if(!set_PGCN(vm, link_values.data1)) | |
1605 assert(0); | |
1606 link_values = play_PGC(vm); | |
1607 break; | |
1608 case PlayThis: | |
1609 /* Should never happen. */ | |
1610 assert(0); | |
1611 break; | |
1612 } | |
1613 | |
1614 #ifdef TRACE | |
1615 fprintf(MSG_OUT, "libdvdnav: After printout starts:\n"); | |
1616 vm_print_current_domain_state(vm); | |
1617 fprintf(MSG_OUT, "libdvdnav: After printout ends.\n"); | |
1618 #endif | |
388 | 1619 |
225 | 1620 } |
252
aee8af592d66
fix a long-standing problem: sometimes, hitting Escape in the movie and then
mroi
parents:
247
diff
changeset
|
1621 (vm->state).blockN = link_values.data1 | (link_values.data2 << 16); |
225 | 1622 return 1; |
1623 } | |
1624 | |
1625 | |
1626 /* Set functions */ | |
1627 | |
388 | 1628 static int set_TT(vm_t *vm, int tt) { |
225 | 1629 return set_PTT(vm, tt, 1); |
1630 } | |
1631 | |
1632 static int set_PTT(vm_t *vm, int tt, int ptt) { | |
1633 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts); | |
1634 return set_VTS_PTT(vm, vm->vmgi->tt_srpt->title[tt - 1].title_set_nr, | |
1635 vm->vmgi->tt_srpt->title[tt - 1].vts_ttn, ptt); | |
1636 } | |
1637 | |
1638 static int set_VTS_TT(vm_t *vm, int vtsN, int vts_ttn) { | |
1639 return set_VTS_PTT(vm, vtsN, vts_ttn, 1); | |
1640 } | |
1641 | |
1642 static int set_VTS_PTT(vm_t *vm, int vtsN, int vts_ttn, int part) { | |
1643 int pgcN, pgN, res; | |
388 | 1644 |
225 | 1645 (vm->state).domain = VTS_DOMAIN; |
1646 | |
256
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1647 if (vtsN != (vm->state).vtsN) |
6299ccea8a38
killing a lot of asserts and turning them into forced executions of Exit,
mroi
parents:
254
diff
changeset
|
1648 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
|
1649 return 0; |
388 | 1650 |
225 | 1651 if ((vts_ttn < 1) || (vts_ttn > vm->vtsi->vts_ptt_srpt->nr_of_srpts) || |
1652 (part < 1) || (part > vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts) ) { | |
1653 return 0; | |
1654 } | |
388 | 1655 |
225 | 1656 pgcN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn; |
1657 pgN = vm->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn; | |
388 | 1658 |
225 | 1659 (vm->state).TT_PGCN_REG = pgcN; |
1660 (vm->state).PTTN_REG = part; | |
1661 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn); | |
1662 assert( (vm->state.TTN_REG) != 0 ); | |
1663 (vm->state).VTS_TTN_REG = vts_ttn; | |
1664 (vm->state).vtsN = vtsN; /* Not sure about this one. We can get to it easily from TTN_REG */ | |
1665 /* Any other registers? */ | |
388 | 1666 |
225 | 1667 res = set_PGCN(vm, pgcN); /* This clobber's state.pgN (sets it to 1), but we don't want clobbering here. */ |
1668 (vm->state).pgN = pgN; | |
1669 return res; | |
1670 } | |
1671 | |
409
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1672 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
|
1673 assert(tt <= vm->vmgi->tt_srpt->nr_of_srpts); |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1674 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
|
1675 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
|
1676 } |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1677 |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1678 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
|
1679 int pgcN, pgN, res, title, part = 0; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1680 |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1681 (vm->state).domain = VTS_DOMAIN; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1682 |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1683 if (vtsN != (vm->state).vtsN) |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1684 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
|
1685 return 0; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1686 |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1687 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
|
1688 return 0; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1689 } |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1690 |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1691 pgcN = pgcn; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1692 pgN = pgn; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1693 |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1694 (vm->state).TT_PGCN_REG = pgcN; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1695 (vm->state).TTN_REG = get_TT(vm, vtsN, vts_ttn); |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1696 assert( (vm->state.TTN_REG) != 0 ); |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1697 (vm->state).VTS_TTN_REG = vts_ttn; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1698 (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
|
1699 /* Any other registers? */ |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1700 |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1701 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
|
1702 (vm->state).pgN = pgN; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1703 vm_get_current_title_part(vm, &title, &part); |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1704 (vm->state).PTTN_REG = part; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1705 return res; |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1706 } |
9b8bfc56a7fe
Add dvdnav_program_play & dvdnav_current_title_program
erik
parents:
408
diff
changeset
|
1707 |
388 | 1708 static int set_FP_PGC(vm_t *vm) { |
225 | 1709 (vm->state).domain = FP_DOMAIN; |
254
f78669338b49
Fix segfault if the DVD does not contain a FP_PGC.
jcdutton
parents:
252
diff
changeset
|
1710 if (!vm->vmgi->first_play_pgc) { |
f78669338b49
Fix segfault if the DVD does not contain a FP_PGC.
jcdutton
parents:
252
diff
changeset
|
1711 return set_PGCN(vm, 1); |
f78669338b49
Fix segfault if the DVD does not contain a FP_PGC.
jcdutton
parents:
252
diff
changeset
|
1712 } |
225 | 1713 (vm->state).pgc = vm->vmgi->first_play_pgc; |
1714 (vm->state).pgcN = vm->vmgi->vmgi_mat->first_play_pgc; | |
1715 return 1; | |
1716 } | |
1717 | |
1718 | |
1719 static int set_MENU(vm_t *vm, int menu) { | |
1720 assert((vm->state).domain == VMGM_DOMAIN || (vm->state).domain == VTSM_DOMAIN); | |
1721 return set_PGCN(vm, get_ID(vm, menu)); | |
1722 } | |
1723 | |
1724 static int set_PGCN(vm_t *vm, int pgcN) { | |
1725 pgcit_t *pgcit; | |
388 | 1726 |
225 | 1727 pgcit = get_PGCIT(vm); |
1728 assert(pgcit != NULL); /* ?? Make this return -1 instead */ | |
1729 | |
1730 if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) { | |
1731 #ifdef TRACE | |
1732 fprintf(MSG_OUT, "libdvdnav: ** No such pgcN = %d\n", pgcN); | |
1733 #endif | |
1734 return 0; | |
1735 } | |
388 | 1736 |
225 | 1737 (vm->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc; |
1738 (vm->state).pgcN = pgcN; | |
1739 (vm->state).pgN = 1; | |
388 | 1740 |
225 | 1741 if((vm->state).domain == VTS_DOMAIN) |
1742 (vm->state).TT_PGCN_REG = pgcN; | |
1743 | |
1744 return 1; | |
1745 } | |
1746 | |
388 | 1747 /* Figure out the correct pgN from the cell and update (vm->state). */ |
225 | 1748 static int set_PGN(vm_t *vm) { |
1749 int new_pgN = 0; | |
408 | 1750 int dummy, part = 0; |
388 | 1751 |
1752 while(new_pgN < (vm->state).pgc->nr_of_programs | |
225 | 1753 && (vm->state).cellN >= (vm->state).pgc->program_map[new_pgN]) |
1754 new_pgN++; | |
388 | 1755 |
225 | 1756 if(new_pgN == (vm->state).pgc->nr_of_programs) /* We are at the last program */ |
1757 if((vm->state).cellN > (vm->state).pgc->nr_of_cells) | |
1758 return 0; /* We are past the last cell */ | |
388 | 1759 |
225 | 1760 (vm->state).pgN = new_pgN; |
388 | 1761 |
225 | 1762 if((vm->state).domain == VTS_DOMAIN) { |
1763 playback_type_t *pb_ty; | |
1764 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts) | |
1765 return 0; /* ?? */ | |
1766 pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty; | |
1767 vm_get_current_title_part(vm, &dummy, &part); | |
1768 (vm->state).PTTN_REG = part; | |
1769 } | |
1770 return 1; | |
1771 } | |
1772 | |
1773 /* Must be called before domain is changed (set_PGCN()) */ | |
1774 static void set_RSMinfo(vm_t *vm, int cellN, int blockN) { | |
1775 int i; | |
388 | 1776 |
225 | 1777 if(cellN) { |
1778 (vm->state).rsm_cellN = cellN; | |
1779 (vm->state).rsm_blockN = blockN; | |
1780 } else { | |
1781 (vm->state).rsm_cellN = (vm->state).cellN; | |
1782 (vm->state).rsm_blockN = blockN; | |
1783 } | |
1784 (vm->state).rsm_vtsN = (vm->state).vtsN; | |
1785 (vm->state).rsm_pgcN = get_PGCN(vm); | |
388 | 1786 |
225 | 1787 /* assert((vm->state).rsm_pgcN == (vm->state).TT_PGCN_REG); for VTS_DOMAIN */ |
388 | 1788 |
225 | 1789 for(i = 0; i < 5; i++) { |
1790 (vm->state).rsm_regs[i] = (vm->state).registers.SPRM[4 + i]; | |
1791 } | |
1792 } | |
1793 | |
1794 | |
1795 /* Get functions */ | |
1796 | |
1797 /* Searches the TT tables, to find the current TT. | |
1798 * returns the current TT. | |
1799 * returns 0 if not found. | |
1800 */ | |
1801 static int get_TT(vm_t *vm, int vtsN, int vts_ttn) { | |
1802 int i; | |
1803 int tt=0; | |
1804 | |
1805 for(i = 1; i <= vm->vmgi->tt_srpt->nr_of_srpts; i++) { | |
388 | 1806 if( vm->vmgi->tt_srpt->title[i - 1].title_set_nr == vtsN && |
225 | 1807 vm->vmgi->tt_srpt->title[i - 1].vts_ttn == vts_ttn) { |
1808 tt=i; | |
1809 break; | |
1810 } | |
1811 } | |
1812 return tt; | |
1813 } | |
1814 | |
1815 /* Search for entry_id match of the PGC Category in the current VTS PGCIT table. | |
1816 * Return pgcN based on entry_id match. | |
1817 */ | |
1818 static int get_ID(vm_t *vm, int id) { | |
1819 int pgcN, i; | |
1820 pgcit_t *pgcit; | |
388 | 1821 |
225 | 1822 /* Relies on state to get the correct pgcit. */ |
1823 pgcit = get_PGCIT(vm); | |
1824 assert(pgcit != NULL); | |
1825 #ifdef TRACE | |
1826 fprintf(MSG_OUT, "libdvdnav: ** Searching for menu (0x%x) entry PGC\n", id); | |
1827 #endif | |
1828 | |
1829 /* Force high bit set. */ | |
1830 id |=0x80; | |
1831 | |
1832 /* Get menu/title */ | |
1833 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { | |
1834 if( (pgcit->pgci_srp[i].entry_id) == id) { | |
1835 pgcN = i + 1; | |
1836 #ifdef TRACE | |
1837 fprintf(MSG_OUT, "libdvdnav: Found menu.\n"); | |
1838 #endif | |
1839 return pgcN; | |
1840 } | |
1841 } | |
1842 #ifdef TRACE | |
1843 fprintf(MSG_OUT, "libdvdnav: ** No such id/menu (0x%02x) entry PGC\n", id & 0x7f); | |
1844 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { | |
1845 if ( (pgcit->pgci_srp[i].entry_id & 0x80) == 0x80) { | |
1846 fprintf(MSG_OUT, "libdvdnav: Available menus: 0x%x\n", | |
1847 pgcit->pgci_srp[i].entry_id & 0x7f); | |
1848 } | |
1849 } | |
1850 #endif | |
1851 return 0; /* error */ | |
1852 } | |
1853 | |
1854 /* FIXME: we have a pgcN member in the vm's state now, so this should be obsolete */ | |
1855 static int get_PGCN(vm_t *vm) { | |
1856 pgcit_t *pgcit; | |
1857 int pgcN = 1; | |
1858 | |
1859 pgcit = get_PGCIT(vm); | |
388 | 1860 |
225 | 1861 if (pgcit) { |
1862 while(pgcN <= pgcit->nr_of_pgci_srp) { | |
1863 if(pgcit->pgci_srp[pgcN - 1].pgc == (vm->state).pgc) { | |
1864 assert((vm->state).pgcN == pgcN); | |
1865 return pgcN; | |
1866 } | |
1867 pgcN++; | |
1868 } | |
1869 } | |
388 | 1870 fprintf(MSG_OUT, "libdvdnav: get_PGCN failed. Was trying to find pgcN in domain %d\n", |
225 | 1871 (vm->state).domain); |
1872 return 0; /* error */ | |
1873 } | |
1874 | |
1875 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang) { | |
1876 int i; | |
388 | 1877 |
225 | 1878 if(h == NULL || h->pgci_ut == NULL) { |
1879 fprintf(MSG_OUT, "libdvdnav: *** pgci_ut handle is NULL ***\n"); | |
1880 return NULL; /* error? */ | |
1881 } | |
388 | 1882 |
225 | 1883 i = 0; |
1884 while(i < h->pgci_ut->nr_of_lus | |
1885 && h->pgci_ut->lu[i].lang_code != lang) | |
1886 i++; | |
1887 if(i == h->pgci_ut->nr_of_lus) { | |
1888 fprintf(MSG_OUT, "libdvdnav: Language '%c%c' not found, using '%c%c' instead\n", | |
1889 (char)(lang >> 8), (char)(lang & 0xff), | |
1890 (char)(h->pgci_ut->lu[0].lang_code >> 8), | |
1891 (char)(h->pgci_ut->lu[0].lang_code & 0xff)); | |
1892 fprintf(MSG_OUT, "libdvdnav: Menu Languages available: "); | |
1893 for(i = 0; i < h->pgci_ut->nr_of_lus; i++) { | |
1894 fprintf(MSG_OUT, "%c%c ", | |
1895 (char)(h->pgci_ut->lu[i].lang_code >> 8), | |
1896 (char)(h->pgci_ut->lu[i].lang_code & 0xff)); | |
1897 } | |
1898 fprintf(MSG_OUT, "\n"); | |
1899 i = 0; /* error? */ | |
1900 } | |
388 | 1901 |
225 | 1902 return h->pgci_ut->lu[i].pgcit; |
1903 } | |
1904 | |
1905 /* Uses state to decide what to return */ | |
1906 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
|
1907 pgcit_t *pgcit = NULL; |
388 | 1908 |
225 | 1909 switch ((vm->state).domain) { |
1910 case VTS_DOMAIN: | |
344
fb2fbd4cfbf6
in get_PGCIT() check the validity of vm->vtsi before risking to dereference NULL;
nicodvb
parents:
332
diff
changeset
|
1911 if(!vm->vtsi) return NULL; |
225 | 1912 pgcit = vm->vtsi->vts_pgcit; |
1913 break; | |
1914 case VTSM_DOMAIN: | |
344
fb2fbd4cfbf6
in get_PGCIT() check the validity of vm->vtsi before risking to dereference NULL;
nicodvb
parents:
332
diff
changeset
|
1915 if(!vm->vtsi) return NULL; |
225 | 1916 pgcit = get_MENU_PGCIT(vm, vm->vtsi, (vm->state).registers.SPRM[0]); |
1917 break; | |
1918 case VMGM_DOMAIN: | |
1919 case FP_DOMAIN: | |
1920 pgcit = get_MENU_PGCIT(vm, vm->vmgi, (vm->state).registers.SPRM[0]); | |
1921 break; | |
1922 default: | |
243
e75c52894630
* assert(0) does not always and the program (see NDEBUG)
mroi
parents:
229
diff
changeset
|
1923 abort(); |
225 | 1924 } |
388 | 1925 |
225 | 1926 return pgcit; |
1927 } | |
1928 | |
388 | 1929 //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
|
1930 //identify chapters |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1931 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
|
1932 { |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1933 ifo_handle_t *ifo = NULL; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1934 uint8_t titleset_nr; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1935 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
|
1936 return NULL; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1937 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
|
1938 ifo = ifoOpen(vm->dvd, titleset_nr); |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1939 return ifo; |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1940 } |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1941 |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1942 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
|
1943 { |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1944 ifoClose(ifo); |
fdbfb58d2735
added utility functions vm_get_title_ifo() and vm_ifo_close()
nicodvb
parents:
294
diff
changeset
|
1945 } |
225 | 1946 |
1947 /* Debug functions */ | |
1948 | |
1949 #ifdef TRACE | |
1950 void vm_position_print(vm_t *vm, vm_position_t *position) { | |
1951 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", | |
1952 position->button, | |
1953 position->spu_channel, | |
1954 position->audio_channel, | |
1955 position->angle_channel, | |
1956 position->hop_channel, | |
1957 position->vts, | |
1958 position->domain, | |
1959 position->cell, | |
1960 position->cell_restart, | |
1961 position->cell_start, | |
1962 position->still, | |
1963 position->block); | |
1964 } | |
1965 #endif | |
1966 |