|
MythTV
0.26-pre
|
00001 /* 00002 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net> 00003 * 00004 * This file is part of libdvdnav, a DVD navigation library. 00005 * 00006 * libdvdnav is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * libdvdnav is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with libdvdnav; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 00021 #ifdef HAVE_CONFIG_H 00022 #include "config.h" 00023 #endif 00024 00025 #include <assert.h> 00026 #include <inttypes.h> 00027 #include <stdlib.h> 00028 #include <stdio.h> 00029 #include <limits.h> 00030 #include <string.h> 00031 #include <sys/time.h> 00032 #include <dvdread/nav_types.h> 00033 #include "dvdnav/dvdnav.h" 00034 #include "remap.h" 00035 #include "vm/decoder.h" 00036 #include "vm/vm.h" 00037 #include "vm/vmcmd.h" 00038 #include "dvdnav_internal.h" 00039 00040 /* 00041 #define BUTTON_TESTING 00042 */ 00043 00044 #ifdef BUTTON_TESTING 00045 00046 #include "nav_print.h" 00047 00048 static void print_time(dvd_time_t *dtime) { 00049 const char *rate; 00050 00051 assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa); 00052 assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa); 00053 assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa); 00054 assert((dtime->frame_u&0xf) < 0xa); 00055 00056 fprintf(MSG_OUT,"%02x:%02x:%02x.%02x", 00057 dtime->hour, 00058 dtime->minute, 00059 dtime->second, 00060 dtime->frame_u & 0x3f); 00061 switch((dtime->frame_u & 0xc0) >> 6) { 00062 case 1: 00063 rate = "25.00"; 00064 break; 00065 case 3: 00066 rate = "29.97"; 00067 break; 00068 default: 00069 rate = "(please send a bug report)"; 00070 break; 00071 } 00072 fprintf(MSG_OUT," @ %s fps", rate); 00073 } 00074 00075 static void nav_print_PCI_GI(pci_gi_t *pci_gi) { 00076 int32_t i; 00077 00078 fprintf(MSG_OUT,"libdvdnav: pci_gi:\n"); 00079 fprintf(MSG_OUT,"libdvdnav: nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn); 00080 fprintf(MSG_OUT,"libdvdnav: vobu_cat 0x%04x\n", pci_gi->vobu_cat); 00081 fprintf(MSG_OUT,"libdvdnav: vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl); 00082 fprintf(MSG_OUT,"libdvdnav: vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm); 00083 fprintf(MSG_OUT,"libdvdnav: vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm); 00084 fprintf(MSG_OUT,"libdvdnav: vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm); 00085 fprintf(MSG_OUT,"libdvdnav: e_eltm "); 00086 print_time(&pci_gi->e_eltm); 00087 fprintf(MSG_OUT,"\n"); 00088 00089 fprintf(MSG_OUT,"libdvdnav: vobu_isrc \""); 00090 for(i = 0; i < 32; i++) { 00091 char c = pci_gi->vobu_isrc[i]; 00092 if((c >= ' ') && (c <= '~')) 00093 fprintf(MSG_OUT,"%c", c); 00094 else 00095 fprintf(MSG_OUT,"."); 00096 } 00097 fprintf(MSG_OUT,"\"\n"); 00098 } 00099 00100 static void nav_print_NSML_AGLI(nsml_agli_t *nsml_agli) { 00101 int32_t i, j = 0; 00102 00103 for(i = 0; i < 9; i++) 00104 j |= nsml_agli->nsml_agl_dsta[i]; 00105 if(j == 0) 00106 return; 00107 00108 fprintf(MSG_OUT,"libdvdnav: nsml_agli:\n"); 00109 for(i = 0; i < 9; i++) 00110 if(nsml_agli->nsml_agl_dsta[i]) 00111 fprintf(MSG_OUT,"libdvdnav: nsml_agl_c%d_dsta 0x%08x\n", i + 1, 00112 nsml_agli->nsml_agl_dsta[i]); 00113 } 00114 00115 static void nav_print_HL_GI(hl_gi_t *hl_gi, int32_t *btngr_ns, int32_t *btn_ns) { 00116 00117 if((hl_gi->hli_ss & 0x03) == 0) 00118 return; 00119 00120 fprintf(MSG_OUT,"libdvdnav: hl_gi:\n"); 00121 fprintf(MSG_OUT,"libdvdnav: hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03); 00122 fprintf(MSG_OUT,"libdvdnav: hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm); 00123 fprintf(MSG_OUT,"libdvdnav: hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm); 00124 fprintf(MSG_OUT,"libdvdnav: btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm); 00125 00126 *btngr_ns = hl_gi->btngr_ns; 00127 fprintf(MSG_OUT,"libdvdnav: btngr_ns %d\n", hl_gi->btngr_ns); 00128 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty); 00129 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty); 00130 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty); 00131 00132 fprintf(MSG_OUT,"libdvdnav: btn_ofn %d\n", hl_gi->btn_ofn); 00133 *btn_ns = hl_gi->btn_ns; 00134 fprintf(MSG_OUT,"libdvdnav: btn_ns %d\n", hl_gi->btn_ns); 00135 fprintf(MSG_OUT,"libdvdnav: nsl_btn_ns %d\n", hl_gi->nsl_btn_ns); 00136 fprintf(MSG_OUT,"libdvdnav: fosl_btnn %d\n", hl_gi->fosl_btnn); 00137 fprintf(MSG_OUT,"libdvdnav: foac_btnn %d\n", hl_gi->foac_btnn); 00138 } 00139 00140 static void nav_print_BTN_COLIT(btn_colit_t *btn_colit) { 00141 int32_t i, j; 00142 00143 j = 0; 00144 for(i = 0; i < 6; i++) 00145 j |= btn_colit->btn_coli[i/2][i&1]; 00146 if(j == 0) 00147 return; 00148 00149 fprintf(MSG_OUT,"libdvdnav: btn_colit:\n"); 00150 for(i = 0; i < 3; i++) 00151 for(j = 0; j < 2; j++) 00152 fprintf(MSG_OUT,"libdvdnav: btn_cqoli %d %s_coli: %08x\n", 00153 i, (j == 0) ? "sl" : "ac", 00154 btn_colit->btn_coli[i][j]); 00155 } 00156 00157 static void nav_print_BTNIT(btni_t *btni_table, int32_t btngr_ns, int32_t btn_ns) { 00158 int32_t i, j, k; 00159 00160 fprintf(MSG_OUT,"libdvdnav: btnit:\n"); 00161 fprintf(MSG_OUT,"libdvdnav: btngr_ns: %i\n", btngr_ns); 00162 fprintf(MSG_OUT,"libdvdnav: btn_ns: %i\n", btn_ns); 00163 00164 if(btngr_ns == 0) 00165 return; 00166 00167 for(i = 0; i < btngr_ns; i++) { 00168 for(j = 0; j < (36 / btngr_ns); j++) { 00169 if(j < btn_ns) { 00170 btni_t *btni = &btni_table[(36 / btngr_ns) * i + j]; 00171 00172 fprintf(MSG_OUT,"libdvdnav: group %d btni %d: ", i+1, j+1); 00173 fprintf(MSG_OUT,"btn_coln %d, auto_action_mode %d\n", 00174 btni->btn_coln, btni->auto_action_mode); 00175 fprintf(MSG_OUT,"libdvdnav: coords (%d, %d) .. (%d, %d)\n", 00176 btni->x_start, btni->y_start, btni->x_end, btni->y_end); 00177 00178 fprintf(MSG_OUT,"libdvdnav: up %d, ", btni->up); 00179 fprintf(MSG_OUT,"down %d, ", btni->down); 00180 fprintf(MSG_OUT,"left %d, ", btni->left); 00181 fprintf(MSG_OUT,"right %d\n", btni->right); 00182 for(k = 0; k < 8; k++) { 00183 fprintf(MSG_OUT, "libdvdnav: %02x ", btni->cmd.bytes[k]); 00184 } 00185 fprintf(MSG_OUT, "| "); 00186 #ifdef TRACE 00187 vm_print_mnemonic(&btni->cmd); 00188 #endif 00189 fprintf(MSG_OUT, "\n"); 00190 } 00191 } 00192 } 00193 } 00194 00195 static void nav_print_HLI(hli_t *hli) { 00196 int32_t btngr_ns = 0, btn_ns = 0; 00197 00198 fprintf(MSG_OUT,"libdvdnav: hli:\n"); 00199 nav_print_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns); 00200 nav_print_BTN_COLIT(&hli->btn_colit); 00201 nav_print_BTNIT(hli->btnit, btngr_ns, btn_ns); 00202 } 00203 00204 void nav_print_PCI(pci_t *pci) { 00205 fprintf(MSG_OUT,"libdvdnav: pci packet:\n"); 00206 nav_print_PCI_GI(&pci->pci_gi); 00207 nav_print_NSML_AGLI(&pci->nsml_agli); 00208 nav_print_HLI(&pci->hli); 00209 } 00210 00211 #endif 00212 00213 00214 /* Highlighting API calls */ 00215 00216 dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) { 00217 /* Simply return the appropriate value based on the SPRM */ 00218 if(((*button) = this->position_current.button) == -1) 00219 (*button) = this->vm->state.HL_BTNN_REG >> 10; 00220 00221 return DVDNAV_STATUS_OK; 00222 } 00223 00224 static btni_t *get_current_button(dvdnav_t *this, pci_t *pci) { 00225 int32_t button = 0; 00226 00227 if(!pci->hli.hl_gi.hli_ss) { 00228 printerr("Not in a menu."); 00229 return NULL; 00230 } 00231 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { 00232 printerr("This NAV has already been left."); 00233 return NULL; 00234 } 00235 00236 button = this->vm->state.HL_BTNN_REG >> 10; 00237 #ifdef BUTTON_TESTING 00238 nav_print_PCI(pci); 00239 #endif 00240 00241 return &(pci->hli.btnit[button-1]); 00242 } 00243 00244 static dvdnav_status_t button_auto_action(dvdnav_t *this, pci_t *pci) { 00245 if (get_current_button(this, pci)->auto_action_mode) 00246 return dvdnav_button_activate(this, pci); 00247 return DVDNAV_STATUS_OK; 00248 } 00249 00250 dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *this, pci_t *pci) { 00251 btni_t *button_ptr; 00252 00253 if(!(button_ptr = get_current_button(this, pci))) 00254 return DVDNAV_STATUS_ERR; 00255 00256 dvdnav_button_select(this, pci, button_ptr->up); 00257 return button_auto_action(this, pci); 00258 } 00259 00260 dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *this, pci_t *pci) { 00261 btni_t *button_ptr; 00262 00263 if(!(button_ptr = get_current_button(this, pci))) 00264 return DVDNAV_STATUS_ERR; 00265 00266 dvdnav_button_select(this, pci, button_ptr->down); 00267 return button_auto_action(this, pci); 00268 } 00269 00270 dvdnav_status_t dvdnav_right_button_select(dvdnav_t *this, pci_t *pci) { 00271 btni_t *button_ptr; 00272 00273 if(!(button_ptr = get_current_button(this, pci))) 00274 return DVDNAV_STATUS_ERR; 00275 00276 dvdnav_button_select(this, pci, button_ptr->right); 00277 return button_auto_action(this, pci); 00278 } 00279 00280 dvdnav_status_t dvdnav_left_button_select(dvdnav_t *this, pci_t *pci) { 00281 btni_t *button_ptr; 00282 00283 if(!(button_ptr = get_current_button(this, pci))) 00284 return DVDNAV_STATUS_ERR; 00285 00286 dvdnav_button_select(this, pci, button_ptr->left); 00287 return button_auto_action(this, pci); 00288 } 00289 00290 dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode, 00291 dvdnav_highlight_area_t *highlight) { 00292 btni_t *button_ptr; 00293 00294 #ifdef BUTTON_TESTING 00295 fprintf(MSG_OUT, "libdvdnav: Button get_highlight_area %i\n", button); 00296 #endif 00297 00298 if(!nav_pci->hli.hl_gi.hli_ss) 00299 return DVDNAV_STATUS_ERR; 00300 if((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns)) 00301 return DVDNAV_STATUS_ERR; 00302 00303 00304 button_ptr = &nav_pci->hli.btnit[button-1]; 00305 00306 highlight->sx = button_ptr->x_start; 00307 highlight->sy = button_ptr->y_start; 00308 highlight->ex = button_ptr->x_end; 00309 highlight->ey = button_ptr->y_end; 00310 if(button_ptr->btn_coln != 0) { 00311 highlight->palette = nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode]; 00312 } else { 00313 highlight->palette = 0; 00314 } 00315 highlight->pts = nav_pci->hli.hl_gi.hli_s_ptm; 00316 highlight->buttonN = button; 00317 #ifdef BUTTON_TESTING 00318 fprintf(MSG_OUT, "libdvdnav: highlight: Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n", 00319 button_ptr->x_start, button_ptr->y_start, 00320 button_ptr->x_end, button_ptr->y_end, 00321 1, 00322 button); 00323 #endif 00324 00325 return DVDNAV_STATUS_OK; 00326 } 00327 00328 dvdnav_status_t dvdnav_button_activate(dvdnav_t *this, pci_t *pci) { 00329 int32_t button; 00330 btni_t *button_ptr = NULL; 00331 00332 if(!pci->hli.hl_gi.hli_ss) { 00333 printerr("Not in a menu."); 00334 return DVDNAV_STATUS_ERR; 00335 } 00336 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { 00337 printerr("This NAV has already been left."); 00338 return DVDNAV_STATUS_ERR; 00339 } 00340 pthread_mutex_lock(&this->vm_lock); 00341 00342 button = this->vm->state.HL_BTNN_REG >> 10; 00343 00344 if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) { 00345 /* Special code to handle still menus with no buttons. 00346 * The navigation is expected to report to the application that a STILL is 00347 * underway. In turn, the application is supposed to report to the user 00348 * that the playback is paused. The user is then expected to undo the pause, 00349 * ie: hit play. At that point, the navigation should release the still and 00350 * go to the next Cell. 00351 * Explanation by Mathieu Lacage <mathieu_lacage@realmagic.fr> 00352 * Code added by jcdutton. 00353 */ 00354 if (this->position_current.still != 0) { 00355 /* In still, but no buttons. */ 00356 vm_get_next_cell(this->vm); 00357 this->position_current.still = 0; 00358 this->sync_wait = 0; 00359 this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn; 00360 pthread_mutex_unlock(&this->vm_lock); 00361 /* clear error message */ 00362 printerr(""); 00363 return DVDNAV_STATUS_OK; 00364 } 00365 pthread_mutex_unlock(&this->vm_lock); 00366 return DVDNAV_STATUS_ERR; 00367 } 00368 00369 button_ptr = get_current_button(this, pci); 00370 /* Finally, make the VM execute the appropriate code and probably 00371 * schedule a jump */ 00372 #ifdef BUTTON_TESTING 00373 fprintf(MSG_OUT, "libdvdnav: Evaluating Button Activation commands.\n"); 00374 #endif 00375 if(vm_exec_cmd(this->vm, &(button_ptr->cmd)) == 1) { 00376 /* Command caused a jump */ 00377 this->vm->hop_channel++; 00378 this->position_current.still = 0; 00379 this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn; 00380 } 00381 00382 pthread_mutex_unlock(&this->vm_lock); 00383 return DVDNAV_STATUS_OK; 00384 } 00385 00386 dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *this, int32_t button, vm_cmd_t *cmd) 00387 { 00388 pthread_mutex_lock(&this->vm_lock); 00389 /* make the VM execute the appropriate code and probably 00390 * schedule a jump */ 00391 #ifdef BUTTON_TESTING 00392 fprintf(MSG_OUT, "libdvdnav: dvdnav_button_activate_cmd: Evaluating Button Activation commands.\n"); 00393 #endif 00394 if(button > 0) { 00395 this->vm->state.HL_BTNN_REG = (button << 10); 00396 if(vm_exec_cmd(this->vm, cmd) == 1) { 00397 /* Command caused a jump */ 00398 this->vm->hop_channel++; 00399 } 00400 } 00401 /* Always remove still, because some still menus have no buttons. */ 00402 this->position_current.still = 0; 00403 this->sync_wait = 0; 00404 pthread_mutex_unlock(&this->vm_lock); 00405 return DVDNAV_STATUS_OK; 00406 } 00407 00408 dvdnav_status_t dvdnav_button_select(dvdnav_t *this, pci_t *pci, int32_t button) { 00409 if(!pci->hli.hl_gi.hli_ss) { 00410 printerr("Not in a menu."); 00411 return DVDNAV_STATUS_ERR; 00412 } 00413 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { 00414 printerr("This NAV has already been left."); 00415 return DVDNAV_STATUS_ERR; 00416 } 00417 00418 #ifdef BUTTON_TESTING 00419 fprintf(MSG_OUT, "libdvdnav: Button select %i\n", button); 00420 #endif 00421 00422 if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) { 00423 printerr("Button does not exist."); 00424 return DVDNAV_STATUS_ERR; 00425 } 00426 00427 this->vm->state.HL_BTNN_REG = (button << 10); 00428 this->position_current.button = -1; /* Force Highlight change */ 00429 00430 return DVDNAV_STATUS_OK; 00431 } 00432 00433 dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *this, pci_t *pci, 00434 int32_t button) { 00435 /* A trivial function */ 00436 if(dvdnav_button_select(this, pci, button) != DVDNAV_STATUS_ERR) 00437 return dvdnav_button_activate(this, pci); 00438 return DVDNAV_STATUS_ERR; 00439 } 00440 00441 dvdnav_status_t dvdnav_mouse_select(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) { 00442 int32_t button, cur_button; 00443 int32_t best,dist,d; 00444 int32_t mx,my,dx,dy; 00445 00446 if(!pci->hli.hl_gi.hli_ss) { 00447 printerr("Not in a menu."); 00448 return DVDNAV_STATUS_ERR; 00449 } 00450 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) { 00451 printerr("This NAV has already been left."); 00452 return DVDNAV_STATUS_ERR; 00453 } 00454 00455 cur_button = this->vm->state.HL_BTNN_REG >> 10; 00456 00457 best = 0; 00458 dist = 0x08000000; /* >> than (720*720)+(567*567); */ 00459 00460 /* Loop through all buttons */ 00461 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) { 00462 btni_t *button_ptr = &(pci->hli.btnit[button-1]); 00463 00464 if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) && 00465 (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) { 00466 mx = (button_ptr->x_start + button_ptr->x_end)/2; 00467 my = (button_ptr->y_start + button_ptr->y_end)/2; 00468 dx = mx - x; 00469 dy = my - y; 00470 d = (dx*dx) + (dy*dy); 00471 /* If the mouse is within the button and the mouse is closer 00472 * to the center of this button then it is the best choice. */ 00473 if(d < dist) { 00474 dist = d; 00475 best = button; 00476 } 00477 } 00478 } 00479 /* As an efficiency measure, only re-select the button 00480 * if it is different to the previously selected one. */ 00481 if (best != 0 && best != cur_button) 00482 dvdnav_button_select(this, pci, best); 00483 00484 /* return DVDNAV_STATUS_OK only if we actually found a matching button */ 00485 return best ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR; 00486 } 00487 00488 dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) { 00489 /* A trivial function */ 00490 if(dvdnav_mouse_select(this, pci, x,y) != DVDNAV_STATUS_ERR) 00491 return dvdnav_button_activate(this, pci); 00492 return DVDNAV_STATUS_ERR; 00493 }
1.7.6.1