1 /*
2 * Copyright (C) 2000, 2001 Håkan Hjort
3 * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
4 * 2002-2004 the dvdnav project
5 *
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.
8 *
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.
13 *
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.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with libdvdnav; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <assert.h>
29 #include <inttypes.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include <dvdread/nav_types.h>
35 #include <dvdread/ifo_types.h>
36 #include <dvdread/ifo_read.h>
37 #include "dvdnav/dvdnav.h"
38
39 #include "decoder.h"
40 #include "vm.h"
41 #include "getset.h"
42 #include "dvdnav_internal.h"
43 #include "logger.h"
44
45 /* getting information */
46
vm_get_current_menu(vm_t * vm,int * menuid)47 int vm_get_current_menu(vm_t *vm, int *menuid) {
48 pgcit_t* pgcit;
49 int pgcn;
50 pgcn = (vm->state).pgcN;
51 pgcit = get_PGCIT(vm);
52 if(pgcit==NULL) return 0;
53 *menuid = pgcit->pgci_srp[pgcn - 1].entry_id & 0xf ;
54 return 1;
55 }
56
vm_get_current_title_part(vm_t * vm,int * title_result,int * part_result)57 int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) {
58 vts_ptt_srpt_t *vts_ptt_srpt;
59 int title, part = 0, vts_ttn;
60 int found;
61 int16_t pgcN, pgN;
62
63 vts_ptt_srpt = vm->vtsi->vts_ptt_srpt;
64 pgcN = get_PGCN(vm);
65 pgN = vm->state.pgN;
66
67 found = 0;
68 for (vts_ttn = 0; (vts_ttn < vts_ptt_srpt->nr_of_srpts) && !found; vts_ttn++) {
69 for (part = 0; (part < vts_ptt_srpt->title[vts_ttn].nr_of_ptts) && !found; part++) {
70 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgcn == pgcN) {
71 if (vts_ptt_srpt->title[vts_ttn].ptt[part].pgn == pgN) {
72 found = 1;
73 break;
74 }
75 if (part > 0 && vts_ptt_srpt->title[vts_ttn].ptt[part].pgn > pgN &&
76 vts_ptt_srpt->title[vts_ttn].ptt[part - 1].pgn < pgN) {
77 part--;
78 found = 1;
79 break;
80 }
81 }
82 }
83 if (found) break;
84 }
85 vts_ttn++;
86 part++;
87
88 if (!found) {
89 Log1(vm, "chapter NOT FOUND!");
90 return 0;
91 }
92
93 title = get_TT(vm, vm->state.vtsN, vts_ttn);
94
95 #ifdef TRACE
96 if (title) {
97 Log3(vm, "************ this chapter FOUND!");
98 Log3(vm, "VTS_PTT_SRPT - Title %3i part %3i: PGC: %3i PG: %3i",
99 title, part,
100 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgcn ,
101 vts_ptt_srpt->title[vts_ttn-1].ptt[part-1].pgn );
102 }
103 #endif
104 *title_result = title;
105 *part_result = part;
106 return 1;
107 }
108
109 /* Return the substream id for 'logical' audio stream audioN.
110 * 0 <= audioN < 8
111 */
vm_get_audio_stream(vm_t * vm,int audioN)112 int vm_get_audio_stream(vm_t *vm, int audioN) {
113 int streamN = -1;
114
115 if((vm->state).domain != DVD_DOMAIN_VTSTitle)
116 audioN = 0;
117
118 if(audioN < 8) {
119 /* Is there any control info for this logical stream */
120 if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
121 streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07;
122 }
123 }
124
125 if((vm->state).domain != DVD_DOMAIN_VTSTitle && streamN == -1)
126 streamN = 0;
127
128 /* FIXME: Should also check in vtsi/vmgi status what kind of stream
129 * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */
130 return streamN;
131 }
132
133 /* Return the substream id for 'logical' subpicture stream subpN and given mode.
134 * 0 <= subpN < 32
135 * mode == 0 - widescreen
136 * mode == 1 - letterbox
137 * mode == 2 - pan&scan
138 */
vm_get_subp_stream(vm_t * vm,int subpN,int mode)139 int vm_get_subp_stream(vm_t *vm, int subpN, int mode) {
140 int streamN = -1;
141 int source_aspect = vm_get_video_aspect(vm);
142
143 if((vm->state).domain != DVD_DOMAIN_VTSTitle)
144 subpN = 0;
145
146 if(subpN < 32) { /* a valid logical stream */
147 /* Is this logical stream present */
148 if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
149 if(source_aspect == 0) /* 4:3 */
150 streamN = ((vm->state).pgc->subp_control[subpN] >> 24) & 0x1f;
151 if(source_aspect == 3) /* 16:9 */
152 switch (mode) {
153 case 0:
154 streamN = ((vm->state).pgc->subp_control[subpN] >> 16) & 0x1f;
155 break;
156 case 1:
157 streamN = ((vm->state).pgc->subp_control[subpN] >> 8) & 0x1f;
158 break;
159 case 2:
160 streamN = (vm->state).pgc->subp_control[subpN] & 0x1f;
161 }
162 }
163 }
164
165 if((vm->state).domain != DVD_DOMAIN_VTSTitle && streamN == -1)
166 streamN = 0;
167
168 /* FIXME: Should also check in vtsi/vmgi status what kind of stream it is. */
169 return streamN;
170 }
171
vm_get_audio_active_stream(vm_t * vm)172 int vm_get_audio_active_stream(vm_t *vm) {
173 int audioN;
174 int streamN;
175 audioN = (vm->state).AST_REG ;
176 streamN = vm_get_audio_stream(vm, audioN);
177
178 /* If no such stream, then select the first one that exists. */
179 if(streamN == -1) {
180 for(audioN = 0; audioN < 8; audioN++) {
181 if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
182 if ((streamN = vm_get_audio_stream(vm, audioN)) >= 0)
183 break;
184 }
185 }
186 }
187
188 return streamN;
189 }
190
vm_get_subp_active_stream(vm_t * vm,int mode)191 int vm_get_subp_active_stream(vm_t *vm, int mode) {
192 int subpN;
193 int streamN;
194 subpN = (vm->state).SPST_REG & ~0x40;
195 streamN = vm_get_subp_stream(vm, subpN, mode);
196
197 /* If no such stream, then select the first one that exists. */
198 if(streamN == -1) {
199 for(subpN = 0; subpN < 32; subpN++) {
200 if((vm->state).pgc->subp_control[subpN] & (1<<31)) {
201 if ((streamN = vm_get_subp_stream(vm, subpN, mode)) >= 0)
202 break;
203 }
204 }
205 }
206
207 if((vm->state).domain == DVD_DOMAIN_VTSTitle && !((vm->state).SPST_REG & 0x40))
208 /* Bit 7 set means hide, and only let Forced display show */
209 return (streamN | 0x80);
210 else
211 return streamN;
212 }
213
vm_get_angle_info(vm_t * vm,int * current,int * num_avail)214 void vm_get_angle_info(vm_t *vm, int *current, int *num_avail) {
215 *num_avail = 1;
216 *current = 1;
217
218 if((vm->state).domain == DVD_DOMAIN_VTSTitle) {
219 title_info_t *title;
220 /* TTN_REG does not allways point to the correct title.. */
221 if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
222 return;
223 title = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1];
224 if(title->title_set_nr != (vm->state).vtsN ||
225 title->vts_ttn != (vm->state).VTS_TTN_REG)
226 return;
227 *num_avail = title->nr_of_angles;
228 *current = (vm->state).AGL_REG;
229 }
230 }
231
232 #if 0
233 /* currently unused */
234 void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) {
235 switch ((vm->state).domain) {
236 case DVD_DOMAIN_VTSTitle:
237 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_audio_streams;
238 *current = (vm->state).AST_REG;
239 break;
240 case DVD_DOMAIN_VTSMenu:
241 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; /* 1 */
242 *current = 1;
243 break;
244 case DVD_DOMAIN_VMGM:
245 case DVD_DOMAIN_FirstPlay:
246 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; /* 1 */
247 *current = 1;
248 break;
249 }
250 }
251
252 /* currently unused */
253 void vm_get_subp_info(vm_t *vm, int *current, int *num_avail) {
254 switch ((vm->state).domain) {
255 case DVD_DOMAIN_VTSTitle:
256 *num_avail = vm->vtsi->vtsi_mat->nr_of_vts_subp_streams;
257 *current = (vm->state).SPST_REG;
258 break;
259 case DVD_DOMAIN_VTSMenu:
260 *num_avail = vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; /* 1 */
261 *current = 0x41;
262 break;
263 case DVD_DOMAIN_VMGM:
264 case DVD_DOMAIN_FirstPlay:
265 *num_avail = vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; /* 1 */
266 *current = 0x41;
267 break;
268 }
269 }
270 #endif
271
vm_get_video_res(vm_t * vm,int * width,int * height)272 void vm_get_video_res(vm_t *vm, int *width, int *height) {
273 video_attr_t attr = vm_get_video_attr(vm);
274
275 if(attr.video_format != 0)
276 *height = 576;
277 else
278 *height = 480;
279 switch(attr.picture_size) {
280 case 0:
281 *width = 720;
282 break;
283 case 1:
284 *width = 704;
285 break;
286 case 2:
287 *width = 352;
288 break;
289 case 3:
290 *width = 352;
291 *height /= 2;
292 break;
293 }
294 }
295
vm_get_video_aspect(vm_t * vm)296 int vm_get_video_aspect(vm_t *vm) {
297 int aspect = vm_get_video_attr(vm).display_aspect_ratio;
298
299 if(aspect != 0 && aspect != 3) {
300 Log1(vm, "display aspect ratio is unexpected: %d!", aspect);
301 return -1;
302 }
303
304 (vm->state).registers.SPRM[14] &= ~(0x3 << 10);
305 (vm->state).registers.SPRM[14] |= aspect << 10;
306
307 return aspect;
308 }
309
vm_get_video_scale_permission(vm_t * vm)310 int vm_get_video_scale_permission(vm_t *vm) {
311 return vm_get_video_attr(vm).permitted_df;
312 }
313
vm_get_video_attr(vm_t * vm)314 video_attr_t vm_get_video_attr(vm_t *vm) {
315 switch ((vm->state).domain) {
316 case DVD_DOMAIN_VTSTitle:
317 return vm->vtsi->vtsi_mat->vts_video_attr;
318 case DVD_DOMAIN_VTSMenu:
319 return vm->vtsi->vtsi_mat->vtsm_video_attr;
320 case DVD_DOMAIN_VMGM:
321 case DVD_DOMAIN_FirstPlay:
322 return vm->vmgi->vmgi_mat->vmgm_video_attr;
323 default:
324 assert(0);
325 }
326 }
327
vm_get_audio_attr(vm_t * vm,int streamN)328 audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN) {
329 switch ((vm->state).domain) {
330 case DVD_DOMAIN_VTSTitle:
331 return vm->vtsi->vtsi_mat->vts_audio_attr[streamN];
332 case DVD_DOMAIN_VTSMenu:
333 return vm->vtsi->vtsi_mat->vtsm_audio_attr;
334 case DVD_DOMAIN_VMGM:
335 case DVD_DOMAIN_FirstPlay:
336 return vm->vmgi->vmgi_mat->vmgm_audio_attr;
337 default:
338 assert(0);
339 }
340 }
341
vm_get_subp_attr(vm_t * vm,int streamN)342 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN) {
343 switch ((vm->state).domain) {
344 case DVD_DOMAIN_VTSTitle:
345 return vm->vtsi->vtsi_mat->vts_subp_attr[streamN];
346 case DVD_DOMAIN_VTSMenu:
347 return vm->vtsi->vtsi_mat->vtsm_subp_attr;
348 case DVD_DOMAIN_VMGM:
349 case DVD_DOMAIN_FirstPlay:
350 return vm->vmgi->vmgi_mat->vmgm_subp_attr;
351 default:
352 assert(0);
353 }
354 }
355