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