00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025
00026 #include <assert.h>
00027 #include "nav_types.h"
00028 #include "dvdnav_internal.h"
00029
00030
00031
00032
00033
00034 #ifdef BUTTON_TESTING
00035
00036 #include "nav_print.h"
00037
00038 static void print_time(dvd_time_t *dtime) {
00039 const char *rate;
00040
00041 assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa);
00042 assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa);
00043 assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa);
00044 assert((dtime->frame_u&0xf) < 0xa);
00045
00046 fprintf(MSG_OUT,"%02x:%02x:%02x.%02x",
00047 dtime->hour,
00048 dtime->minute,
00049 dtime->second,
00050 dtime->frame_u & 0x3f);
00051 switch((dtime->frame_u & 0xc0) >> 6) {
00052 case 1:
00053 rate = "25.00";
00054 break;
00055 case 3:
00056 rate = "29.97";
00057 break;
00058 default:
00059 rate = "(please send a bug report)";
00060 break;
00061 }
00062 fprintf(MSG_OUT," @ %s fps", rate);
00063 }
00064
00065 static void nav_print_PCI_GI(pci_gi_t *pci_gi) {
00066 int32_t i;
00067
00068 fprintf(MSG_OUT,"libdvdnav: pci_gi:\n");
00069 fprintf(MSG_OUT,"libdvdnav: nv_pck_lbn 0x%08x\n", pci_gi->nv_pck_lbn);
00070 fprintf(MSG_OUT,"libdvdnav: vobu_cat 0x%04x\n", pci_gi->vobu_cat);
00071 fprintf(MSG_OUT,"libdvdnav: vobu_uop_ctl 0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl);
00072 fprintf(MSG_OUT,"libdvdnav: vobu_s_ptm 0x%08x\n", pci_gi->vobu_s_ptm);
00073 fprintf(MSG_OUT,"libdvdnav: vobu_e_ptm 0x%08x\n", pci_gi->vobu_e_ptm);
00074 fprintf(MSG_OUT,"libdvdnav: vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm);
00075 fprintf(MSG_OUT,"libdvdnav: e_eltm ");
00076 print_time(&pci_gi->e_eltm);
00077 fprintf(MSG_OUT,"\n");
00078
00079 fprintf(MSG_OUT,"libdvdnav: vobu_isrc \"");
00080 for(i = 0; i < 32; i++) {
00081 char c = pci_gi->vobu_isrc[i];
00082 if((c >= ' ') && (c <= '~'))
00083 fprintf(MSG_OUT,"%c", c);
00084 else
00085 fprintf(MSG_OUT,".");
00086 }
00087 fprintf(MSG_OUT,"\"\n");
00088 }
00089
00090 static void nav_print_NSML_AGLI(nsml_agli_t *nsml_agli) {
00091 int32_t i, j = 0;
00092
00093 for(i = 0; i < 9; i++)
00094 j |= nsml_agli->nsml_agl_dsta[i];
00095 if(j == 0)
00096 return;
00097
00098 fprintf(MSG_OUT,"libdvdnav: nsml_agli:\n");
00099 for(i = 0; i < 9; i++)
00100 if(nsml_agli->nsml_agl_dsta[i])
00101 fprintf(MSG_OUT,"libdvdnav: nsml_agl_c%d_dsta 0x%08x\n", i + 1,
00102 nsml_agli->nsml_agl_dsta[i]);
00103 }
00104
00105 static void nav_print_HL_GI(hl_gi_t *hl_gi, int32_t *btngr_ns, int32_t *btn_ns) {
00106
00107 if((hl_gi->hli_ss & 0x03) == 0)
00108 return;
00109
00110 fprintf(MSG_OUT,"libdvdnav: hl_gi:\n");
00111 fprintf(MSG_OUT,"libdvdnav: hli_ss 0x%01x\n", hl_gi->hli_ss & 0x03);
00112 fprintf(MSG_OUT,"libdvdnav: hli_s_ptm 0x%08x\n", hl_gi->hli_s_ptm);
00113 fprintf(MSG_OUT,"libdvdnav: hli_e_ptm 0x%08x\n", hl_gi->hli_e_ptm);
00114 fprintf(MSG_OUT,"libdvdnav: btn_se_e_ptm 0x%08x\n", hl_gi->btn_se_e_ptm);
00115
00116 *btngr_ns = hl_gi->btngr_ns;
00117 fprintf(MSG_OUT,"libdvdnav: btngr_ns %d\n", hl_gi->btngr_ns);
00118 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 1, hl_gi->btngr1_dsp_ty);
00119 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 2, hl_gi->btngr2_dsp_ty);
00120 fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty 0x%02x\n", 3, hl_gi->btngr3_dsp_ty);
00121
00122 fprintf(MSG_OUT,"libdvdnav: btn_ofn %d\n", hl_gi->btn_ofn);
00123 *btn_ns = hl_gi->btn_ns;
00124 fprintf(MSG_OUT,"libdvdnav: btn_ns %d\n", hl_gi->btn_ns);
00125 fprintf(MSG_OUT,"libdvdnav: nsl_btn_ns %d\n", hl_gi->nsl_btn_ns);
00126 fprintf(MSG_OUT,"libdvdnav: fosl_btnn %d\n", hl_gi->fosl_btnn);
00127 fprintf(MSG_OUT,"libdvdnav: foac_btnn %d\n", hl_gi->foac_btnn);
00128 }
00129
00130 static void nav_print_BTN_COLIT(btn_colit_t *btn_colit) {
00131 int32_t i, j;
00132
00133 j = 0;
00134 for(i = 0; i < 6; i++)
00135 j |= btn_colit->btn_coli[i/2][i&1];
00136 if(j == 0)
00137 return;
00138
00139 fprintf(MSG_OUT,"libdvdnav: btn_colit:\n");
00140 for(i = 0; i < 3; i++)
00141 for(j = 0; j < 2; j++)
00142 fprintf(MSG_OUT,"libdvdnav: btn_cqoli %d %s_coli: %08x\n",
00143 i, (j == 0) ? "sl" : "ac",
00144 btn_colit->btn_coli[i][j]);
00145 }
00146
00147 static void nav_print_BTNIT(btni_t *btni_table, int32_t btngr_ns, int32_t btn_ns) {
00148 int32_t i, j, k;
00149
00150 fprintf(MSG_OUT,"libdvdnav: btnit:\n");
00151 fprintf(MSG_OUT,"libdvdnav: btngr_ns: %i\n", btngr_ns);
00152 fprintf(MSG_OUT,"libdvdnav: btn_ns: %i\n", btn_ns);
00153
00154 if(btngr_ns == 0)
00155 return;
00156
00157 for(i = 0; i < btngr_ns; i++) {
00158 for(j = 0; j < (36 / btngr_ns); j++) {
00159 if(j < btn_ns) {
00160 btni_t *btni = &btni_table[(36 / btngr_ns) * i + j];
00161
00162 fprintf(MSG_OUT,"libdvdnav: group %d btni %d: ", i+1, j+1);
00163 fprintf(MSG_OUT,"btn_coln %d, auto_action_mode %d\n",
00164 btni->btn_coln, btni->auto_action_mode);
00165 fprintf(MSG_OUT,"libdvdnav: coords (%d, %d) .. (%d, %d)\n",
00166 btni->x_start, btni->y_start, btni->x_end, btni->y_end);
00167
00168 fprintf(MSG_OUT,"libdvdnav: up %d, ", btni->up);
00169 fprintf(MSG_OUT,"down %d, ", btni->down);
00170 fprintf(MSG_OUT,"left %d, ", btni->left);
00171 fprintf(MSG_OUT,"right %d\n", btni->right);
00172 for(k = 0; k < 8; k++) {
00173 fprintf(MSG_OUT, "libdvdnav: %02x ", btni->cmd.bytes[k]);
00174 }
00175 fprintf(MSG_OUT, "| ");
00176 #ifdef TRACE
00177 vm_print_mnemonic(&btni->cmd);
00178 #endif
00179 fprintf(MSG_OUT, "\n");
00180 }
00181 }
00182 }
00183 }
00184
00185 static void nav_print_HLI(hli_t *hli) {
00186 int32_t btngr_ns = 0, btn_ns = 0;
00187
00188 fprintf(MSG_OUT,"libdvdnav: hli:\n");
00189 nav_print_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns);
00190 nav_print_BTN_COLIT(&hli->btn_colit);
00191 nav_print_BTNIT(hli->btnit, btngr_ns, btn_ns);
00192 }
00193
00194 void nav_print_PCI(pci_t *pci) {
00195 fprintf(MSG_OUT,"libdvdnav: pci packet:\n");
00196 nav_print_PCI_GI(&pci->pci_gi);
00197 nav_print_NSML_AGLI(&pci->nsml_agli);
00198 nav_print_HLI(&pci->hli);
00199 }
00200
00201 #endif
00202
00203
00204
00205
00206 dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) {
00207
00208 if(!this || !button) {
00209 printerr("Passed a NULL pointer.");
00210 return DVDNAV_STATUS_ERR;
00211 }
00212
00213
00214 if(((*button) = this->position_current.button) == -1)
00215 (*button) = this->vm->state.HL_BTNN_REG >> 10;
00216
00217 return DVDNAV_STATUS_OK;
00218 }
00219
00220 static btni_t *get_current_button(dvdnav_t *this, pci_t *pci) {
00221 int32_t button = 0;
00222
00223 if(!this || !pci) {
00224 printerr("Passed a NULL pointer.");
00225 return NULL;
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 = NULL;
00293 unsigned int btns_per_group;
00294
00295 #ifdef BUTTON_TESTING
00296 fprintf(MSG_OUT, "libdvdnav: Button get_highlight_area %i\n", button);
00297 #endif
00298
00299 if(!nav_pci->hli.hl_gi.hli_ss)
00300 return DVDNAV_STATUS_ERR;
00301 if((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns))
00302 return DVDNAV_STATUS_ERR;
00303
00304
00305
00306
00307
00308 btns_per_group = 36 / nav_pci->hli.hl_gi.btngr_ns;
00309
00310 if (!button_ptr && nav_pci->hli.hl_gi.btngr_ns >= 1 &&
00311 !(nav_pci->hli.hl_gi.btngr1_dsp_ty & 6))
00312 {
00313 button_ptr = &nav_pci->hli.btnit[0 * btns_per_group + button - 1];
00314 }
00315
00316 if (!button_ptr && nav_pci->hli.hl_gi.btngr_ns >= 2 &&
00317 !(nav_pci->hli.hl_gi.btngr2_dsp_ty & 6))
00318 {
00319 button_ptr = &nav_pci->hli.btnit[1 * btns_per_group + button - 1];
00320 }
00321
00322 if (!button_ptr && nav_pci->hli.hl_gi.btngr_ns >= 3 &&
00323 !(nav_pci->hli.hl_gi.btngr3_dsp_ty & 6))
00324 {
00325 button_ptr = &nav_pci->hli.btnit[2 * btns_per_group + button - 1];
00326 }
00327
00328 if (!button_ptr) {
00329 button_ptr = &nav_pci->hli.btnit[button - 1];
00330 }
00331
00332
00333 highlight->sx = button_ptr->x_start;
00334 highlight->sy = button_ptr->y_start;
00335 highlight->ex = button_ptr->x_end;
00336 highlight->ey = button_ptr->y_end;
00337 if(button_ptr->btn_coln != 0) {
00338 highlight->palette = nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode];
00339 } else {
00340 highlight->palette = 0;
00341 }
00342 highlight->pts = nav_pci->hli.hl_gi.hli_s_ptm;
00343 highlight->buttonN = button;
00344 #ifdef BUTTON_TESTING
00345 fprintf(MSG_OUT, "libdvdnav: highlight: Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n",
00346 button_ptr->x_start, button_ptr->y_start,
00347 button_ptr->x_end, button_ptr->y_end,
00348 1,
00349 button);
00350 #endif
00351
00352 return DVDNAV_STATUS_OK;
00353 }
00354
00355 dvdnav_status_t dvdnav_button_activate(dvdnav_t *this, pci_t *pci) {
00356 int32_t button;
00357 btni_t *button_ptr = NULL;
00358
00359 if(!this || !pci) {
00360 printerr("Passed a NULL pointer.");
00361 return DVDNAV_STATUS_ERR;
00362 }
00363 if(!pci->hli.hl_gi.hli_ss) {
00364 printerr("Not in a menu.");
00365 return DVDNAV_STATUS_ERR;
00366 }
00367 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
00368 printerr("This NAV has already been left.");
00369 return DVDNAV_STATUS_ERR;
00370 }
00371 pthread_mutex_lock(&this->vm_lock);
00372
00373 button = this->vm->state.HL_BTNN_REG >> 10;
00374
00375 if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 if (this->position_current.still != 0) {
00386
00387 vm_get_next_cell(this->vm);
00388 this->position_current.still = 0;
00389 this->sync_wait = 0;
00390 this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
00391 pthread_mutex_unlock(&this->vm_lock);
00392
00393 printerr("");
00394 return DVDNAV_STATUS_OK;
00395 }
00396 pthread_mutex_unlock(&this->vm_lock);
00397 return DVDNAV_STATUS_ERR;
00398 }
00399
00400 button_ptr = get_current_button(this, pci);
00401
00402
00403 #ifdef BUTTON_TESTING
00404 fprintf(MSG_OUT, "libdvdnav: Evaluating Button Activation commands.\n");
00405 #endif
00406 if(vm_exec_cmd(this->vm, &(button_ptr->cmd)) == 1) {
00407
00408 this->vm->hop_channel++;
00409 this->position_current.still = 0;
00410 this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
00411 }
00412
00413 pthread_mutex_unlock(&this->vm_lock);
00414 return DVDNAV_STATUS_OK;
00415 }
00416
00417 dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *this, int32_t button, vm_cmd_t *cmd)
00418 {
00419 if(!this || !cmd) {
00420 printerr("Passed a NULL pointer.");
00421 return DVDNAV_STATUS_ERR;
00422 }
00423
00424 pthread_mutex_lock(&this->vm_lock);
00425
00426
00427 #ifdef BUTTON_TESTING
00428 fprintf(MSG_OUT, "libdvdnav: dvdnav_button_activate_cmd: Evaluating Button Activation commands.\n");
00429 #endif
00430 if(button > 0) {
00431 this->vm->state.HL_BTNN_REG = (button << 10);
00432 if(vm_exec_cmd(this->vm, cmd) == 1) {
00433
00434 this->vm->hop_channel++;
00435 }
00436 }
00437
00438 this->position_current.still = 0;
00439 this->sync_wait = 0;
00440 pthread_mutex_unlock(&this->vm_lock);
00441 return DVDNAV_STATUS_OK;
00442 }
00443
00444 dvdnav_status_t dvdnav_button_select(dvdnav_t *this, pci_t *pci, int32_t button) {
00445
00446 if(!this || !pci) {
00447 printerr("Passed a NULL pointer.");
00448 return DVDNAV_STATUS_ERR;
00449 }
00450 if(!pci->hli.hl_gi.hli_ss) {
00451 printerr("Not in a menu.");
00452 return DVDNAV_STATUS_ERR;
00453 }
00454 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
00455 printerr("This NAV has already been left.");
00456 return DVDNAV_STATUS_ERR;
00457 }
00458
00459 #ifdef BUTTON_TESTING
00460 fprintf(MSG_OUT, "libdvdnav: Button select %i\n", button);
00461 #endif
00462
00463 if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
00464 printerr("Button does not exist.");
00465 return DVDNAV_STATUS_ERR;
00466 }
00467
00468 this->vm->state.HL_BTNN_REG = (button << 10);
00469 this->position_current.button = -1;
00470
00471 return DVDNAV_STATUS_OK;
00472 }
00473
00474 dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *this, pci_t *pci,
00475 int32_t button) {
00476
00477 if(dvdnav_button_select(this, pci, button) != DVDNAV_STATUS_ERR)
00478 return dvdnav_button_activate(this, pci);
00479 return DVDNAV_STATUS_ERR;
00480 }
00481
00482 dvdnav_status_t dvdnav_mouse_select(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
00483 int32_t button, cur_button;
00484 int32_t best,dist,d;
00485 int32_t mx,my,dx,dy;
00486
00487 if(!this || !pci) {
00488 printerr("Passed a NULL pointer.");
00489 return DVDNAV_STATUS_ERR;
00490 }
00491 if(!pci->hli.hl_gi.hli_ss) {
00492 printerr("Not in a menu.");
00493 return DVDNAV_STATUS_ERR;
00494 }
00495 if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
00496 printerr("This NAV has already been left.");
00497 return DVDNAV_STATUS_ERR;
00498 }
00499
00500 cur_button = this->vm->state.HL_BTNN_REG >> 10;
00501
00502 best = 0;
00503 dist = 0x08000000;
00504
00505
00506 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) {
00507 btni_t *button_ptr = &(pci->hli.btnit[button-1]);
00508
00509 if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) &&
00510 (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) {
00511 mx = (button_ptr->x_start + button_ptr->x_end)/2;
00512 my = (button_ptr->y_start + button_ptr->y_end)/2;
00513 dx = mx - x;
00514 dy = my - y;
00515 d = (dx*dx) + (dy*dy);
00516
00517
00518 if(d < dist) {
00519 dist = d;
00520 best = button;
00521 }
00522 }
00523 }
00524
00525
00526 if (best != 0 && best != cur_button)
00527 dvdnav_button_select(this, pci, best);
00528
00529
00530 return best ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
00531 }
00532
00533 dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
00534
00535 if(dvdnav_mouse_select(this, pci, x,y) != DVDNAV_STATUS_ERR)
00536 return dvdnav_button_activate(this, pci);
00537 return DVDNAV_STATUS_ERR;
00538 }