Mercurial > libdvdnav.hg
annotate vm.c @ 4:99bed5d6db2f src
Added reset patch from Kees Cook <kees@outflux.net>
author | richwareham |
---|---|
date | Tue, 02 Apr 2002 18:22:27 +0000 |
parents | 328eadb3f37e |
children | 5f319e02e333 |
rev | line source |
---|---|
0 | 1 /* |
2 * Copyright (C) 2000, 2001 Håkan Hjort | |
3 * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net> | |
4 * | |
5 * This file is part of libdvdnav, a DVD navigation library. It is modified | |
6 * from a file originally part of the Ogle DVD player. | |
7 * | |
8 * libdvdnav is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * libdvdnav is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | |
21 * | |
22 * $Id$ | |
23 * | |
24 */ | |
25 | |
26 #ifdef HAVE_CONFIG_H | |
27 #include "config.h" | |
28 #endif | |
29 | |
30 #include <stdio.h> | |
31 #include <string.h> | |
32 #include <stdlib.h> | |
33 #include <unistd.h> | |
34 #include <inttypes.h> | |
35 #include <assert.h> | |
36 | |
37 #include <dvdread/ifo_types.h> | |
38 #include <dvdread/ifo_read.h> | |
39 | |
40 #include "decoder.h" | |
41 #include "vmcmd.h" | |
42 #include "vm.h" | |
43 | |
44 /* Local prototypes */ | |
45 | |
46 static void saveRSMinfo(vm_t *self,int cellN, int blockN); | |
47 static int set_PGN(vm_t *self); | |
48 static link_t play_PGC(vm_t *self); | |
49 static link_t play_PG(vm_t *self); | |
50 static link_t play_Cell(vm_t *self); | |
51 static link_t play_Cell_post(vm_t *self); | |
52 static link_t play_PGC_post(vm_t *self); | |
53 static link_t process_command(vm_t *self,link_t link_values); | |
54 | |
55 static void ifoOpenNewVTSI(vm_t *self,dvd_reader_t *dvd, int vtsN); | |
56 static pgcit_t* get_PGCIT(vm_t *self); | |
57 static int get_video_aspect(vm_t *self); | |
58 | |
59 /* Can only be called when in VTS_DOMAIN */ | |
60 static int get_TT(vm_t *self,int tt); | |
61 static int get_VTS_TT(vm_t *self,int vtsN, int vts_ttn); | |
62 static int get_VTS_PTT(vm_t *self,int vtsN, int vts_ttn, int part); | |
63 | |
64 static int get_MENU(vm_t *self,int menu); /* VTSM & VMGM */ | |
65 static int get_FP_PGC(vm_t *self); /* FP */ | |
66 | |
67 /* Called in any domain */ | |
68 static int get_ID(vm_t *self,int id); | |
69 static int get_PGC(vm_t *self,int pgcN); | |
70 static int get_PGCN(vm_t *self); | |
71 | |
72 /* Initialisation */ | |
73 | |
74 vm_t* vm_new_vm() { | |
75 vm_t *vm = (vm_t*)calloc(sizeof(vm_t), sizeof(char)); | |
76 | |
77 return vm; | |
78 } | |
79 | |
80 static void vm_print_current_domain_state(vm_t *self) { | |
81 switch((self->state).domain) { | |
82 case VTS_DOMAIN: | |
83 fprintf(stderr, "Video Title Domain: -\n"); | |
84 break; | |
85 | |
86 case VTSM_DOMAIN: | |
87 fprintf(stderr, "Video Title Menu Domain: -\n"); | |
88 break; | |
89 | |
90 case VMGM_DOMAIN: | |
91 fprintf(stderr, "Video Manager Menu Domain: -\n"); | |
92 break; | |
93 | |
94 case FP_DOMAIN: | |
95 fprintf(stderr, "First Play Domain: -\n"); | |
96 break; | |
97 | |
98 default: | |
99 fprintf(stderr, "Unknown Domain: -\n"); | |
100 break; | |
101 } | |
102 fprintf(stderr, "VTS:%d PG:%u CELL:%u BLOCK:%u VTS_TTN:%u TTN:%u TT_PGCN:%u\n", | |
103 (self->state).vtsN, | |
104 (self->state).pgN, | |
105 (self->state).cellN, | |
106 (self->state).blockN, | |
107 (self->state).VTS_TTN_REG, | |
108 (self->state).TTN_REG, | |
109 (self->state).TT_PGCN_REG); | |
110 } | |
111 | |
112 void vm_stop(vm_t *self) { | |
113 if(!self) | |
114 return; | |
115 | |
116 if(self->vmgi) { | |
117 ifoClose(self->vmgi); | |
4
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
118 self->vmgi=NULL; |
0 | 119 } |
120 | |
121 if(self->vtsi) { | |
122 ifoClose(self->vtsi); | |
4
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
123 self->vmgi=NULL; |
0 | 124 } |
125 | |
126 if(self->dvd) { | |
127 DVDClose(self->dvd); | |
4
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
128 self->dvd=NULL; |
0 | 129 } |
130 } | |
131 | |
132 void vm_free_vm(vm_t *self) { | |
133 if(self) { | |
134 vm_stop(self); | |
135 free(self); | |
136 } | |
137 } | |
138 | |
139 /* IFO Access */ | |
140 | |
141 ifo_handle_t *vm_get_vmgi(vm_t *self) { | |
142 if(!self) | |
143 return NULL; | |
144 | |
145 return self->vmgi; | |
146 } | |
147 | |
148 ifo_handle_t *vm_get_vtsi(vm_t *self) { | |
149 if(!self) | |
150 return NULL; | |
151 | |
152 return self->vtsi; | |
153 } | |
154 | |
155 /* Reader Access */ | |
156 | |
157 dvd_reader_t *vm_get_dvd_reader(vm_t *self) { | |
158 if(!self) | |
159 return NULL; | |
160 | |
161 return self->dvd; | |
162 } | |
163 | |
164 int vm_reset(vm_t *self, char *dvdroot) /* , register_t regs) */ { | |
165 /* Setup State */ | |
166 memset((self->state).registers.SPRM, 0, sizeof(uint16_t)*24); | |
167 memset((self->state).registers.GPRM, 0, sizeof((self->state).registers.GPRM)); | |
168 (self->state).registers.SPRM[0] = ('e'<<8)|'n'; /* Player Menu Languange code */ | |
169 (self->state).AST_REG = 15; /* 15 why? */ | |
170 (self->state).SPST_REG = 62; /* 62 why? */ | |
171 (self->state).AGL_REG = 1; | |
172 (self->state).TTN_REG = 1; | |
173 (self->state).VTS_TTN_REG = 1; | |
174 /* (self->state).TT_PGCN_REG = 0 */ | |
175 (self->state).PTTN_REG = 1; | |
176 (self->state).HL_BTNN_REG = 1 << 10; | |
177 | |
178 (self->state).PTL_REG = 15; /* Parental Level */ | |
179 (self->state).registers.SPRM[12] = ('U'<<8)|'S'; /* Parental Management Country Code */ | |
180 (self->state).registers.SPRM[16] = ('e'<<8)|'n'; /* Initial Language Code for Audio */ | |
181 (self->state).registers.SPRM[18] = ('e'<<8)|'n'; /* Initial Language Code for Spu */ | |
182 /* Player Regional Code Mask. | |
183 * bit0 = Region 1 | |
184 * bit1 = Region 2 | |
185 */ | |
186 (self->state).registers.SPRM[20] = 0x1; /* Player Regional Code Mask. Region free! */ | |
187 (self->state).registers.SPRM[14] = 0x100; /* Try Pan&Scan */ | |
188 | |
189 (self->state).pgN = 0; | |
190 (self->state).cellN = 0; | |
191 | |
192 (self->state).domain = FP_DOMAIN; | |
193 (self->state).rsm_vtsN = 0; | |
194 (self->state).rsm_cellN = 0; | |
195 (self->state).rsm_blockN = 0; | |
196 | |
197 (self->state).vtsN = -1; | |
198 | |
4
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
199 if (self->dvd && dvdroot) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
200 // a new dvd device has been requested |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
201 vm_stop(self); |
0 | 202 } |
4
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
203 if (!self->dvd) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
204 self->dvd = DVDOpen(dvdroot); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
205 if(!self->dvd) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
206 fprintf(stderr, "vm: faild to open/read the DVD\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
207 return -1; |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
208 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
209 |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
210 self->vmgi = ifoOpenVMGI(self->dvd); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
211 if(!self->vmgi) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
212 fprintf(stderr, "vm: faild to read VIDEO_TS.IFO\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
213 return -1; |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
214 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
215 if(!ifoRead_FP_PGC(self->vmgi)) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
216 fprintf(stderr, "vm: ifoRead_FP_PGC failed\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
217 return -1; |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
218 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
219 if(!ifoRead_TT_SRPT(self->vmgi)) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
220 fprintf(stderr, "vm: ifoRead_TT_SRPT failed\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
221 return -1; |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
222 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
223 if(!ifoRead_PGCI_UT(self->vmgi)) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
224 fprintf(stderr, "vm: ifoRead_PGCI_UT failed\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
225 return -1; |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
226 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
227 if(!ifoRead_PTL_MAIT(self->vmgi)) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
228 fprintf(stderr, "vm: ifoRead_PTL_MAIT failed\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
229 ; /* return -1; Not really used for now.. */ |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
230 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
231 if(!ifoRead_VTS_ATRT(self->vmgi)) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
232 fprintf(stderr, "vm: ifoRead_VTS_ATRT failed\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
233 ; /* return -1; Not really used for now.. */ |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
234 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
235 if(!ifoRead_VOBU_ADMAP(self->vmgi)) { |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
236 fprintf(stderr, "vm: ifoRead_VOBU_ADMAP vgmi failed\n"); |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
237 ; /* return -1; Not really used for now.. */ |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
238 } |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
239 /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */ |
0 | 240 } |
4
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
241 else fprintf(stderr, "vm: reset\n"); |
0 | 242 |
243 return 0; | |
244 } | |
245 | |
246 /* FIXME TODO XXX $$$ Handle error condition too... */ | |
247 int vm_start(vm_t *self) | |
248 { | |
249 link_t link_values; | |
250 | |
251 /* Set pgc to FP pgc */ | |
252 get_FP_PGC(self); | |
253 link_values = play_PGC(self); | |
254 link_values = process_command(self,link_values); | |
255 assert(link_values.command == PlayThis); | |
256 (self->state).blockN = link_values.data1; | |
257 | |
258 return 0; /* ?? */ | |
259 } | |
260 | |
261 int vm_start_title(vm_t *self, int tt) { | |
262 link_t link_values; | |
263 | |
264 get_TT(self, tt); | |
265 link_values = play_PGC(self); | |
266 link_values = process_command(self, link_values); | |
267 assert(link_values.command == PlayThis); | |
268 (self->state).blockN = link_values.data1; | |
269 | |
270 return 0; /* ?? */ | |
271 } | |
272 | |
273 int vm_jump_prog(vm_t *self, int pr) { | |
274 link_t link_values; | |
275 | |
276 (self->state).pgN = pr; /* ?? */ | |
277 | |
278 get_PGC(self, get_PGCN(self)); | |
279 link_values = play_PG(self); | |
280 link_values = process_command(self, link_values); | |
281 assert(link_values.command == PlayThis); | |
282 (self->state).blockN = link_values.data1; | |
283 | |
284 return 0; /* ?? */ | |
285 } | |
286 | |
287 int vm_eval_cmd(vm_t *self, vm_cmd_t *cmd) | |
288 { | |
289 link_t link_values; | |
290 | |
291 if(vmEval_CMD(cmd, 1, &(self->state).registers, &link_values)) { | |
292 link_values = process_command(self, link_values); | |
293 assert(link_values.command == PlayThis); | |
294 (self->state).blockN = link_values.data1; | |
295 return 1; /* Something changed, Jump */ | |
296 } else { | |
297 return 0; /* It updated some state thats all... */ | |
298 } | |
299 } | |
300 | |
301 int vm_get_next_cell(vm_t *self) | |
302 { | |
303 link_t link_values; | |
304 link_values = play_Cell_post(self); | |
305 link_values = process_command(self,link_values); | |
306 assert(link_values.command == PlayThis); | |
307 (self->state).blockN = link_values.data1; | |
308 | |
309 return 0; /* ?? */ | |
310 } | |
311 | |
312 int vm_top_pg(vm_t *self) | |
313 { | |
314 link_t link_values; | |
315 link_values = play_PG(self); | |
316 link_values = process_command(self,link_values); | |
317 assert(link_values.command == PlayThis); | |
318 (self->state).blockN = link_values.data1; | |
319 | |
320 return 1; /* Jump */ | |
321 } | |
322 | |
323 int vm_go_up(vm_t *self) | |
324 { | |
325 link_t link_values; | |
326 | |
327 if(get_PGC(self, (self->state).pgc->goup_pgc_nr)) | |
328 assert(0); | |
329 | |
330 link_values = play_PGC(self); | |
331 link_values = process_command(self,link_values); | |
332 assert(link_values.command == PlayThis); | |
333 (self->state).blockN = link_values.data1; | |
334 | |
335 return 1; /* Jump */ | |
336 } | |
337 | |
338 int vm_next_pg(vm_t *self) | |
339 { | |
340 /* Do we need to get a updated pgN value first? */ | |
341 (self->state).pgN += 1; | |
342 return vm_top_pg(self); | |
343 } | |
344 | |
345 int vm_prev_pg(vm_t *self) | |
346 { | |
347 /* Do we need to get a updated pgN value first? */ | |
348 (self->state).pgN -= 1; | |
349 if((self->state).pgN == 0) { | |
350 /* Check for previous PGCN ? */ | |
351 (self->state).pgN = 1; | |
352 /* return 0; */ | |
353 } | |
354 return vm_top_pg(self); | |
355 } | |
356 | |
357 | |
358 static domain_t menuid2domain(DVDMenuID_t menuid) | |
359 { | |
360 domain_t result = VTSM_DOMAIN; /* Really shouldn't have to.. */ | |
361 | |
362 switch(menuid) { | |
363 case DVD_MENU_Title: | |
364 result = VMGM_DOMAIN; | |
365 break; | |
366 case DVD_MENU_Root: | |
367 case DVD_MENU_Subpicture: | |
368 case DVD_MENU_Audio: | |
369 case DVD_MENU_Angle: | |
370 case DVD_MENU_Part: | |
371 result = VTSM_DOMAIN; | |
372 break; | |
373 } | |
374 | |
375 return result; | |
376 } | |
377 | |
378 int vm_menu_call(vm_t *self, DVDMenuID_t menuid, int block) | |
379 { | |
380 domain_t old_domain; | |
381 link_t link_values; | |
382 | |
383 /* Should check if we are allowed/can acces this menu */ | |
384 | |
385 | |
386 /* FIXME XXX $$$ How much state needs to be restored | |
387 * when we fail to find a menu? */ | |
388 | |
389 old_domain = (self->state).domain; | |
390 | |
391 switch((self->state).domain) { | |
392 case VTS_DOMAIN: | |
393 saveRSMinfo(self, 0, block); | |
394 /* FALL THROUGH */ | |
395 case VTSM_DOMAIN: | |
396 case VMGM_DOMAIN: | |
397 (self->state).domain = menuid2domain(menuid); | |
398 if(get_PGCIT(self) != NULL && get_MENU(self, menuid) != -1) { | |
399 link_values = play_PGC(self); | |
400 link_values = process_command(self, link_values); | |
401 assert(link_values.command == PlayThis); | |
402 (self->state).blockN = link_values.data1; | |
403 return 1; /* Jump */ | |
404 } else { | |
405 (self->state).domain = old_domain; | |
406 } | |
407 break; | |
408 case FP_DOMAIN: /* FIXME XXX $$$ What should we do here? */ | |
409 break; | |
410 } | |
411 | |
412 return 0; | |
413 } | |
414 | |
415 | |
416 int vm_resume(vm_t *self) | |
417 { | |
418 int i; | |
419 link_t link_values; | |
420 | |
421 /* Check and see if there is any rsm info!! */ | |
422 if((self->state).rsm_vtsN == 0) { | |
423 return 0; | |
424 } | |
425 | |
426 (self->state).domain = VTS_DOMAIN; | |
427 ifoOpenNewVTSI(self, self->dvd, (self->state).rsm_vtsN); | |
428 get_PGC(self, (self->state).rsm_pgcN); | |
429 | |
430 /* These should never be set in SystemSpace and/or MenuSpace */ | |
431 /* (self->state).TTN_REG = (self->state).rsm_tt; */ | |
432 /* (self->state).TT_PGCN_REG = (self->state).rsm_pgcN; */ | |
433 /* (self->state).HL_BTNN_REG = (self->state).rsm_btnn; */ | |
434 for(i = 0; i < 5; i++) { | |
435 (self->state).registers.SPRM[4 + i] = (self->state).rsm_regs[i]; | |
436 } | |
437 | |
438 if((self->state).rsm_cellN == 0) { | |
439 assert((self->state).cellN); /* Checking if this ever happens */ | |
440 (self->state).pgN = 1; | |
441 link_values = play_PG(self); | |
442 link_values = process_command(self, link_values); | |
443 assert(link_values.command == PlayThis); | |
444 (self->state).blockN = link_values.data1; | |
445 } else { | |
446 (self->state).cellN = (self->state).rsm_cellN; | |
447 (self->state).blockN = (self->state).rsm_blockN; | |
448 /* (self->state).pgN = ?? does this gets the righ value in play_Cell, no! */ | |
449 if(set_PGN(self)) { | |
450 /* Were at or past the end of the PGC, should not happen for a RSM */ | |
451 assert(0); | |
452 play_PGC_post(self); | |
453 } | |
454 } | |
455 | |
456 return 1; /* Jump */ | |
457 } | |
458 | |
459 /** | |
460 * Return the substream id for 'logical' audio stream audioN. | |
461 * 0 <= audioN < 8 | |
462 */ | |
463 int vm_get_audio_stream(vm_t *self, int audioN) | |
464 { | |
465 int streamN = -1; | |
3
328eadb3f37e
Added initial example programs directory and make sure all debug/error output goes to stderr.
richwareham
parents:
0
diff
changeset
|
466 fprintf(stderr,"dvdnav:vm.c:get_audio_stream audioN=%d\n",audioN); |
0 | 467 if((self->state).domain == VTSM_DOMAIN |
468 || (self->state).domain == VMGM_DOMAIN | |
469 || (self->state).domain == FP_DOMAIN) { | |
470 audioN = 0; | |
471 } | |
472 | |
473 if(audioN < 8) { | |
474 /* Is there any contol info for this logical stream */ | |
475 if((self->state).pgc->audio_control[audioN] & (1<<15)) { | |
476 streamN = ((self->state).pgc->audio_control[audioN] >> 8) & 0x07; | |
477 } | |
478 } | |
479 | |
480 if((self->state).domain == VTSM_DOMAIN | |
481 || (self->state).domain == VMGM_DOMAIN | |
482 || (self->state).domain == FP_DOMAIN) { | |
483 if(streamN == -1) | |
484 streamN = 0; | |
485 } | |
486 | |
487 /* Should also check in vtsi/vmgi status that what kind of stream | |
488 * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */ | |
489 return streamN; | |
490 } | |
491 | |
492 /** | |
493 * Return the substream id for 'logical' subpicture stream subpN. | |
494 * 0 <= subpN < 32 | |
495 */ | |
496 int vm_get_subp_stream(vm_t *self, int subpN) | |
497 { | |
498 int streamN = -1; | |
499 int source_aspect = get_video_aspect(self); | |
500 | |
501 if((self->state).domain == VTSM_DOMAIN | |
502 || (self->state).domain == VMGM_DOMAIN | |
503 || (self->state).domain == FP_DOMAIN) { | |
504 subpN = 0; | |
505 } | |
506 | |
507 if(subpN < 32) { /* a valid logical stream */ | |
508 /* Is this logical stream present */ | |
509 if((self->state).pgc->subp_control[subpN] & (1<<31)) { | |
510 if(source_aspect == 0) /* 4:3 */ | |
511 streamN = ((self->state).pgc->subp_control[subpN] >> 24) & 0x1f; | |
512 if(source_aspect == 3) /* 16:9 */ | |
513 streamN = ((self->state).pgc->subp_control[subpN] >> 16) & 0x1f; | |
514 } | |
515 } | |
516 | |
517 /* Paranoia.. if no stream select 0 anyway */ | |
518 /* I am not paranoid */ | |
519 /* if((self->state).domain == VTSM_DOMAIN | |
520 || (self->state).domain == VMGM_DOMAIN | |
521 || (self->state).domain == FP_DOMAIN) { | |
522 if(streamN == -1) | |
523 streamN = 0; | |
524 } | |
525 */ | |
526 /* Should also check in vtsi/vmgi status that what kind of stream it is. */ | |
527 return streamN; | |
528 } | |
529 | |
530 int vm_get_subp_active_stream(vm_t *self) | |
531 { | |
532 int subpN; | |
533 int streamN; | |
534 subpN = (self->state).SPST_REG & ~0x40; | |
535 streamN = vm_get_subp_stream(self, subpN); | |
536 | |
537 /* If no such stream, then select the first one that exists. */ | |
538 if(streamN == -1) { | |
539 for(subpN = 0; subpN < 32; subpN++) { | |
540 if((self->state).pgc->subp_control[subpN] & (1<<31)) { | |
541 | |
542 streamN = vm_get_subp_stream(self, subpN); | |
543 break; | |
544 } | |
545 } | |
546 } | |
547 | |
548 /* We should instead send the on/off status to the spudecoder / mixer */ | |
549 /* If we are in the title domain see if the spu mixing is on */ | |
550 if((self->state).domain == VTS_DOMAIN && !((self->state).SPST_REG & 0x40)) { | |
551 /* Bit 7 set means hide, and only let Forced display show */ | |
552 return (streamN | 0x80); | |
553 } else { | |
554 return streamN; | |
555 } | |
556 } | |
557 | |
558 int vm_get_audio_active_stream(vm_t *self) | |
559 { | |
560 int audioN; | |
561 int streamN; | |
562 audioN = (self->state).AST_REG ; | |
563 streamN = vm_get_audio_stream(self, audioN); | |
564 | |
565 /* If no such stream, then select the first one that exists. */ | |
566 if(streamN == -1) { | |
567 for(audioN = 0; audioN < 8; audioN++) { | |
568 if((self->state).pgc->audio_control[audioN] & (1<<15)) { | |
569 streamN = vm_get_audio_stream(self, audioN); | |
570 break; | |
571 } | |
572 } | |
573 } | |
574 | |
575 return streamN; | |
576 } | |
577 | |
578 | |
579 void vm_get_angle_info(vm_t *self, int *num_avail, int *current) | |
580 { | |
581 *num_avail = 1; | |
582 *current = 1; | |
583 | |
584 if((self->state).domain == VTS_DOMAIN) { | |
585 /* TTN_REG does not allways point to the correct title.. */ | |
586 title_info_t *title; | |
587 if((self->state).TTN_REG > self->vmgi->tt_srpt->nr_of_srpts) | |
588 return; | |
589 title = &self->vmgi->tt_srpt->title[(self->state).TTN_REG - 1]; | |
590 if(title->title_set_nr != (self->state).vtsN || | |
591 title->vts_ttn != (self->state).VTS_TTN_REG) | |
592 return; | |
593 *num_avail = title->nr_of_angles; | |
594 *current = (self->state).AGL_REG; | |
595 if(*current > *num_avail) /* Is this really a good idea? */ | |
596 *current = *num_avail; | |
597 } | |
598 } | |
599 | |
600 | |
601 void vm_get_audio_info(vm_t *self, int *num_avail, int *current) | |
602 { | |
603 if((self->state).domain == VTS_DOMAIN) { | |
604 *num_avail = self->vtsi->vtsi_mat->nr_of_vts_audio_streams; | |
605 *current = (self->state).AST_REG; | |
606 } else if((self->state).domain == VTSM_DOMAIN) { | |
607 *num_avail = self->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */ | |
608 *current = 1; | |
609 } else if((self->state).domain == VMGM_DOMAIN || (self->state).domain == FP_DOMAIN) { | |
610 *num_avail = self->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */ | |
611 *current = 1; | |
612 } | |
613 } | |
614 | |
615 void vm_get_subp_info(vm_t *self, int *num_avail, int *current) | |
616 { | |
617 if((self->state).domain == VTS_DOMAIN) { | |
618 *num_avail = self->vtsi->vtsi_mat->nr_of_vts_subp_streams; | |
619 *current = (self->state).SPST_REG; | |
620 } else if((self->state).domain == VTSM_DOMAIN) { | |
621 *num_avail = self->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */ | |
622 *current = 0x41; | |
623 } else if((self->state).domain == VMGM_DOMAIN || (self->state).domain == FP_DOMAIN) { | |
624 *num_avail = self->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */ | |
625 *current = 0x41; | |
626 } | |
627 } | |
628 | |
629 subp_attr_t vm_get_subp_attr(vm_t *self, int streamN) | |
630 { | |
631 subp_attr_t attr; | |
632 | |
633 if((self->state).domain == VTS_DOMAIN) { | |
634 attr = self->vtsi->vtsi_mat->vts_subp_attr[streamN]; | |
635 } else if((self->state).domain == VTSM_DOMAIN) { | |
636 attr = self->vtsi->vtsi_mat->vtsm_subp_attr; | |
637 } else if((self->state).domain == VMGM_DOMAIN || (self->state).domain == FP_DOMAIN) { | |
638 attr = self->vmgi->vmgi_mat->vmgm_subp_attr; | |
639 } | |
640 return attr; | |
641 } | |
642 | |
643 audio_attr_t vm_get_audio_attr(vm_t *self, int streamN) | |
644 { | |
645 audio_attr_t attr; | |
646 | |
647 if((self->state).domain == VTS_DOMAIN) { | |
648 attr = self->vtsi->vtsi_mat->vts_audio_attr[streamN]; | |
649 } else if((self->state).domain == VTSM_DOMAIN) { | |
650 attr = self->vtsi->vtsi_mat->vtsm_audio_attr; | |
651 } else if((self->state).domain == VMGM_DOMAIN || (self->state).domain == FP_DOMAIN) { | |
652 attr = self->vmgi->vmgi_mat->vmgm_audio_attr; | |
653 } | |
654 return attr; | |
655 } | |
656 | |
657 video_attr_t vm_get_video_attr(vm_t *self) | |
658 { | |
659 video_attr_t attr; | |
660 | |
661 if((self->state).domain == VTS_DOMAIN) { | |
662 attr = self->vtsi->vtsi_mat->vts_video_attr; | |
663 } else if((self->state).domain == VTSM_DOMAIN) { | |
664 attr = self->vtsi->vtsi_mat->vtsm_video_attr; | |
665 } else if((self->state).domain == VMGM_DOMAIN || (self->state).domain == FP_DOMAIN) { | |
666 attr = self->vmgi->vmgi_mat->vmgm_video_attr; | |
667 } | |
668 return attr; | |
669 } | |
670 | |
671 void vm_get_video_res(vm_t *self, int *width, int *height) | |
672 { | |
673 video_attr_t attr; | |
674 | |
675 attr = vm_get_video_attr(self); | |
676 | |
677 if(attr.video_format != 0) | |
678 *height = 576; | |
679 else | |
680 *height = 480; | |
681 switch(attr.picture_size) { | |
682 case 0: | |
683 *width = 720; | |
684 break; | |
685 case 1: | |
686 *width = 704; | |
687 break; | |
688 case 2: | |
689 *width = 352; | |
690 break; | |
691 case 3: | |
692 *width = 352; | |
693 *height /= 2; | |
694 break; | |
695 } | |
696 } | |
697 | |
698 /* Must be called before domain is changed (get_PGCN()) */ | |
699 static void saveRSMinfo(vm_t *self, int cellN, int blockN) | |
700 { | |
701 int i; | |
702 | |
703 if(cellN != 0) { | |
704 (self->state).rsm_cellN = cellN; | |
705 (self->state).rsm_blockN = 0; | |
706 } else { | |
707 (self->state).rsm_cellN = (self->state).cellN; | |
708 (self->state).rsm_blockN = blockN; | |
709 } | |
710 (self->state).rsm_vtsN = (self->state).vtsN; | |
711 (self->state).rsm_pgcN = get_PGCN(self); | |
712 | |
713 /* assert((self->state).rsm_pgcN == (self->state).TT_PGCN_REG); // for VTS_DOMAIN */ | |
714 | |
715 for(i = 0; i < 5; i++) { | |
716 (self->state).rsm_regs[i] = (self->state).registers.SPRM[4 + i]; | |
717 } | |
718 } | |
719 | |
720 | |
721 | |
722 /* Figure out the correct pgN from the cell and update (self->state). */ | |
723 static int set_PGN(vm_t *self) { | |
724 int new_pgN = 0; | |
725 | |
726 while(new_pgN < (self->state).pgc->nr_of_programs | |
727 && (self->state).cellN >= (self->state).pgc->program_map[new_pgN]) | |
728 new_pgN++; | |
729 | |
730 if(new_pgN == (self->state).pgc->nr_of_programs) /* We are at the last program */ | |
731 if((self->state).cellN > (self->state).pgc->nr_of_cells) | |
732 return 1; /* We are past the last cell */ | |
733 | |
734 (self->state).pgN = new_pgN; | |
735 | |
736 if((self->state).domain == VTS_DOMAIN) { | |
737 playback_type_t *pb_ty; | |
738 if((self->state).TTN_REG > self->vmgi->tt_srpt->nr_of_srpts) | |
739 return 0; /* ?? */ | |
740 pb_ty = &self->vmgi->tt_srpt->title[(self->state).TTN_REG - 1].pb_ty; | |
741 if(pb_ty->multi_or_random_pgc_title == /* One_Sequential_PGC_Title */ 0) { | |
742 #if 0 /* TTN_REG can't be trusted to have a correct value here... */ | |
743 vts_ptt_srpt_t *ptt_srpt = vtsi->vts_ptt_srpt; | |
744 assert((self->state).VTS_TTN_REG <= ptt_srpt->nr_of_srpts); | |
745 assert(get_PGCN() == ptt_srpt->title[(self->state).VTS_TTN_REG - 1].ptt[0].pgcn); | |
746 assert(1 == ptt_srpt->title[(self->state).VTS_TTN_REG - 1].ptt[0].pgn); | |
747 #endif | |
748 (self->state).PTTN_REG = (self->state).pgN; | |
749 } | |
750 } | |
751 | |
752 return 0; | |
753 } | |
754 | |
755 | |
756 | |
757 | |
758 | |
759 static link_t play_PGC(vm_t *self) | |
760 { | |
761 link_t link_values; | |
762 | |
763 fprintf(stderr, "vm: play_PGC:"); | |
764 if((self->state).domain != FP_DOMAIN) | |
765 fprintf(stderr, " (self->state).pgcN (%i)\n", get_PGCN(self)); | |
766 else | |
767 fprintf(stderr, " first_play_pgc\n"); | |
768 | |
769 /* This must be set before the pre-commands are executed because they */ | |
770 /* might contain a CallSS that will save resume state */ | |
771 (self->state).pgN = 1; | |
772 (self->state).cellN = 0; | |
773 | |
774 /* eval -> updates the state and returns either | |
775 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) | |
776 - just play video i.e first PG | |
777 (This is what happens if you fall of the end of the pre_cmds) | |
778 - or a error (are there more cases?) */ | |
779 if((self->state).pgc->command_tbl && (self->state).pgc->command_tbl->nr_of_pre) { | |
780 if(vmEval_CMD((self->state).pgc->command_tbl->pre_cmds, | |
781 (self->state).pgc->command_tbl->nr_of_pre, | |
782 &(self->state).registers, &link_values)) { | |
783 /* link_values contains the 'jump' return value */ | |
784 return link_values; | |
785 } else { | |
786 fprintf(stderr, "PGC pre commands didn't do a Jump, Link or Call\n"); | |
787 } | |
788 } | |
789 return play_PG(self); | |
790 } | |
791 | |
792 | |
793 static link_t play_PG(vm_t *self) | |
794 { | |
795 fprintf(stderr, "play_PG: (self->state).pgN (%i)\n", (self->state).pgN); | |
796 | |
797 assert((self->state).pgN > 0); | |
798 if((self->state).pgN > (self->state).pgc->nr_of_programs) { | |
799 fprintf(stderr, "(self->state).pgN (%i) == pgc->nr_of_programs + 1 (%i)\n", | |
800 (self->state).pgN, (self->state).pgc->nr_of_programs + 1); | |
801 assert((self->state).pgN == (self->state).pgc->nr_of_programs + 1); | |
802 return play_PGC_post(self); | |
803 } | |
804 | |
805 (self->state).cellN = (self->state).pgc->program_map[(self->state).pgN - 1]; | |
806 | |
807 return play_Cell(self); | |
808 } | |
809 | |
810 | |
811 static link_t play_Cell(vm_t *self) | |
812 { | |
813 fprintf(stderr, "play_Cell: (self->state).cellN (%i)\n", (self->state).cellN); | |
814 | |
815 assert((self->state).cellN > 0); | |
816 if((self->state).cellN > (self->state).pgc->nr_of_cells) { | |
817 fprintf(stderr, "(self->state).cellN (%i) == pgc->nr_of_cells + 1 (%i)\n", | |
818 (self->state).cellN, (self->state).pgc->nr_of_cells + 1); | |
819 assert((self->state).cellN == (self->state).pgc->nr_of_cells + 1); | |
820 return play_PGC_post(self); | |
821 } | |
822 | |
823 | |
824 /* Multi angle/Interleaved */ | |
825 switch((self->state).pgc->cell_playback[(self->state).cellN - 1].block_mode) { | |
826 case 0: /* Normal */ | |
827 assert((self->state).pgc->cell_playback[(self->state).cellN - 1].block_type == 0); | |
828 break; | |
829 case 1: /* The first cell in the block */ | |
830 switch((self->state).pgc->cell_playback[(self->state).cellN - 1].block_type) { | |
831 case 0: /* Not part of a block */ | |
832 assert(0); | |
833 case 1: /* Angle block */ | |
834 /* Loop and check each cell instead? So we don't get outsid the block. */ | |
835 (self->state).cellN += (self->state).AGL_REG - 1; | |
836 assert((self->state).cellN <= (self->state).pgc->nr_of_cells); | |
837 assert((self->state).pgc->cell_playback[(self->state).cellN - 1].block_mode != 0); | |
838 assert((self->state).pgc->cell_playback[(self->state).cellN - 1].block_type == 1); | |
839 break; | |
840 case 2: /* ?? */ | |
841 case 3: /* ?? */ | |
842 default: | |
843 fprintf(stderr, "Invalid? Cell block_mode (%d), block_type (%d)\n", | |
844 (self->state).pgc->cell_playback[(self->state).cellN - 1].block_mode, | |
845 (self->state).pgc->cell_playback[(self->state).cellN - 1].block_type); | |
846 } | |
847 break; | |
848 case 2: /* Cell in the block */ | |
849 case 3: /* Last cell in the block */ | |
850 /* These might perhaps happen for RSM or LinkC commands? */ | |
851 default: | |
852 fprintf(stderr, "Cell is in block but did not enter at first cell!\n"); | |
853 } | |
854 | |
855 /* Updates (self->state).pgN and PTTN_REG */ | |
856 if(set_PGN(self)) { | |
857 /* Should not happen */ | |
858 link_t tmp = {LinkTailPGC, /* No Button */ 0, 0, 0}; | |
859 assert(0); | |
860 return tmp; | |
861 } | |
862 | |
863 { | |
864 link_t tmp = {PlayThis, /* Block in Cell */ 0, 0, 0}; | |
865 return tmp; | |
866 } | |
867 | |
868 } | |
869 | |
870 static link_t play_Cell_post(vm_t *self) | |
871 { | |
872 cell_playback_t *cell; | |
873 | |
874 fprintf(stderr, "play_Cell_post: (self->state).cellN (%i)\n", (self->state).cellN); | |
875 | |
876 cell = &(self->state).pgc->cell_playback[(self->state).cellN - 1]; | |
877 | |
878 /* Still time is already taken care of before we get called. */ | |
879 | |
880 /* Deal with a Cell command, if any */ | |
881 if(cell->cell_cmd_nr != 0) { | |
882 link_t link_values; | |
883 | |
884 assert((self->state).pgc->command_tbl != NULL); | |
885 assert((self->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr); | |
886 fprintf(stderr, "Cell command pressent, executing\n"); | |
887 if(vmEval_CMD(&(self->state).pgc->command_tbl->cell_cmds[cell->cell_cmd_nr - 1], 1, | |
888 &(self->state).registers, &link_values)) { | |
889 return link_values; | |
890 } else { | |
891 fprintf(stderr, "Cell command didn't do a Jump, Link or Call\n"); | |
892 /* Error ?? goto tail? goto next PG? or what? just continue? */ | |
893 } | |
894 } | |
895 | |
896 | |
897 /* Where to continue after playing the cell... */ | |
898 /* Multi angle/Interleaved */ | |
899 switch((self->state).pgc->cell_playback[(self->state).cellN - 1].block_mode) { | |
900 case 0: /* Normal */ | |
901 assert((self->state).pgc->cell_playback[(self->state).cellN - 1].block_type == 0); | |
902 (self->state).cellN++; | |
903 break; | |
904 case 1: /* The first cell in the block */ | |
905 case 2: /* A cell in the block */ | |
906 case 3: /* The last cell in the block */ | |
907 default: | |
908 switch((self->state).pgc->cell_playback[(self->state).cellN - 1].block_type) { | |
909 case 0: /* Not part of a block */ | |
910 assert(0); | |
911 case 1: /* Angle block */ | |
912 /* Skip the 'other' angles */ | |
913 (self->state).cellN++; | |
914 while((self->state).cellN <= (self->state).pgc->nr_of_cells | |
915 && (self->state).pgc->cell_playback[(self->state).cellN - 1].block_mode >= 2) { | |
916 (self->state).cellN++; | |
917 } | |
918 break; | |
919 case 2: /* ?? */ | |
920 case 3: /* ?? */ | |
921 default: | |
922 fprintf(stderr, "Invalid? Cell block_mode (%d), block_type (%d)\n", | |
923 (self->state).pgc->cell_playback[(self->state).cellN - 1].block_mode, | |
924 (self->state).pgc->cell_playback[(self->state).cellN - 1].block_type); | |
925 } | |
926 break; | |
927 } | |
928 | |
929 | |
930 /* Figure out the correct pgN for the new cell */ | |
931 if(set_PGN(self)) { | |
932 fprintf(stderr, "last cell in this PGC\n"); | |
933 return play_PGC_post(self); | |
934 } | |
935 | |
936 return play_Cell(self); | |
937 } | |
938 | |
939 | |
940 static link_t play_PGC_post(vm_t *self) | |
941 { | |
942 link_t link_values; | |
943 | |
944 fprintf(stderr, "play_PGC_post:\n"); | |
945 | |
946 assert((self->state).pgc->still_time == 0); /* FIXME $$$ */ | |
947 | |
948 /* eval -> updates the state and returns either | |
949 - some kind of jump (Jump(TT/SS/VTS_TTN/CallSS/link C/PG/PGC/PTTN) | |
950 - or a error (are there more cases?) | |
951 - if you got to the end of the post_cmds, then what ?? */ | |
952 if((self->state).pgc->command_tbl && | |
953 vmEval_CMD((self->state).pgc->command_tbl->post_cmds, | |
954 (self->state).pgc->command_tbl->nr_of_post, | |
955 &(self->state).registers, &link_values)) { | |
956 return link_values; | |
957 } | |
958 | |
959 /* Or perhaps handle it here? */ | |
960 { | |
961 link_t link_next_pgc = {LinkNextPGC, 0, 0, 0}; | |
962 fprintf(stderr, "** Fell of the end of the pgc, continuing in NextPGC\n"); | |
963 assert((self->state).pgc->next_pgc_nr != 0); | |
964 return link_next_pgc; | |
965 } | |
966 } | |
967 | |
968 | |
969 static link_t process_command(vm_t *self, link_t link_values) | |
970 { | |
971 /* FIXME $$$ Move this to a separate function? */ | |
972 self->badness_counter++; | |
973 if (self->badness_counter > 1) fprintf(stderr, "**** process_command re-entered %d*****\n",self->badness_counter); | |
974 while(link_values.command != PlayThis) { | |
975 | |
976 vmPrint_LINK(link_values); | |
977 | |
978 fprintf(stderr, "Link values %i %i %i %i\n", link_values.command, | |
979 link_values.data1, link_values.data2, link_values.data3); | |
980 | |
981 fprintf(stderr, "Before:"); | |
982 vm_print_current_domain_state(self); | |
983 | |
984 switch(link_values.command) { | |
985 case LinkNoLink: | |
986 /* No Link */ | |
987 if(link_values.data1 != 0) | |
988 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
989 exit(1); | |
990 | |
991 case LinkTopC: | |
992 /* Link to Top?? Cell */ | |
993 if(link_values.data1 != 0) | |
994 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
995 link_values = play_Cell(self); | |
996 break; | |
997 case LinkNextC: | |
998 /* Link to Next Cell */ | |
999 if(link_values.data1 != 0) | |
1000 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1001 (self->state).cellN += 1; /* FIXME: What if cellN becomes > nr_of_cells? */ | |
1002 link_values = play_Cell(self); | |
1003 break; | |
1004 case LinkPrevC: | |
1005 /* Link to Previous Cell */ | |
1006 if(link_values.data1 != 0) | |
1007 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1008 (self->state).cellN -= 1; /* FIXME: What if cellN becomes < 1? */ | |
1009 link_values = play_Cell(self); | |
1010 break; | |
1011 | |
1012 case LinkTopPG: | |
1013 /* Link to Top Program */ | |
1014 if(link_values.data1 != 0) | |
1015 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1016 /* Does pgN always contain the current value? */ | |
1017 link_values = play_PG(self); | |
1018 break; | |
1019 case LinkNextPG: | |
1020 /* Link to Next Program */ | |
1021 if(link_values.data1 != 0) | |
1022 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1023 /* Does pgN always contain the current value? */ | |
1024 (self->state).pgN += 1; /* FIXME: What if pgN becomes > pgc.nr_of_programs? */ | |
1025 link_values = play_PG(self); | |
1026 break; | |
1027 case LinkPrevPG: | |
1028 /* Link to Previous Program */ | |
1029 if(link_values.data1 != 0) | |
1030 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1031 /* Does pgN always contain the current value? */ | |
1032 (self->state).pgN -= 1; /* FIXME: What if pgN becomes < 1? */ | |
1033 link_values = play_PG(self); | |
1034 break; | |
1035 | |
1036 case LinkTopPGC: | |
1037 /* Link to Top Program Chain */ | |
1038 if(link_values.data1 != 0) | |
1039 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1040 link_values = play_PGC(self); | |
1041 break; | |
1042 case LinkNextPGC: | |
1043 /* Link to Next Program Chain */ | |
1044 if(link_values.data1 != 0) | |
1045 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1046 assert((self->state).pgc->next_pgc_nr != 0); | |
1047 if(get_PGC(self, (self->state).pgc->next_pgc_nr)) | |
1048 assert(0); | |
1049 link_values = play_PGC(self); | |
1050 break; | |
1051 case LinkPrevPGC: | |
1052 /* Link to Previous Program Chain */ | |
1053 if(link_values.data1 != 0) | |
1054 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1055 assert((self->state).pgc->prev_pgc_nr != 0); | |
1056 if(get_PGC(self, (self->state).pgc->prev_pgc_nr)) | |
1057 assert(0); | |
1058 link_values = play_PGC(self); | |
1059 break; | |
1060 case LinkGoUpPGC: | |
1061 /* Link to GoUp??? Program Chain */ | |
1062 if(link_values.data1 != 0) | |
1063 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1064 assert((self->state).pgc->goup_pgc_nr != 0); | |
1065 if(get_PGC(self, (self->state).pgc->goup_pgc_nr)) | |
1066 assert(0); | |
1067 link_values = play_PGC(self); | |
1068 break; | |
1069 case LinkTailPGC: | |
1070 /* Link to Tail??? Program Chain */ | |
1071 if(link_values.data1 != 0) | |
1072 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1073 link_values = play_PGC_post(self); | |
1074 break; | |
1075 | |
1076 case LinkRSM: | |
1077 { | |
1078 /* Link to Resume */ | |
1079 int i; | |
1080 /* Check and see if there is any rsm info!! */ | |
1081 (self->state).domain = VTS_DOMAIN; | |
1082 ifoOpenNewVTSI(self, self->dvd, (self->state).rsm_vtsN); | |
1083 get_PGC(self, (self->state).rsm_pgcN); | |
1084 | |
1085 /* These should never be set in SystemSpace and/or MenuSpace */ | |
1086 /* (self->state).TTN_REG = rsm_tt; ?? */ | |
1087 /* (self->state).TT_PGCN_REG = (self->state).rsm_pgcN; ?? */ | |
1088 for(i = 0; i < 5; i++) { | |
1089 (self->state).registers.SPRM[4 + i] = (self->state).rsm_regs[i]; | |
1090 } | |
1091 | |
1092 if(link_values.data1 != 0) | |
1093 (self->state).HL_BTNN_REG = link_values.data1 << 10; | |
1094 | |
1095 if((self->state).rsm_cellN == 0) { | |
1096 assert((self->state).cellN); /* Checking if this ever happens */ | |
1097 /* assert( time/block/vobu is 0 ); */ | |
1098 (self->state).pgN = 1; | |
1099 link_values = play_PG(self); | |
1100 } else { | |
1101 /* assert( time/block/vobu is _not_ 0 ); */ | |
1102 /* play_Cell_at_time */ | |
1103 /* (self->state).pgN = ?? this gets the righ value in play_Cell */ | |
1104 (self->state).cellN = (self->state).rsm_cellN; | |
1105 link_values.command = PlayThis; | |
1106 link_values.data1 = (self->state).rsm_blockN; | |
1107 if(set_PGN(self)) { | |
1108 /* Were at the end of the PGC, should not happen for a RSM */ | |
1109 assert(0); | |
1110 link_values.command = LinkTailPGC; | |
1111 link_values.data1 = 0; /* No button */ | |
1112 } | |
1113 } | |
1114 } | |
1115 break; | |
1116 case LinkPGCN: | |
1117 /* Link to Program Chain Number:data1 */ | |
1118 if(get_PGC(self, link_values.data1)) | |
1119 assert(0); | |
1120 link_values = play_PGC(self); | |
1121 break; | |
1122 case LinkPTTN: | |
1123 /* Link to Part of this Title Number:data1 */ | |
1124 assert((self->state).domain == VTS_DOMAIN); | |
1125 if(link_values.data2 != 0) | |
1126 (self->state).HL_BTNN_REG = link_values.data2 << 10; | |
1127 if(get_VTS_PTT(self, (self->state).vtsN, (self->state).VTS_TTN_REG, link_values.data1) == -1) | |
1128 assert(0); | |
1129 link_values = play_PG(self); | |
1130 break; | |
1131 case LinkPGN: | |
1132 /* Link to Program Number:data1 */ | |
1133 if(link_values.data2 != 0) | |
1134 (self->state).HL_BTNN_REG = link_values.data2 << 10; | |
1135 /* Update any other state, PTTN perhaps? */ | |
1136 (self->state).pgN = link_values.data1; | |
1137 link_values = play_PG(self); | |
1138 break; | |
1139 case LinkCN: | |
1140 /* Link to Cell Number:data1 */ | |
1141 if(link_values.data2 != 0) | |
1142 (self->state).HL_BTNN_REG = link_values.data2 << 10; | |
1143 /* Update any other state, pgN, PTTN perhaps? */ | |
1144 (self->state).cellN = link_values.data1; | |
1145 link_values = play_Cell(self); | |
1146 break; | |
1147 | |
1148 case Exit: | |
1149 exit(1); /* What should we do here?? */ | |
1150 | |
1151 case JumpTT: | |
1152 /* Jump to VTS Title Domain */ | |
1153 /* Only allowed from the First Play domain(PGC) */ | |
1154 /* or the Video Manager domain (VMG) */ | |
1155 //fprintf(stderr,"****** JumpTT is Broken, please fix me!!! ****\n"); | |
1156 assert((self->state).domain == VMGM_DOMAIN || (self->state).domain == FP_DOMAIN); /* ?? */ | |
1157 if(get_TT(self,link_values.data1) == -1) | |
1158 assert(0); | |
1159 link_values = play_PGC(self); | |
1160 break; | |
1161 case JumpVTS_TT: | |
1162 /* Jump to Title:data1 in same VTS Title Domain */ | |
1163 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1164 /* or the Video Title Set Domain(VTS) */ | |
1165 assert((self->state).domain == VTSM_DOMAIN || (self->state).domain == VTS_DOMAIN); /* ?? */ | |
1166 /* FIXME: Should be able to use get_VTS_PTT here */ | |
1167 if(get_VTS_TT(self,(self->state).vtsN, link_values.data1) == -1) | |
1168 assert(0); | |
1169 link_values = play_PGC(self); | |
1170 break; | |
1171 case JumpVTS_PTT: | |
1172 /* Jump to Part:data2 of Title:data1 in same VTS Title Domain */ | |
1173 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1174 /* or the Video Title Set Domain(VTS) */ | |
1175 assert((self->state).domain == VTSM_DOMAIN || (self->state).domain == VTS_DOMAIN); /* ?? */ | |
1176 if(get_VTS_PTT(self,(self->state).vtsN, link_values.data1, link_values.data2) == -1) | |
1177 assert(0); | |
1178 link_values = play_PG(self); | |
1179 break; | |
1180 | |
1181 case JumpSS_FP: | |
1182 /* Jump to First Play Domain */ | |
1183 /* Only allowed from the VTS Menu Domain(VTSM) */ | |
1184 /* or the Video Manager domain (VMG) */ | |
1185 assert((self->state).domain == VMGM_DOMAIN || (self->state).domain == VTSM_DOMAIN); /* ?? */ | |
1186 get_FP_PGC(self); | |
1187 link_values = play_PGC(self); | |
1188 break; | |
1189 case JumpSS_VMGM_MENU: | |
1190 /* Jump to Video Manger domain - Title Menu:data1 or any PGC in VMG */ | |
1191 /* Allowed from anywhere except the VTS Title domain */ | |
1192 assert((self->state).domain == VMGM_DOMAIN || | |
1193 (self->state).domain == VTSM_DOMAIN || | |
1194 (self->state).domain == FP_DOMAIN); /* ?? */ | |
1195 (self->state).domain = VMGM_DOMAIN; | |
1196 if(get_MENU(self,link_values.data1) == -1) | |
1197 assert(0); | |
1198 link_values = play_PGC(self); | |
1199 break; | |
1200 case JumpSS_VTSM: | |
1201 /* Jump to a menu in Video Title domain, */ | |
1202 /* or to a Menu is the current VTS */ | |
1203 /* FIXME: This goes badly wrong for some DVDs. */ | |
1204 /* FIXME: Keep in touch with ogle people regarding what to do here */ | |
1205 fprintf(stderr, "dvdnav: BUG TRACKING *******************************************************************\n"); | |
1206 fprintf(stderr, "dvdnav: If you see this message, please report these values to the dvd-devel mailing list.\n"); | |
1207 fprintf(stderr, " data1=%u data2=%u data3=%u\n", | |
1208 link_values.data1, | |
1209 link_values.data2, | |
1210 link_values.data3); | |
1211 fprintf(stderr, "dvdnav: *******************************************************************\n"); | |
1212 | |
1213 if(link_values.data1 !=0) { | |
1214 assert((self->state).domain == VMGM_DOMAIN || (self->state).domain == FP_DOMAIN); /* ?? */ | |
1215 (self->state).domain = VTSM_DOMAIN; | |
1216 ifoOpenNewVTSI(self, self->dvd, link_values.data1); /* Also sets (self->state).vtsN */ | |
1217 } else { | |
1218 /* This happens on 'The Fifth Element' region 2. */ | |
1219 assert((self->state).domain == VTSM_DOMAIN); | |
1220 } | |
1221 /* I don't know what title is supposed to be used for. */ | |
1222 /* Alien or Aliens has this != 1, I think. */ | |
1223 /* assert(link_values.data2 == 1); */ | |
1224 (self->state).VTS_TTN_REG = link_values.data2; | |
1225 if(get_MENU(self, link_values.data3) == -1) | |
1226 assert(0); | |
1227 link_values = play_PGC(self); | |
1228 break; | |
1229 case JumpSS_VMGM_PGC: | |
1230 assert((self->state).domain == VMGM_DOMAIN || | |
1231 (self->state).domain == VTSM_DOMAIN || | |
1232 (self->state).domain == FP_DOMAIN); /* ?? */ | |
1233 (self->state).domain = VMGM_DOMAIN; | |
1234 if(get_PGC(self,link_values.data1) == -1) | |
1235 assert(0); | |
1236 link_values = play_PGC(self); | |
1237 break; | |
1238 | |
1239 case CallSS_FP: | |
1240 assert((self->state).domain == VTS_DOMAIN); /* ?? */ | |
1241 /* Must be called before domain is changed */ | |
1242 saveRSMinfo(self, link_values.data1, /* We dont have block info */ 0); | |
1243 get_FP_PGC(self); | |
1244 link_values = play_PGC(self); | |
1245 break; | |
1246 case CallSS_VMGM_MENU: | |
1247 assert((self->state).domain == VTS_DOMAIN); /* ?? */ | |
1248 /* Must be called before domain is changed */ | |
1249 saveRSMinfo(self,link_values.data2, /* We dont have block info */ 0); | |
1250 (self->state).domain = VMGM_DOMAIN; | |
1251 if(get_MENU(self,link_values.data1) == -1) | |
1252 assert(0); | |
1253 link_values = play_PGC(self); | |
1254 break; | |
1255 case CallSS_VTSM: | |
1256 assert((self->state).domain == VTS_DOMAIN); /* ?? */ | |
1257 /* Must be called before domain is changed */ | |
1258 saveRSMinfo(self,link_values.data2, /* We dont have block info */ 0); | |
1259 (self->state).domain = VTSM_DOMAIN; | |
1260 if(get_MENU(self,link_values.data1) == -1) | |
1261 assert(0); | |
1262 link_values = play_PGC(self); | |
1263 break; | |
1264 case CallSS_VMGM_PGC: | |
1265 assert((self->state).domain == VTS_DOMAIN); /* ?? */ | |
1266 /* Must be called before domain is changed */ | |
1267 saveRSMinfo(self,link_values.data2, /* We dont have block info */ 0); | |
1268 (self->state).domain = VMGM_DOMAIN; | |
1269 if(get_PGC(self,link_values.data1) == -1) | |
1270 assert(0); | |
1271 link_values = play_PGC(self); | |
1272 break; | |
1273 case PlayThis: | |
1274 /* Should never happen. */ | |
1275 break; | |
1276 } | |
1277 fprintf(stderr, "After:"); | |
1278 vm_print_current_domain_state(self); | |
1279 | |
1280 } | |
1281 self->badness_counter--; | |
1282 return link_values; | |
1283 } | |
1284 | |
1285 static int get_TT(vm_t *self, int tt) | |
1286 { | |
1287 //fprintf(stderr,"****** get_TT is Broken, please fix me!!! ****\n"); | |
1288 assert(tt <= self->vmgi->tt_srpt->nr_of_srpts); | |
1289 | |
1290 (self->state).TTN_REG = tt; | |
1291 | |
1292 return get_VTS_TT(self, self->vmgi->tt_srpt->title[tt - 1].title_set_nr, | |
1293 self->vmgi->tt_srpt->title[tt - 1].vts_ttn); | |
1294 } | |
1295 | |
1296 | |
1297 static int get_VTS_TT(vm_t *self, int vtsN, int vts_ttn) | |
1298 { | |
1299 int pgcN; | |
1300 //fprintf(stderr,"****** get_VTS_TT is Broken, please fix me!!! ****\n"); | |
1301 fprintf(stderr,"title_set_nr=%d\n", vtsN); | |
1302 fprintf(stderr,"vts_ttn=%d\n", vts_ttn); | |
1303 | |
1304 (self->state).domain = VTS_DOMAIN; | |
1305 if(vtsN != (self->state).vtsN) { | |
1306 fprintf(stderr,"****** opening new VTSI ****\n"); | |
1307 ifoOpenNewVTSI(self, self->dvd, vtsN); /* Also sets (self->state).vtsN */ | |
1308 fprintf(stderr,"****** opened VTSI ****\n"); | |
1309 } | |
1310 | |
1311 pgcN = get_ID(self, vts_ttn); /* This might return -1 */ | |
1312 assert(pgcN != -1); | |
1313 | |
1314 /* (self->state).TTN_REG = ?? Must search tt_srpt for a matching entry... */ | |
1315 (self->state).VTS_TTN_REG = vts_ttn; | |
1316 /* Any other registers? */ | |
1317 | |
1318 return get_PGC(self, pgcN); | |
1319 } | |
1320 | |
1321 | |
1322 static int get_VTS_PTT(vm_t *self, int vtsN, int /* is this really */ vts_ttn, int part) | |
1323 { | |
1324 int pgcN, pgN; | |
1325 | |
1326 (self->state).domain = VTS_DOMAIN; | |
1327 if(vtsN != (self->state).vtsN) | |
1328 ifoOpenNewVTSI(self, self->dvd, vtsN); /* Also sets (self->state).vtsN */ | |
1329 | |
1330 assert(vts_ttn <= self->vtsi->vts_ptt_srpt->nr_of_srpts); | |
1331 assert(part <= self->vtsi->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts); | |
1332 | |
1333 pgcN = self->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgcn; | |
1334 pgN = self->vtsi->vts_ptt_srpt->title[vts_ttn - 1].ptt[part - 1].pgn; | |
1335 | |
1336 /* (self->state).TTN_REG = ?? Must search tt_srpt for a matchhing entry... */ | |
1337 (self->state).VTS_TTN_REG = vts_ttn; | |
1338 /* Any other registers? */ | |
1339 | |
1340 (self->state).pgN = pgN; /* ?? */ | |
1341 | |
1342 return get_PGC(self, pgcN); | |
1343 } | |
1344 | |
1345 | |
1346 | |
1347 static int get_FP_PGC(vm_t *self) | |
1348 { | |
1349 (self->state).domain = FP_DOMAIN; | |
1350 | |
1351 (self->state).pgc = self->vmgi->first_play_pgc; | |
1352 | |
1353 return 0; | |
1354 } | |
1355 | |
1356 | |
1357 static int get_MENU(vm_t *self, int menu) | |
1358 { | |
1359 assert((self->state).domain == VMGM_DOMAIN || (self->state).domain == VTSM_DOMAIN); | |
1360 return get_PGC(self, get_ID(self, menu)); | |
1361 } | |
1362 | |
1363 static int get_ID(vm_t *self, int id) | |
1364 { | |
1365 int pgcN, i; | |
1366 pgcit_t *pgcit; | |
1367 | |
1368 /* Relies on state to get the correct pgcit. */ | |
1369 pgcit = get_PGCIT(self); | |
1370 assert(pgcit != NULL); | |
1371 | |
1372 /* Get menu/title */ | |
1373 for(i = 0; i < pgcit->nr_of_pgci_srp; i++) { | |
1374 if((pgcit->pgci_srp[i].entry_id & 0x7f) == id) { | |
1375 assert((pgcit->pgci_srp[i].entry_id & 0x80) == 0x80); | |
1376 pgcN = i + 1; | |
1377 return pgcN; | |
1378 } | |
1379 } | |
1380 fprintf(stderr, "** No such id/menu (%d) entry PGC\n", id); | |
1381 return -1; /* error */ | |
1382 } | |
1383 | |
1384 | |
1385 | |
1386 static int get_PGC(vm_t *self, int pgcN) | |
1387 { | |
1388 /* FIXME: Keep this up to date with the ogle people */ | |
1389 pgcit_t *pgcit; | |
1390 | |
1391 pgcit = get_PGCIT(self); | |
1392 | |
1393 assert(pgcit != NULL); /* ?? Make this return -1 instead */ | |
1394 if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) { | |
1395 /* if(pgcit->nr_of_pgci_srp != 1) */ | |
1396 return -1; /* error */ | |
1397 /* pgcN = 1; */ | |
1398 } | |
1399 | |
1400 /* (self->state).pgcN = pgcN; */ | |
1401 (self->state).pgc = pgcit->pgci_srp[pgcN - 1].pgc; | |
1402 | |
1403 if((self->state).domain == VTS_DOMAIN) | |
1404 (self->state).TT_PGCN_REG = pgcN; | |
1405 | |
1406 return 0; | |
1407 } | |
1408 | |
1409 static int get_PGCN(vm_t *self) | |
1410 { | |
1411 pgcit_t *pgcit; | |
1412 int pgcN = 1; | |
1413 | |
1414 pgcit = get_PGCIT(self); | |
1415 | |
1416 assert(pgcit != NULL); | |
1417 | |
1418 while(pgcN <= pgcit->nr_of_pgci_srp) { | |
1419 if(pgcit->pgci_srp[pgcN - 1].pgc == (self->state).pgc) | |
1420 return pgcN; | |
1421 pgcN++; | |
1422 } | |
1423 | |
1424 return -1; /* error */ | |
1425 } | |
1426 | |
1427 | |
1428 static int get_video_aspect(vm_t *self) | |
1429 { | |
1430 int aspect = 0; | |
1431 | |
1432 if((self->state).domain == VTS_DOMAIN) { | |
1433 aspect = self->vtsi->vtsi_mat->vts_video_attr.display_aspect_ratio; | |
1434 } else if((self->state).domain == VTSM_DOMAIN) { | |
1435 aspect = self->vtsi->vtsi_mat->vtsm_video_attr.display_aspect_ratio; | |
1436 } else if((self->state).domain == VMGM_DOMAIN) { | |
1437 aspect = self->vmgi->vmgi_mat->vmgm_video_attr.display_aspect_ratio; | |
1438 } | |
1439 fprintf(stderr, "dvdnav:get_video_aspect:aspect=%d\n",aspect); | |
1440 assert(aspect == 0 || aspect == 3); | |
1441 (self->state).registers.SPRM[14] &= ~(0x3 << 10); | |
1442 (self->state).registers.SPRM[14] |= aspect << 10; | |
1443 | |
1444 return aspect; | |
1445 } | |
1446 | |
1447 | |
1448 | |
1449 | |
1450 | |
1451 | |
1452 static void ifoOpenNewVTSI(vm_t *self, dvd_reader_t *dvd, int vtsN) | |
1453 { | |
1454 if((self->state).vtsN == vtsN) { | |
1455 return; /* We alread have it */ | |
1456 } | |
1457 | |
1458 if(self->vtsi != NULL) | |
1459 ifoClose(self->vtsi); | |
1460 | |
1461 self->vtsi = ifoOpenVTSI(dvd, vtsN); | |
1462 if(self->vtsi == NULL) { | |
1463 fprintf(stderr, "ifoOpenVTSI failed\n"); | |
1464 exit(1); | |
1465 } | |
1466 if(!ifoRead_VTS_PTT_SRPT(self->vtsi)) { | |
1467 fprintf(stderr, "ifoRead_VTS_PTT_SRPT failed\n"); | |
1468 exit(1); | |
1469 } | |
1470 if(!ifoRead_PGCIT(self->vtsi)) { | |
1471 fprintf(stderr, "ifoRead_PGCIT failed\n"); | |
1472 exit(1); | |
1473 } | |
1474 if(!ifoRead_PGCI_UT(self->vtsi)) { | |
1475 fprintf(stderr, "ifoRead_PGCI_UT failed\n"); | |
1476 exit(1); | |
1477 } | |
1478 if(!ifoRead_VOBU_ADMAP(self->vtsi)) { | |
1479 fprintf(stderr, "ifoRead_VOBU_ADMAP vtsi failed\n"); | |
1480 exit(1); | |
1481 } | |
1482 if(!ifoRead_TITLE_VOBU_ADMAP(self->vtsi)) { | |
1483 fprintf(stderr, "ifoRead_TITLE_VOBU_ADMAP vtsi failed\n"); | |
1484 exit(1); | |
1485 } | |
1486 (self->state).vtsN = vtsN; | |
1487 } | |
1488 | |
1489 | |
1490 | |
1491 | |
1492 static pgcit_t* get_MENU_PGCIT(vm_t *self, ifo_handle_t *h, uint16_t lang) | |
1493 { | |
1494 int i; | |
1495 | |
1496 if(h == NULL || h->pgci_ut == NULL) { | |
1497 fprintf(stderr, "*** pgci_ut handle is NULL ***\n"); | |
1498 return NULL; /* error? */ | |
1499 } | |
1500 | |
1501 i = 0; | |
1502 while(i < h->pgci_ut->nr_of_lus | |
1503 && h->pgci_ut->lu[i].lang_code != lang) | |
1504 i++; | |
1505 if(i == h->pgci_ut->nr_of_lus) { | |
1506 fprintf(stderr, "Language '%c%c' not found, using '%c%c' instead\n", | |
1507 (char)(lang >> 8), (char)(lang & 0xff), | |
1508 (char)(h->pgci_ut->lu[0].lang_code >> 8), | |
1509 (char)(h->pgci_ut->lu[0].lang_code & 0xff)); | |
1510 i = 0; /* error? */ | |
1511 } | |
1512 | |
1513 return h->pgci_ut->lu[i].pgcit; | |
1514 } | |
1515 | |
1516 /* Uses state to decide what to return */ | |
1517 static pgcit_t* get_PGCIT(vm_t *self) { | |
1518 pgcit_t *pgcit; | |
1519 | |
1520 if((self->state).domain == VTS_DOMAIN) { | |
1521 pgcit = self->vtsi->vts_pgcit; | |
1522 } else if((self->state).domain == VTSM_DOMAIN) { | |
1523 pgcit = get_MENU_PGCIT(self, self->vtsi, (self->state).registers.SPRM[0]); | |
1524 } else if((self->state).domain == VMGM_DOMAIN) { | |
1525 pgcit = get_MENU_PGCIT(self, self->vmgi, (self->state).registers.SPRM[0]); | |
1526 } else { | |
1527 pgcit = NULL; /* Should never hapen */ | |
1528 } | |
1529 | |
1530 return pgcit; | |
1531 } | |
1532 | |
1533 /* | |
1534 * $Log$ | |
4
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
1535 * Revision 1.3 2002/04/02 18:22:27 richwareham |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
1536 * Added reset patch from Kees Cook <kees@outflux.net> |
99bed5d6db2f
Added reset patch from Kees Cook <kees@outflux.net>
richwareham
parents:
3
diff
changeset
|
1537 * |
3
328eadb3f37e
Added initial example programs directory and make sure all debug/error output goes to stderr.
richwareham
parents:
0
diff
changeset
|
1538 * Revision 1.2 2002/04/01 18:56:28 richwareham |
328eadb3f37e
Added initial example programs directory and make sure all debug/error output goes to stderr.
richwareham
parents:
0
diff
changeset
|
1539 * Added initial example programs directory and make sure all debug/error output goes to stderr. |
328eadb3f37e
Added initial example programs directory and make sure all debug/error output goes to stderr.
richwareham
parents:
0
diff
changeset
|
1540 * |
328eadb3f37e
Added initial example programs directory and make sure all debug/error output goes to stderr.
richwareham
parents:
0
diff
changeset
|
1541 * Revision 1.1.1.1 2002/03/12 19:45:55 richwareham |
328eadb3f37e
Added initial example programs directory and make sure all debug/error output goes to stderr.
richwareham
parents:
0
diff
changeset
|
1542 * Initial import |
0 | 1543 * |
1544 * Revision 1.18 2002/01/22 16:56:49 jcdutton | |
1545 * Fix clut after seeking. | |
1546 * Add a few virtual machine debug messages, to help diagnose problems with "Deep Purple - Total Abandon" DVD as I don't have the DVD itself. | |
1547 * Fix a few debug messages, so they do not say FIXME. | |
1548 * Move the FIXME debug messages to comments in the code. | |
1549 * | |
1550 * Revision 1.17 2002/01/21 01:16:30 jcdutton | |
1551 * Added some debug messages, to hopefully get info from users. | |
1552 * | |
1553 * Revision 1.16 2002/01/20 21:40:46 jcdutton | |
1554 * Start to fix some assert failures. | |
1555 * | |
1556 * Revision 1.15 2002/01/19 20:24:38 jcdutton | |
1557 * Just some FIXME notes added. | |
1558 * | |
1559 * Revision 1.14 2002/01/13 22:17:57 jcdutton | |
1560 * Change logging. | |
1561 * | |
1562 * | |
1563 */ |