00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00215
00216 dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) {
00217
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
00346
00347
00348
00349
00350
00351
00352
00353
00354 if (this->position_current.still != 0) {
00355
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
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
00371
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
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
00390
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
00398 this->vm->hop_channel++;
00399 }
00400 }
00401
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;
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
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;
00459
00460
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
00472
00473 if(d < dist) {
00474 dist = d;
00475 best = button;
00476 }
00477 }
00478 }
00479
00480
00481 if (best != 0 && best != cur_button)
00482 dvdnav_button_select(this, pci, best);
00483
00484
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
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 }