MythTV  0.26-pre
highlight.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends