Fix vf_tcdump's compilation
[mplayer/kovensky.git] / libdvdnav / highlight.c
blob8fe7a0b2a6c57f3607a0f6b7519b9d0c80f589aa
1 /*
2 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
4 * This file is part of libdvdnav, a DVD navigation library.
6 * libdvdnav is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * libdvdnav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with libdvdnav; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
25 #include <assert.h>
26 #include <inttypes.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <limits.h>
30 #include <string.h>
31 #include <sys/time.h>
32 #include <dvdread/nav_types.h>
33 #include "dvdnav/dvdnav.h"
34 #include "remap.h"
35 #include "vm/decoder.h"
36 #include "vm/vm.h"
37 #include "vm/vmcmd.h"
38 #include "dvdnav_internal.h"
41 #define BUTTON_TESTING
44 #ifdef BUTTON_TESTING
46 #include "nav_print.h"
48 static void print_time(dvd_time_t *dtime) {
49 const char *rate;
51 assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa);
52 assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa);
53 assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa);
54 assert((dtime->frame_u&0xf) < 0xa);
56 fprintf(MSG_OUT,"%02x:%02x:%02x.%02x",
57 dtime->hour,
58 dtime->minute,
59 dtime->second,
60 dtime->frame_u & 0x3f);
61 switch((dtime->frame_u & 0xc0) >> 6) {
62 case 1:
63 rate = "25.00";
64 break;
65 case 3:
66 rate = "29.97";
67 break;
68 default:
69 rate = "(please send a bug report)";
70 break;
72 fprintf(MSG_OUT," @ %s fps", rate);
75 static void nav_print_PCI_GI(pci_gi_t *pci_gi) {
76 int32_t i;
78 fprintf(MSG_OUT,"libdvdnav: pci_gi:\n");
79 fprintf(MSG_OUT,"libdvdnav: nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn);
80 fprintf(MSG_OUT,"libdvdnav: vobu_cat 0x%04x\n", pci_gi->vobu_cat);
81 fprintf(MSG_OUT,"libdvdnav: vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl);
82 fprintf(MSG_OUT,"libdvdnav: vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm);
83 fprintf(MSG_OUT,"libdvdnav: vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm);
84 fprintf(MSG_OUT,"libdvdnav: vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm);
85 fprintf(MSG_OUT,"libdvdnav: e_eltm ");
86 print_time(&pci_gi->e_eltm);
87 fprintf(MSG_OUT,"\n");
89 fprintf(MSG_OUT,"libdvdnav: vobu_isrc \"");
90 for(i = 0; i < 32; i++) {
91 char c = pci_gi->vobu_isrc[i];
92 if((c >= ' ') && (c <= '~'))
93 fprintf(MSG_OUT,"%c", c);
94 else
95 fprintf(MSG_OUT,".");
97 fprintf(MSG_OUT,"\"\n");
100 static void nav_print_NSML_AGLI(nsml_agli_t *nsml_agli) {
101 int32_t i, j = 0;
103 for(i = 0; i < 9; i++)
104 j |= nsml_agli->nsml_agl_dsta[i];
105 if(j == 0)
106 return;
108 fprintf(MSG_OUT,"libdvdnav: nsml_agli:\n");
109 for(i = 0; i < 9; i++)
110 if(nsml_agli->nsml_agl_dsta[i])
111 fprintf(MSG_OUT,"libdvdnav: nsml_agl_c%d_dsta 0x%08x\n", i + 1,
112 nsml_agli->nsml_agl_dsta[i]);
115 static void nav_print_HL_GI(hl_gi_t *hl_gi, int32_t *btngr_ns, int32_t *btn_ns) {
117 if((hl_gi->hli_ss & 0x03) == 0)
118 return;
120 fprintf(MSG_OUT,"libdvdnav: hl_gi:\n");
121 fprintf(MSG_OUT,"libdvdnav: hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03);
122 fprintf(MSG_OUT,"libdvdnav: hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm);
123 fprintf(MSG_OUT,"libdvdnav: hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm);
124 fprintf(MSG_OUT,"libdvdnav: btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm);
126 *btngr_ns = hl_gi->btngr_ns;
127 fprintf(MSG_OUT,"libdvdnav: btngr_ns %d\n", hl_gi->btngr_ns);
128 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty);
129 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty);
130 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty);
132 fprintf(MSG_OUT,"libdvdnav: btn_ofn %d\n", hl_gi->btn_ofn);
133 *btn_ns = hl_gi->btn_ns;
134 fprintf(MSG_OUT,"libdvdnav: btn_ns %d\n", hl_gi->btn_ns);
135 fprintf(MSG_OUT,"libdvdnav: nsl_btn_ns %d\n", hl_gi->nsl_btn_ns);
136 fprintf(MSG_OUT,"libdvdnav: fosl_btnn %d\n", hl_gi->fosl_btnn);
137 fprintf(MSG_OUT,"libdvdnav: foac_btnn %d\n", hl_gi->foac_btnn);
140 static void nav_print_BTN_COLIT(btn_colit_t *btn_colit) {
141 int32_t i, j;
143 j = 0;
144 for(i = 0; i < 6; i++)
145 j |= btn_colit->btn_coli[i/2][i&1];
146 if(j == 0)
147 return;
149 fprintf(MSG_OUT,"libdvdnav: btn_colit:\n");
150 for(i = 0; i < 3; i++)
151 for(j = 0; j < 2; j++)
152 fprintf(MSG_OUT,"libdvdnav: btn_cqoli %d %s_coli: %08x\n",
153 i, (j == 0) ? "sl" : "ac",
154 btn_colit->btn_coli[i][j]);
157 static void nav_print_BTNIT(btni_t *btni_table, int32_t btngr_ns, int32_t btn_ns) {
158 int32_t i, j, k;
160 fprintf(MSG_OUT,"libdvdnav: btnit:\n");
161 fprintf(MSG_OUT,"libdvdnav: btngr_ns: %i\n", btngr_ns);
162 fprintf(MSG_OUT,"libdvdnav: btn_ns: %i\n", btn_ns);
164 if(btngr_ns == 0)
165 return;
167 for(i = 0; i < btngr_ns; i++) {
168 for(j = 0; j < (36 / btngr_ns); j++) {
169 if(j < btn_ns) {
170 btni_t *btni = &btni_table[(36 / btngr_ns) * i + j];
172 fprintf(MSG_OUT,"libdvdnav: group %d btni %d: ", i+1, j+1);
173 fprintf(MSG_OUT,"btn_coln %d, auto_action_mode %d\n",
174 btni->btn_coln, btni->auto_action_mode);
175 fprintf(MSG_OUT,"libdvdnav: coords (%d, %d) .. (%d, %d)\n",
176 btni->x_start, btni->y_start, btni->x_end, btni->y_end);
178 fprintf(MSG_OUT,"libdvdnav: up %d, ", btni->up);
179 fprintf(MSG_OUT,"down %d, ", btni->down);
180 fprintf(MSG_OUT,"left %d, ", btni->left);
181 fprintf(MSG_OUT,"right %d\n", btni->right);
182 for(k = 0; k < 8; k++) {
183 fprintf(MSG_OUT, "libdvdnav: %02x ", btni->cmd.bytes[k]);
185 fprintf(MSG_OUT, "| ");
186 #ifdef TRACE
187 vm_print_mnemonic(&btni->cmd);
188 #endif
189 fprintf(MSG_OUT, "\n");
195 static void nav_print_HLI(hli_t *hli) {
196 int32_t btngr_ns = 0, btn_ns = 0;
198 fprintf(MSG_OUT,"libdvdnav: hli:\n");
199 nav_print_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns);
200 nav_print_BTN_COLIT(&hli->btn_colit);
201 nav_print_BTNIT(hli->btnit, btngr_ns, btn_ns);
204 void nav_print_PCI(pci_t *pci) {
205 fprintf(MSG_OUT,"libdvdnav: pci packet:\n");
206 nav_print_PCI_GI(&pci->pci_gi);
207 nav_print_NSML_AGLI(&pci->nsml_agli);
208 nav_print_HLI(&pci->hli);
211 #endif
214 /* Highlighting API calls */
216 dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) {
217 /* Simply return the appropriate value based on the SPRM */
218 if(((*button) = this->position_current.button) == -1)
219 (*button) = this->vm->state.HL_BTNN_REG >> 10;
221 return DVDNAV_STATUS_OK;
224 static btni_t *get_current_button(dvdnav_t *this, pci_t *pci) {
225 int32_t button = 0;
227 if(!pci->hli.hl_gi.hli_ss) {
228 printerr("Not in a menu.");
229 return NULL;
231 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
232 printerr("This NAV has already been left.");
233 return NULL;
236 button = this->vm->state.HL_BTNN_REG >> 10;
237 #ifdef BUTTON_TESTING
238 nav_print_PCI(pci);
239 #endif
241 return &(pci->hli.btnit[button-1]);
244 static dvdnav_status_t button_auto_action(dvdnav_t *this, pci_t *pci) {
245 if (get_current_button(this, pci)->auto_action_mode)
246 return dvdnav_button_activate(this, pci);
247 return DVDNAV_STATUS_OK;
250 dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *this, pci_t *pci) {
251 btni_t *button_ptr;
253 if(!(button_ptr = get_current_button(this, pci)))
254 return DVDNAV_STATUS_ERR;
256 dvdnav_button_select(this, pci, button_ptr->up);
257 return button_auto_action(this, pci);
260 dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *this, pci_t *pci) {
261 btni_t *button_ptr;
263 if(!(button_ptr = get_current_button(this, pci)))
264 return DVDNAV_STATUS_ERR;
266 dvdnav_button_select(this, pci, button_ptr->down);
267 return button_auto_action(this, pci);
270 dvdnav_status_t dvdnav_right_button_select(dvdnav_t *this, pci_t *pci) {
271 btni_t *button_ptr;
273 if(!(button_ptr = get_current_button(this, pci)))
274 return DVDNAV_STATUS_ERR;
276 dvdnav_button_select(this, pci, button_ptr->right);
277 return button_auto_action(this, pci);
280 dvdnav_status_t dvdnav_left_button_select(dvdnav_t *this, pci_t *pci) {
281 btni_t *button_ptr;
283 if(!(button_ptr = get_current_button(this, pci)))
284 return DVDNAV_STATUS_ERR;
286 dvdnav_button_select(this, pci, button_ptr->left);
287 return button_auto_action(this, pci);
290 dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode,
291 dvdnav_highlight_area_t *highlight) {
292 btni_t *button_ptr;
294 #ifdef BUTTON_TESTING
295 fprintf(MSG_OUT, "libdvdnav: Button get_highlight_area %i\n", button);
296 #endif
298 if(!nav_pci->hli.hl_gi.hli_ss)
299 return DVDNAV_STATUS_ERR;
300 if((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns))
301 return DVDNAV_STATUS_ERR;
304 button_ptr = &nav_pci->hli.btnit[button-1];
306 highlight->sx = button_ptr->x_start;
307 highlight->sy = button_ptr->y_start;
308 highlight->ex = button_ptr->x_end;
309 highlight->ey = button_ptr->y_end;
310 if(button_ptr->btn_coln != 0) {
311 highlight->palette = nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode];
312 } else {
313 highlight->palette = 0;
315 highlight->pts = nav_pci->hli.hl_gi.hli_s_ptm;
316 highlight->buttonN = button;
317 #ifdef BUTTON_TESTING
318 fprintf(MSG_OUT, "libdvdnav: highlight: Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n",
319 button_ptr->x_start, button_ptr->y_start,
320 button_ptr->x_end, button_ptr->y_end,
322 button);
323 #endif
325 return DVDNAV_STATUS_OK;
328 dvdnav_status_t dvdnav_button_activate(dvdnav_t *this, pci_t *pci) {
329 int32_t button;
330 btni_t *button_ptr = NULL;
332 if(!pci->hli.hl_gi.hli_ss) {
333 printerr("Not in a menu.");
334 return DVDNAV_STATUS_ERR;
336 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
337 printerr("This NAV has already been left.");
338 return DVDNAV_STATUS_ERR;
340 pthread_mutex_lock(&this->vm_lock);
342 button = this->vm->state.HL_BTNN_REG >> 10;
344 if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
345 /* Special code to handle still menus with no buttons.
346 * The navigation is expected to report to the application that a STILL is
347 * underway. In turn, the application is supposed to report to the user
348 * that the playback is paused. The user is then expected to undo the pause,
349 * ie: hit play. At that point, the navigation should release the still and
350 * go to the next Cell.
351 * Explanation by Mathieu Lacage <mathieu_lacage@realmagic.fr>
352 * Code added by jcdutton.
354 if (this->position_current.still != 0) {
355 /* In still, but no buttons. */
356 vm_get_next_cell(this->vm);
357 this->position_current.still = 0;
358 this->sync_wait = 0;
359 this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
360 pthread_mutex_unlock(&this->vm_lock);
361 /* clear error message */
362 printerr("");
363 return DVDNAV_STATUS_OK;
365 pthread_mutex_unlock(&this->vm_lock);
366 return DVDNAV_STATUS_ERR;
369 button_ptr = get_current_button(this, pci);
370 /* Finally, make the VM execute the appropriate code and probably
371 * scedule a jump */
372 #ifdef BUTTON_TESTING
373 fprintf(MSG_OUT, "libdvdnav: Evaluating Button Activation commands.\n");
374 #endif
375 if(vm_exec_cmd(this->vm, &(button_ptr->cmd)) == 1) {
376 /* Command caused a jump */
377 this->vm->hop_channel++;
378 this->position_current.still = 0;
379 this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
382 pthread_mutex_unlock(&this->vm_lock);
383 return DVDNAV_STATUS_OK;
386 dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *this, int32_t button, vm_cmd_t *cmd)
388 pthread_mutex_lock(&this->vm_lock);
389 /* make the VM execute the appropriate code and probably
390 * schedule a jump */
391 #ifdef BUTTON_TESTING
392 fprintf(MSG_OUT, "libdvdnav: dvdnav_button_activate_cmd: Evaluating Button Activation commands.\n");
393 #endif
394 if(button > 0) {
395 this->vm->state.HL_BTNN_REG = (button << 10);
396 if(vm_exec_cmd(this->vm, cmd) == 1) {
397 /* Command caused a jump */
398 this->vm->hop_channel++;
401 /* Always remove still, because some still menus have no buttons. */
402 this->position_current.still = 0;
403 this->sync_wait = 0;
404 pthread_mutex_unlock(&this->vm_lock);
405 return DVDNAV_STATUS_OK;
408 dvdnav_status_t dvdnav_button_select(dvdnav_t *this, pci_t *pci, int32_t button) {
409 if(!pci->hli.hl_gi.hli_ss) {
410 printerr("Not in a menu.");
411 return DVDNAV_STATUS_ERR;
413 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
414 printerr("This NAV has already been left.");
415 return DVDNAV_STATUS_ERR;
418 #ifdef BUTTON_TESTING
419 fprintf(MSG_OUT, "libdvdnav: Button select %i\n", button);
420 #endif
422 if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
423 printerr("Button does not exist.");
424 return DVDNAV_STATUS_ERR;
427 this->vm->state.HL_BTNN_REG = (button << 10);
428 this->position_current.button = -1; /* Force Highligh change */
430 return DVDNAV_STATUS_OK;
433 dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *this, pci_t *pci,
434 int32_t button) {
435 /* A trivial function */
436 if(dvdnav_button_select(this, pci, button) != DVDNAV_STATUS_ERR)
437 return dvdnav_button_activate(this, pci);
438 return DVDNAV_STATUS_ERR;
441 dvdnav_status_t dvdnav_mouse_select(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
442 int32_t button, cur_button;
443 int32_t best,dist,d;
444 int32_t mx,my,dx,dy;
446 if(!pci->hli.hl_gi.hli_ss) {
447 printerr("Not in a menu.");
448 return DVDNAV_STATUS_ERR;
450 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
451 printerr("This NAV has already been left.");
452 return DVDNAV_STATUS_ERR;
455 cur_button = this->vm->state.HL_BTNN_REG >> 10;
457 best = 0;
458 dist = 0x08000000; /* >> than (720*720)+(567*567); */
460 /* Loop through all buttons */
461 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) {
462 btni_t *button_ptr = &(pci->hli.btnit[button-1]);
464 if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) &&
465 (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) {
466 mx = (button_ptr->x_start + button_ptr->x_end)/2;
467 my = (button_ptr->y_start + button_ptr->y_end)/2;
468 dx = mx - x;
469 dy = my - y;
470 d = (dx*dx) + (dy*dy);
471 /* If the mouse is within the button and the mouse is closer
472 * to the center of this button then it is the best choice. */
473 if(d < dist) {
474 dist = d;
475 best = button;
479 /* As an efficiency measure, only re-select the button
480 * if it is different to the previously selected one. */
481 if (best != 0 && best != cur_button)
482 dvdnav_button_select(this, pci, best);
484 /* return DVDNAV_STATUS_OK only if we actually found a matching button */
485 return best ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
488 dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
489 /* A trivial function */
490 if(dvdnav_mouse_select(this, pci, x,y) != DVDNAV_STATUS_ERR)
491 return dvdnav_button_activate(this, pci);
492 return DVDNAV_STATUS_ERR;