|
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 /* 00026 #define LOG_DEBUG 00027 */ 00028 00029 #include <inttypes.h> 00030 #include <stdlib.h> 00031 #include <stdio.h> 00032 #include <unistd.h> 00033 #include <limits.h> 00034 #include <string.h> 00035 #include <sys/time.h> 00036 #include "dvdnav/dvdnav.h" 00037 #include <dvdread/dvd_reader.h> 00038 #include <dvdread/nav_types.h> 00039 #include <dvdread/ifo_types.h> /* For vm_cmd_t */ 00040 #include "remap.h" 00041 #include "vm/decoder.h" 00042 #include "vm/vm.h" 00043 #include "dvdnav_internal.h" 00044 #include "read_cache.h" 00045 #include <dvdread/nav_read.h> 00046 #include "remap.h" 00047 00048 static dvdnav_status_t dvdnav_clear(dvdnav_t * this) { 00049 /* clear everything except file, vm, mutex, readahead */ 00050 00051 pthread_mutex_lock(&this->vm_lock); 00052 if (this->file) DVDCloseFile(this->file); 00053 this->file = NULL; 00054 00055 memset(&this->position_current,0,sizeof(this->position_current)); 00056 memset(&this->pci,0,sizeof(this->pci)); 00057 memset(&this->dsi,0,sizeof(this->dsi)); 00058 this->last_cmd_nav_lbn = SRI_END_OF_CELL; 00059 00060 /* Set initial values of flags */ 00061 this->skip_still = 0; 00062 this->sync_wait = 0; 00063 this->sync_wait_skip = 0; 00064 this->spu_clut_changed = 0; 00065 this->started = 0; 00066 this->cur_cell_time = 0; 00067 00068 dvdnav_read_cache_clear(this->cache); 00069 pthread_mutex_unlock(&this->vm_lock); 00070 00071 return DVDNAV_STATUS_OK; 00072 } 00073 00074 dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) { 00075 dvdnav_t *this; 00076 struct timeval time; 00077 00078 /* Create a new structure */ 00079 fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s\n", DVDNAV_SVN_REV); 00080 00081 (*dest) = NULL; 00082 this = (dvdnav_t*)malloc(sizeof(dvdnav_t)); 00083 if(!this) 00084 return DVDNAV_STATUS_ERR; 00085 memset(this, 0, (sizeof(dvdnav_t) ) ); /* Make sure this structure is clean */ 00086 00087 pthread_mutex_init(&this->vm_lock, NULL); 00088 /* Initialise the error string */ 00089 printerr(""); 00090 00091 /* Initialise the VM */ 00092 this->vm = vm_new_vm(); 00093 if(!this->vm) { 00094 printerr("Error initialising the DVD VM."); 00095 pthread_mutex_destroy(&this->vm_lock); 00096 free(this); 00097 return DVDNAV_STATUS_ERR; 00098 } 00099 if(!vm_reset(this->vm, path)) { 00100 printerr("Error starting the VM / opening the DVD device."); 00101 pthread_mutex_destroy(&this->vm_lock); 00102 vm_free_vm(this->vm); 00103 free(this); 00104 return DVDNAV_STATUS_ERR; 00105 } 00106 00107 /* Set the path. FIXME: Is a deep copy 'right' */ 00108 strncpy(this->path, path, MAX_PATH_LEN - 1); 00109 this->path[MAX_PATH_LEN - 1] = '\0'; 00110 00111 /* Pre-open and close a file so that the CSS-keys are cached. */ 00112 this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS); 00113 00114 /* Start the read-ahead cache. */ 00115 this->cache = dvdnav_read_cache_new(this); 00116 00117 /* Seed the random numbers. So that the DVD VM Command rand() 00118 * gives a different start value each time a DVD is played. */ 00119 gettimeofday(&time, NULL); 00120 srand(time.tv_usec); 00121 00122 dvdnav_clear(this); 00123 00124 (*dest) = this; 00125 return DVDNAV_STATUS_OK; 00126 } 00127 00128 dvdnav_status_t dvdnav_close(dvdnav_t *this) { 00129 00130 #ifdef LOG_DEBUG 00131 fprintf(MSG_OUT, "libdvdnav: close:called\n"); 00132 #endif 00133 00134 if (this->file) { 00135 pthread_mutex_lock(&this->vm_lock); 00136 DVDCloseFile(this->file); 00137 #ifdef LOG_DEBUG 00138 fprintf(MSG_OUT, "libdvdnav: close:file closing\n"); 00139 #endif 00140 this->file = NULL; 00141 pthread_mutex_unlock(&this->vm_lock); 00142 } 00143 00144 /* Free the VM */ 00145 if(this->vm) 00146 vm_free_vm(this->vm); 00147 00148 pthread_mutex_destroy(&this->vm_lock); 00149 00150 /* We leave the final freeing of the entire structure to the cache, 00151 * because we don't know, if there are still buffers out in the wild, 00152 * that must return first. */ 00153 if(this->cache) 00154 dvdnav_read_cache_free(this->cache); 00155 else 00156 free(this); 00157 00158 return DVDNAV_STATUS_OK; 00159 } 00160 00161 dvdnav_status_t dvdnav_reset(dvdnav_t *this) { 00162 dvdnav_status_t result; 00163 00164 #ifdef LOG_DEBUG 00165 fprintf(MSG_OUT, "libdvdnav: reset:called\n"); 00166 #endif 00167 00168 pthread_mutex_lock(&this->vm_lock); 00169 00170 #ifdef LOG_DEBUG 00171 fprintf(MSG_OUT, "libdvdnav: reseting vm\n"); 00172 #endif 00173 if(!vm_reset(this->vm, NULL)) { 00174 printerr("Error restarting the VM."); 00175 pthread_mutex_unlock(&this->vm_lock); 00176 return DVDNAV_STATUS_ERR; 00177 } 00178 #ifdef LOG_DEBUG 00179 fprintf(MSG_OUT, "libdvdnav: clearing dvdnav\n"); 00180 #endif 00181 pthread_mutex_unlock(&this->vm_lock); 00182 result = dvdnav_clear(this); 00183 00184 return result; 00185 } 00186 00187 dvdnav_status_t dvdnav_path(dvdnav_t *this, const char** path) { 00188 (*path) = this->path; 00189 00190 return DVDNAV_STATUS_OK; 00191 } 00192 00193 const char* dvdnav_err_to_string(dvdnav_t *this) { 00194 00195 if(!this) 00196 return "Hey! You gave me a NULL pointer you naughty person!"; 00197 00198 return this->err_str; 00199 } 00200 00201 /* converts a dvd_time_t to PTS ticks */ 00202 int64_t dvdnav_convert_time(dvd_time_t *time) { 00203 int64_t result; 00204 int64_t frames; 00205 00206 result = (time->hour >> 4 ) * 10 * 60 * 60 * 90000; 00207 result += (time->hour & 0x0f) * 60 * 60 * 90000; 00208 result += (time->minute >> 4 ) * 10 * 60 * 90000; 00209 result += (time->minute & 0x0f) * 60 * 90000; 00210 result += (time->second >> 4 ) * 10 * 90000; 00211 result += (time->second & 0x0f) * 90000; 00212 00213 frames = ((time->frame_u & 0x30) >> 4) * 10; 00214 frames += ((time->frame_u & 0x0f) ) ; 00215 00216 if (time->frame_u & 0x80) 00217 result += frames * 3000; 00218 else 00219 result += frames * 3600; 00220 00221 return result; 00222 } 00223 00224 /* 00225 * Returns 1 if block contains NAV packet, 0 otherwise. 00226 * Processes said NAV packet if present. 00227 * 00228 * Most of the code in here is copied from xine's MPEG demuxer 00229 * so any bugs which are found in that should be corrected here also. 00230 */ 00231 static int32_t dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t *nav_dsi, pci_t *nav_pci) { 00232 int32_t bMpeg1 = 0; 00233 uint32_t nHeaderLen; 00234 uint32_t nPacketLen; 00235 uint32_t nStreamID; 00236 00237 if (p[3] == 0xBA) { /* program stream pack header */ 00238 int32_t nStuffingBytes; 00239 00240 bMpeg1 = (p[4] & 0x40) == 0; 00241 00242 if (bMpeg1) { 00243 p += 12; 00244 } else { /* mpeg2 */ 00245 nStuffingBytes = p[0xD] & 0x07; 00246 p += 14 + nStuffingBytes; 00247 } 00248 } 00249 00250 if (p[3] == 0xbb) { /* program stream system header */ 00251 nHeaderLen = (p[4] << 8) | p[5]; 00252 p += 6 + nHeaderLen; 00253 } 00254 00255 /* we should now have a PES packet here */ 00256 if (p[0] || p[1] || (p[2] != 1)) { 00257 fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); 00258 return 0; 00259 } 00260 00261 nPacketLen = p[4] << 8 | p[5]; 00262 nStreamID = p[3]; 00263 00264 nHeaderLen = 6; 00265 p += nHeaderLen; 00266 00267 if (nStreamID == 0xbf) { /* Private stream 2 */ 00268 #if 0 00269 int32_t i; 00270 fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6); 00271 for(i=0;i<80;i++) 00272 fprintf(MSG_OUT, "%02x ",p[i-6]); 00273 fprintf(MSG_OUT, "\n"); 00274 #endif 00275 00276 if(p[0] == 0x00) { 00277 navRead_PCI(nav_pci, p+1); 00278 } 00279 00280 p += nPacketLen; 00281 00282 /* We should now have a DSI packet. */ 00283 if(p[6] == 0x01) { 00284 nPacketLen = p[4] << 8 | p[5]; 00285 p += 6; 00286 navRead_DSI(nav_dsi, p+1); 00287 } 00288 return 1; 00289 } 00290 return 0; 00291 } 00292 00293 /* DSI is used for most angle stuff. 00294 * PCI is used for only non-seemless angle stuff 00295 */ 00296 static int32_t dvdnav_get_vobu(dvdnav_t *this, dsi_t *nav_dsi, pci_t *nav_pci, dvdnav_vobu_t *vobu) { 00297 uint32_t next; 00298 int32_t angle, num_angle; 00299 00300 vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn; /* Absolute offset from start of disk */ 00301 vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea; /* Relative offset from vobu_start */ 00302 00303 /* 00304 * If we're not at the end of this cell, we can determine the next 00305 * VOBU to display using the VOBU_SRI information section of the 00306 * DSI. Using this value correctly follows the current angle, 00307 * avoiding the doubled scenes in The Matrix, and makes our life 00308 * really happy. 00309 * 00310 * vobu_next is an offset value, 0x3fffffff = SRI_END_OF_CELL 00311 * DVDs are about 6 Gigs, which is only up to 0x300000 blocks 00312 * Should really assert if bit 31 != 1 00313 */ 00314 00315 #if 0 00316 /* Old code -- may still be useful one day */ 00317 if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) { 00318 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff ); 00319 } else { 00320 vobu->vobu_next = vobu->vobu_length; 00321 } 00322 #else 00323 /* Relative offset from vobu_start */ 00324 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff ); 00325 #endif 00326 00327 vm_get_angle_info(this->vm, &angle, &num_angle); 00328 00329 /* FIMXE: The angle reset doesn't work for some reason for the moment */ 00330 #if 0 00331 if((num_angle < angle) && (angle != 1)) { 00332 fprintf(MSG_OUT, "libdvdnav: angle ends!\n"); 00333 00334 /* This is to switch back to angle one when we 00335 * finish with angles. */ 00336 dvdnav_angle_change(this, 1); 00337 } 00338 #endif 00339 00340 if(num_angle != 0) { 00341 00342 if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) { 00343 if((next & 0x3fffffff) != 0) { 00344 if(next & 0x80000000) 00345 vobu->vobu_next = - (int32_t)(next & 0x3fffffff); 00346 else 00347 vobu->vobu_next = + (int32_t)(next & 0x3fffffff); 00348 } 00349 } else if((next = nav_dsi->sml_agli.data[angle-1].address) != 0) { 00350 vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea; 00351 00352 if((next & 0x80000000) && (next != 0x7fffffff)) 00353 vobu->vobu_next = - (int32_t)(next & 0x3fffffff); 00354 else 00355 vobu->vobu_next = + (int32_t)(next & 0x3fffffff); 00356 } 00357 } 00358 00359 return 1; 00360 } 00361 00362 /* 00363 * These are the main get_next_block function which actually get the media stream video and audio etc. 00364 * 00365 * There are two versions: The second one is using the zero-copy read ahead cache and therefore 00366 * hands out pointers targetting directly into the cache. 00367 * The first one uses a memcopy to fill this cache block into the application provided memory. 00368 * The benefit of this first one is that no special memory management is needed. The application is 00369 * the only one responsible of allocating and freeing the memory associated with the pointer. 00370 * The drawback is the additional memcopy. 00371 */ 00372 00373 dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, uint8_t *buf, 00374 int32_t *event, int32_t *len) { 00375 unsigned char *block; 00376 dvdnav_status_t status; 00377 00378 block = buf; 00379 status = dvdnav_get_next_cache_block(this, &block, event, len); 00380 if (status == DVDNAV_STATUS_OK && block != buf) { 00381 /* we received a block from the cache, copy it, so we can give it back */ 00382 memcpy(buf, block, DVD_VIDEO_LB_LEN); 00383 dvdnav_free_cache_block(this, block); 00384 } 00385 return status; 00386 } 00387 00388 int64_t dvdnav_get_current_time(dvdnav_t *this) { 00389 int i; 00390 int64_t tm=0; 00391 dvd_state_t *state = &this->vm->state; 00392 00393 for(i=0; i<state->cellN-1; i++) { 00394 if(! 00395 (state->pgc->cell_playback[i].block_type == BLOCK_TYPE_ANGLE_BLOCK && 00396 state->pgc->cell_playback[i].block_mode != BLOCK_MODE_FIRST_CELL) 00397 ) 00398 tm += dvdnav_convert_time(&state->pgc->cell_playback[i].playback_time); 00399 } 00400 tm += this->cur_cell_time; 00401 00402 return tm; 00403 } 00404 00405 dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, uint8_t **buf, 00406 int32_t *event, int32_t *len) { 00407 dvd_state_t *state; 00408 int32_t result; 00409 00410 pthread_mutex_lock(&this->vm_lock); 00411 00412 if(!this->started) { 00413 /* Start the VM */ 00414 if (!vm_start(this->vm)) { 00415 printerr("Encrypted or faulty DVD"); 00416 pthread_mutex_unlock(&this->vm_lock); 00417 return DVDNAV_STATUS_ERR; 00418 } 00419 this->started = 1; 00420 } 00421 00422 state = &(this->vm->state); 00423 (*event) = DVDNAV_NOP; 00424 (*len) = 0; 00425 00426 /* Check the STOP flag */ 00427 if(this->vm->stopped) { 00428 vm_stop(this->vm); 00429 (*event) = DVDNAV_STOP; 00430 this->started = 0; 00431 pthread_mutex_unlock(&this->vm_lock); 00432 return DVDNAV_STATUS_OK; 00433 } 00434 00435 vm_position_get(this->vm, &this->position_next); 00436 00437 #ifdef LOG_DEBUG 00438 fprintf(MSG_OUT, "libdvdnav: POS-NEXT "); 00439 vm_position_print(this->vm, &this->position_next); 00440 fprintf(MSG_OUT, "libdvdnav: POS-CUR "); 00441 vm_position_print(this->vm, &this->position_current); 00442 #endif 00443 00444 /* did we hop? */ 00445 if(this->position_current.hop_channel != this->position_next.hop_channel) { 00446 (*event) = DVDNAV_HOP_CHANNEL; 00447 #ifdef LOG_DEBUG 00448 fprintf(MSG_OUT, "libdvdnav: HOP_CHANNEL\n"); 00449 #endif 00450 if (this->position_next.hop_channel - this->position_current.hop_channel >= HOP_SEEK) { 00451 int32_t num_angles = 0, current; 00452 00453 /* we seeked -> check for multiple angles */ 00454 vm_get_angle_info(this->vm, ¤t, &num_angles); 00455 if (num_angles > 1) { 00456 int32_t result, block; 00457 /* we have to skip the first VOBU when seeking in a multiangle feature, 00458 * because it might belong to the wrong angle */ 00459 block = this->position_next.cell_start + this->position_next.block; 00460 result = dvdnav_read_cache_block(this->cache, block, 1, buf); 00461 if(result <= 0) { 00462 printerr("Error reading NAV packet."); 00463 pthread_mutex_unlock(&this->vm_lock); 00464 return DVDNAV_STATUS_ERR; 00465 } 00466 /* Decode nav into pci and dsi. Then get next VOBU info. */ 00467 if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) { 00468 printerr("Expected NAV packet but none found."); 00469 pthread_mutex_unlock(&this->vm_lock); 00470 return DVDNAV_STATUS_ERR; 00471 } 00472 dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu); 00473 /* skip to next, if there is a next */ 00474 if (this->vobu.vobu_next != SRI_END_OF_CELL) { 00475 this->vobu.vobu_start += this->vobu.vobu_next; 00476 this->vobu.vobu_next = 0; 00477 } 00478 /* update VM state */ 00479 this->vm->state.blockN = this->vobu.vobu_start - this->position_next.cell_start; 00480 } 00481 } 00482 this->position_current.hop_channel = this->position_next.hop_channel; 00483 /* update VOBU info */ 00484 this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block; 00485 this->vobu.vobu_next = 0; 00486 /* Make blockN == vobu_length to do expected_nav */ 00487 this->vobu.vobu_length = 0; 00488 this->vobu.blockN = 0; 00489 this->sync_wait = 0; 00490 pthread_mutex_unlock(&this->vm_lock); 00491 return DVDNAV_STATUS_OK; 00492 } 00493 00494 /* Check the HIGHLIGHT flag */ 00495 if(this->position_current.button != this->position_next.button) { 00496 dvdnav_highlight_event_t *hevent = (dvdnav_highlight_event_t *)*buf; 00497 00498 (*event) = DVDNAV_HIGHLIGHT; 00499 #ifdef LOG_DEBUG 00500 fprintf(MSG_OUT, "libdvdnav: HIGHLIGHT\n"); 00501 #endif 00502 (*len) = sizeof(dvdnav_highlight_event_t); 00503 hevent->display = 1; 00504 hevent->buttonN = this->position_next.button; 00505 this->position_current.button = this->position_next.button; 00506 pthread_mutex_unlock(&this->vm_lock); 00507 return DVDNAV_STATUS_OK; 00508 } 00509 00510 /* Check the WAIT flag */ 00511 if(this->sync_wait) { 00512 (*event) = DVDNAV_WAIT; 00513 #ifdef LOG_DEBUG 00514 fprintf(MSG_OUT, "libdvdnav: WAIT\n"); 00515 #endif 00516 (*len) = 0; 00517 pthread_mutex_unlock(&this->vm_lock); 00518 return DVDNAV_STATUS_OK; 00519 } 00520 00521 /* Check to see if we need to change the currently opened VOB */ 00522 if((this->position_current.vts != this->position_next.vts) || 00523 (this->position_current.domain != this->position_next.domain)) { 00524 dvd_read_domain_t domain; 00525 int32_t vtsN; 00526 dvdnav_vts_change_event_t *vts_event = (dvdnav_vts_change_event_t *)*buf; 00527 00528 if(this->file) { 00529 DVDCloseFile(this->file); 00530 this->file = NULL; 00531 } 00532 00533 vts_event->old_vtsN = this->position_current.vts; 00534 vts_event->old_domain = this->position_current.domain; 00535 00536 /* Use the DOMAIN to find whether to open menu or title VOBs */ 00537 switch(this->position_next.domain) { 00538 case FP_DOMAIN: 00539 case VMGM_DOMAIN: 00540 domain = DVD_READ_MENU_VOBS; 00541 vtsN = 0; 00542 break; 00543 case VTSM_DOMAIN: 00544 domain = DVD_READ_MENU_VOBS; 00545 vtsN = this->position_next.vts; 00546 break; 00547 case VTS_DOMAIN: 00548 domain = DVD_READ_TITLE_VOBS; 00549 vtsN = this->position_next.vts; 00550 break; 00551 default: 00552 printerr("Unknown domain when changing VTS."); 00553 pthread_mutex_unlock(&this->vm_lock); 00554 return DVDNAV_STATUS_ERR; 00555 } 00556 00557 this->position_current.vts = this->position_next.vts; 00558 this->position_current.domain = this->position_next.domain; 00559 dvdnav_read_cache_clear(this->cache); 00560 this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), vtsN, domain); 00561 vts_event->new_vtsN = this->position_next.vts; 00562 vts_event->new_domain = this->position_next.domain; 00563 00564 /* If couldn't open the file for some reason, moan */ 00565 if(this->file == NULL) { 00566 printerrf("Error opening vtsN=%i, domain=%i.", vtsN, domain); 00567 pthread_mutex_unlock(&this->vm_lock); 00568 return DVDNAV_STATUS_ERR; 00569 } 00570 00571 /* File opened successfully so return a VTS change event */ 00572 (*event) = DVDNAV_VTS_CHANGE; 00573 #ifdef LOG_DEBUG 00574 fprintf(MSG_OUT, "libdvdnav: VTS_CHANGE\n"); 00575 #endif 00576 (*len) = sizeof(dvdnav_vts_change_event_t); 00577 00578 this->spu_clut_changed = 1; 00579 this->position_current.cell = -1; /* Force an update */ 00580 this->position_current.spu_channel = -1; /* Force an update */ 00581 this->position_current.audio_channel = -1; /* Force an update */; 00582 00583 pthread_mutex_unlock(&this->vm_lock); 00584 return DVDNAV_STATUS_OK; 00585 } 00586 00587 /* Check if the cell changed */ 00588 if( (this->position_current.cell != this->position_next.cell) || 00589 (this->position_current.cell_restart != this->position_next.cell_restart) || 00590 (this->position_current.cell_start != this->position_next.cell_start) ) { 00591 dvdnav_cell_change_event_t *cell_event = (dvdnav_cell_change_event_t *)*buf; 00592 int32_t first_cell_nr, last_cell_nr, i; 00593 dvd_state_t *state = &this->vm->state; 00594 00595 this->cur_cell_time = 0; 00596 (*event) = DVDNAV_CELL_CHANGE; 00597 #ifdef LOG_DEBUG 00598 fprintf(MSG_OUT, "libdvdnav: CELL_CHANGE\n"); 00599 #endif 00600 (*len) = sizeof(dvdnav_cell_change_event_t); 00601 00602 cell_event->cellN = state->cellN; 00603 cell_event->pgN = state->pgN; 00604 cell_event->cell_length = 00605 dvdnav_convert_time(&state->pgc->cell_playback[state->cellN-1].playback_time); 00606 00607 cell_event->pg_length = 0; 00608 /* Find start cell of program. */ 00609 first_cell_nr = state->pgc->program_map[state->pgN-1]; 00610 /* Find end cell of program */ 00611 if(state->pgN < state->pgc->nr_of_programs) 00612 last_cell_nr = state->pgc->program_map[state->pgN] - 1; 00613 else 00614 last_cell_nr = state->pgc->nr_of_cells; 00615 for (i = first_cell_nr; i <= last_cell_nr; i++) 00616 cell_event->pg_length += 00617 dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time); 00618 cell_event->pgc_length = dvdnav_convert_time(&state->pgc->playback_time); 00619 00620 cell_event->cell_start = 0; 00621 for (i = 1; i < state->cellN; i++) 00622 cell_event->cell_start += 00623 dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time); 00624 00625 cell_event->pg_start = 0; 00626 for (i = 1; i < state->pgc->program_map[state->pgN-1]; i++) 00627 cell_event->pg_start += 00628 dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time); 00629 00630 this->position_current.cell = this->position_next.cell; 00631 this->position_current.cell_restart = this->position_next.cell_restart; 00632 this->position_current.cell_start = this->position_next.cell_start; 00633 this->position_current.block = this->position_next.block; 00634 00635 /* vobu info is used for mid cell resumes */ 00636 this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block; 00637 this->vobu.vobu_next = 0; 00638 /* Make blockN == vobu_length to do expected_nav */ 00639 this->vobu.vobu_length = 0; 00640 this->vobu.blockN = 0; 00641 00642 /* update the spu palette at least on PGC changes */ 00643 this->spu_clut_changed = 1; 00644 this->position_current.spu_channel = -1; /* Force an update */ 00645 this->position_current.audio_channel = -1; /* Force an update */ 00646 00647 pthread_mutex_unlock(&this->vm_lock); 00648 return DVDNAV_STATUS_OK; 00649 } 00650 00651 /* has the CLUT changed? */ 00652 if(this->spu_clut_changed) { 00653 (*event) = DVDNAV_SPU_CLUT_CHANGE; 00654 #ifdef LOG_DEBUG 00655 fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n"); 00656 #endif 00657 (*len) = 16 * sizeof(uint32_t); 00658 memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t)); 00659 this->spu_clut_changed = 0; 00660 pthread_mutex_unlock(&this->vm_lock); 00661 return DVDNAV_STATUS_OK; 00662 } 00663 00664 /* has the SPU channel changed? */ 00665 if(this->position_current.spu_channel != this->position_next.spu_channel) { 00666 dvdnav_spu_stream_change_event_t *stream_change = (dvdnav_spu_stream_change_event_t *)*buf; 00667 00668 (*event) = DVDNAV_SPU_STREAM_CHANGE; 00669 #ifdef LOG_DEBUG 00670 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE\n"); 00671 #endif 00672 (*len) = sizeof(dvdnav_spu_stream_change_event_t); 00673 stream_change->physical_wide = vm_get_subp_active_stream(this->vm, 0); 00674 stream_change->physical_letterbox = vm_get_subp_active_stream(this->vm, 1); 00675 stream_change->physical_pan_scan = vm_get_subp_active_stream(this->vm, 2); 00676 this->position_current.spu_channel = this->position_next.spu_channel; 00677 #ifdef LOG_DEBUG 00678 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change->physical_wide); 00679 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_letterbox=%d\n",stream_change->physical_letterbox); 00680 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_pan_scan=%d\n",stream_change->physical_pan_scan); 00681 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE returning DVDNAV_STATUS_OK\n"); 00682 #endif 00683 pthread_mutex_unlock(&this->vm_lock); 00684 return DVDNAV_STATUS_OK; 00685 } 00686 00687 /* has the audio channel changed? */ 00688 if(this->position_current.audio_channel != this->position_next.audio_channel) { 00689 dvdnav_audio_stream_change_event_t *stream_change = (dvdnav_audio_stream_change_event_t *)*buf; 00690 00691 (*event) = DVDNAV_AUDIO_STREAM_CHANGE; 00692 #ifdef LOG_DEBUG 00693 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE\n"); 00694 #endif 00695 (*len) = sizeof(dvdnav_audio_stream_change_event_t); 00696 stream_change->physical = vm_get_audio_active_stream( this->vm ); 00697 stream_change->logical = this->position_next.audio_channel; 00698 this->position_current.audio_channel = this->position_next.audio_channel; 00699 #ifdef LOG_DEBUG 00700 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE stream_id=%d returning DVDNAV_STATUS_OK\n",stream_change->physical); 00701 #endif 00702 pthread_mutex_unlock(&this->vm_lock); 00703 return DVDNAV_STATUS_OK; 00704 } 00705 00706 /* Check the STILLFRAME flag */ 00707 if(this->position_current.still != 0) { 00708 dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)*buf; 00709 00710 (*event) = DVDNAV_STILL_FRAME; 00711 #ifdef LOG_DEBUG 00712 fprintf(MSG_OUT, "libdvdnav: STILL_FRAME\n"); 00713 #endif 00714 (*len) = sizeof(dvdnav_still_event_t); 00715 still_event->length = this->position_current.still; 00716 pthread_mutex_unlock(&this->vm_lock); 00717 return DVDNAV_STATUS_OK; 00718 } 00719 00720 /* Have we reached the end of a VOBU? */ 00721 if (this->vobu.blockN >= this->vobu.vobu_length) { 00722 00723 /* Have we reached the end of a cell? */ 00724 if(this->vobu.vobu_next == SRI_END_OF_CELL) { 00725 /* End of Cell from NAV DSI info */ 00726 #ifdef LOG_DEBUG 00727 fprintf(MSG_OUT, "libdvdnav: Still set to %x\n", this->position_next.still); 00728 #endif 00729 this->position_current.still = this->position_next.still; 00730 00731 /* we are about to leave a cell, so a lot of state changes could occur; 00732 * under certain conditions, the application should get in sync with us before this, 00733 * otherwise it might show stills or menus too shortly */ 00734 if ((this->position_current.still || this->pci.hli.hl_gi.hli_ss) && !this->sync_wait_skip) { 00735 this->sync_wait = 1; 00736 } else { 00737 if( this->position_current.still == 0 || this->skip_still ) { 00738 /* no active cell still -> get us to the next cell */ 00739 vm_get_next_cell(this->vm); 00740 this->position_current.still = 0; /* still gets activated at end of cell */ 00741 this->skip_still = 0; 00742 this->sync_wait_skip = 0; 00743 } 00744 } 00745 /* handle related state changes in next iteration */ 00746 (*event) = DVDNAV_NOP; 00747 (*len) = 0; 00748 pthread_mutex_unlock(&this->vm_lock); 00749 return DVDNAV_STATUS_OK; 00750 } 00751 00752 /* Perform remapping jump if necessary (this is always a 00753 * VOBU boundary). */ 00754 if (this->vm->map) { 00755 this->vobu.vobu_next = remap_block( this->vm->map, 00756 this->vm->state.domain, this->vm->state.TTN_REG, 00757 this->vm->state.pgN, 00758 this->vobu.vobu_start, this->vobu.vobu_next); 00759 } 00760 00761 /* at the start of the next VOBU -> expecting NAV packet */ 00762 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf); 00763 00764 if(result <= 0) { 00765 printerr("Error reading NAV packet."); 00766 pthread_mutex_unlock(&this->vm_lock); 00767 return DVDNAV_STATUS_ERR; 00768 } 00769 /* Decode nav into pci and dsi. Then get next VOBU info. */ 00770 if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) { 00771 printerr("Expected NAV packet but none found."); 00772 pthread_mutex_unlock(&this->vm_lock); 00773 return DVDNAV_STATUS_ERR; 00774 } 00775 /* We need to update the vm state->blockN with which VOBU we are in. 00776 * This is so RSM resumes to the VOBU level and not just the CELL level. 00777 */ 00778 this->vm->state.blockN = this->vobu.vobu_start - this->position_current.cell_start; 00779 00780 dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu); 00781 this->vobu.blockN = 0; 00782 /* Give the cache a hint about the size of next VOBU. 00783 * This improves pre-caching, because the VOBU will almost certainly be read entirely. 00784 */ 00785 dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1); 00786 00787 /* release NAV menu filter, when we reach the same NAV packet again */ 00788 if (this->last_cmd_nav_lbn == this->pci.pci_gi.nv_pck_lbn) 00789 this->last_cmd_nav_lbn = SRI_END_OF_CELL; 00790 00791 /* Successfully got a NAV packet */ 00792 (*event) = DVDNAV_NAV_PACKET; 00793 #ifdef LOG_DEBUG 00794 fprintf(MSG_OUT, "libdvdnav: NAV_PACKET\n"); 00795 #endif 00796 (*len) = 2048; 00797 this->cur_cell_time = dvdnav_convert_time(&this->dsi.dsi_gi.c_eltm); 00798 pthread_mutex_unlock(&this->vm_lock); 00799 return DVDNAV_STATUS_OK; 00800 } 00801 00802 /* If we've got here, it must just be a normal block. */ 00803 if(!this->file) { 00804 printerr("Attempting to read without opening file."); 00805 pthread_mutex_unlock(&this->vm_lock); 00806 return DVDNAV_STATUS_ERR; 00807 } 00808 00809 this->vobu.blockN++; 00810 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.blockN, 1, buf); 00811 if(result <= 0) { 00812 printerr("Error reading from DVD."); 00813 pthread_mutex_unlock(&this->vm_lock); 00814 return DVDNAV_STATUS_ERR; 00815 } 00816 (*event) = DVDNAV_BLOCK_OK; 00817 (*len) = 2048; 00818 00819 pthread_mutex_unlock(&this->vm_lock); 00820 return DVDNAV_STATUS_OK; 00821 } 00822 00823 dvdnav_status_t dvdnav_get_title_string(dvdnav_t *this, const char **title_str) { 00824 (*title_str) = this->vm->dvd_name; 00825 return DVDNAV_STATUS_OK; 00826 } 00827 00828 dvdnav_status_t dvdnav_get_serial_string(dvdnav_t *this, const char **serial_str) { 00829 (*serial_str) = this->vm->dvd_serial; 00830 return DVDNAV_STATUS_OK; 00831 } 00832 00833 uint8_t dvdnav_get_video_aspect(dvdnav_t *this) { 00834 uint8_t retval; 00835 00836 if(!this->started) { 00837 printerr("Virtual DVD machine not started."); 00838 return -1; 00839 } 00840 00841 pthread_mutex_lock(&this->vm_lock); 00842 retval = (uint8_t)vm_get_video_aspect(this->vm); 00843 pthread_mutex_unlock(&this->vm_lock); 00844 00845 return retval; 00846 } 00847 00848 int dvdnav_get_video_resolution(dvdnav_t *this, uint32_t *width, uint32_t *height) { 00849 int w, h; 00850 00851 if(!this->started) { 00852 printerr("Virtual DVD machine not started."); 00853 return -1; 00854 } 00855 00856 pthread_mutex_lock(&this->vm_lock); 00857 vm_get_video_res(this->vm, &w, &h); 00858 pthread_mutex_unlock(&this->vm_lock); 00859 00860 *width = w; 00861 *height = h; 00862 return 0; 00863 } 00864 00865 uint8_t dvdnav_get_video_scale_permission(dvdnav_t *this) { 00866 uint8_t retval; 00867 00868 if(!this->started) { 00869 printerr("Virtual DVD machine not started."); 00870 return -1; 00871 } 00872 00873 pthread_mutex_lock(&this->vm_lock); 00874 retval = (uint8_t)vm_get_video_scale_permission(this->vm); 00875 pthread_mutex_unlock(&this->vm_lock); 00876 00877 return retval; 00878 } 00879 00880 uint8_t dvdnav_get_video_format(dvdnav_t *this) { 00881 uint8_t retval; 00882 00883 if(!this) { 00884 printerr("Passed a NULL pointer."); 00885 return -1; 00886 } 00887 if(!this->started) { 00888 printerr("Virtual DVD machine not started."); 00889 return -1; 00890 } 00891 00892 pthread_mutex_lock(&this->vm_lock); 00893 retval = (uint8_t)vm_get_video_format(this->vm); 00894 pthread_mutex_unlock(&this->vm_lock); 00895 00896 return retval; 00897 } 00898 00899 uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *this, uint8_t stream) { 00900 audio_attr_t attr; 00901 00902 if(!this->started) { 00903 printerr("Virtual DVD machine not started."); 00904 return -1; 00905 } 00906 00907 pthread_mutex_lock(&this->vm_lock); 00908 attr = vm_get_audio_attr(this->vm, stream); 00909 pthread_mutex_unlock(&this->vm_lock); 00910 00911 if(attr.lang_type != 1) 00912 return 0xffff; 00913 00914 return attr.lang_code; 00915 } 00916 00917 uint16_t dvdnav_audio_stream_format(dvdnav_t *this, uint8_t stream) { 00918 audio_attr_t attr; 00919 uint16_t format; 00920 00921 if(!this->started) { 00922 printerr("Virtual DVD machine not started."); 00923 return -1; /* 0xffff */ 00924 } 00925 00926 pthread_mutex_lock(&this->vm_lock); 00927 attr = vm_get_audio_attr(this->vm, stream); 00928 pthread_mutex_unlock(&this->vm_lock); 00929 00930 switch(attr.audio_format) { 00931 case 0: 00932 format = DVDNAV_FORMAT_AC3; 00933 break; 00934 case 2: /* MPEG-1 or MPEG-2 without extension bitstream. */ 00935 case 3: /* MPEG-2 with extension bitstream. */ 00936 format = DVDNAV_FORMAT_MPEGAUDIO; 00937 break; 00938 case 4: 00939 format = DVDNAV_FORMAT_LPCM; 00940 break; 00941 case 6: 00942 format = DVDNAV_FORMAT_DTS; 00943 break; 00944 case 7: 00945 format = DVDNAV_FORMAT_SDDS; 00946 break; 00947 default: 00948 format = 0xffff; 00949 break; 00950 } 00951 00952 return format; 00953 } 00954 00955 uint16_t dvdnav_audio_stream_channels(dvdnav_t *this, uint8_t stream) { 00956 audio_attr_t attr; 00957 00958 if(!this->started) { 00959 printerr("Virtual DVD machine not started."); 00960 return -1; /* 0xffff */ 00961 } 00962 00963 pthread_mutex_lock(&this->vm_lock); 00964 attr = vm_get_audio_attr(this->vm, stream); 00965 pthread_mutex_unlock(&this->vm_lock); 00966 00967 return attr.channels + 1; 00968 } 00969 00970 uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *this, uint8_t stream) { 00971 subp_attr_t attr; 00972 00973 if(!this->started) { 00974 printerr("Virtual DVD machine not started."); 00975 return -1; 00976 } 00977 00978 pthread_mutex_lock(&this->vm_lock); 00979 attr = vm_get_subp_attr(this->vm, stream); 00980 pthread_mutex_unlock(&this->vm_lock); 00981 00982 if(attr.type != 1) 00983 return 0xffff; 00984 00985 return attr.lang_code; 00986 } 00987 00988 int8_t dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) { 00989 int8_t retval; 00990 00991 if(!this->started) { 00992 printerr("Virtual DVD machine not started."); 00993 return -1; 00994 } 00995 00996 pthread_mutex_lock(&this->vm_lock); 00997 if (!this->vm->state.pgc) { 00998 printerr("No current PGC."); 00999 pthread_mutex_unlock(&this->vm_lock); 01000 return -1; 01001 } 01002 retval = vm_get_audio_stream(this->vm, audio_num); 01003 pthread_mutex_unlock(&this->vm_lock); 01004 01005 return retval; 01006 } 01007 01008 dvdnav_status_t dvdnav_get_audio_attr(dvdnav_t *this, uint8_t audio_num, audio_attr_t *audio_attr) { 01009 if(!this->started) { 01010 printerr("Virtual DVD machine not started."); 01011 return -1; 01012 } 01013 pthread_mutex_lock(&this->vm_lock); 01014 if (!this->vm->state.pgc) { 01015 printerr("No current PGC."); 01016 pthread_mutex_unlock(&this->vm_lock); 01017 return -1; 01018 } 01019 *audio_attr=vm_get_audio_attr(this->vm, audio_num); 01020 pthread_mutex_unlock(&this->vm_lock); 01021 01022 return DVDNAV_STATUS_OK; 01023 } 01024 01025 int8_t dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) { 01026 int8_t retval; 01027 01028 if(!this->started) { 01029 printerr("Virtual DVD machine not started."); 01030 return -1; 01031 } 01032 01033 pthread_mutex_lock(&this->vm_lock); 01034 if (!this->vm->state.pgc) { 01035 printerr("No current PGC."); 01036 pthread_mutex_unlock(&this->vm_lock); 01037 return -1; 01038 } 01039 retval = vm_get_subp_stream(this->vm, subp_num, 0); 01040 pthread_mutex_unlock(&this->vm_lock); 01041 01042 return retval; 01043 } 01044 01045 dvdnav_status_t dvdnav_get_spu_attr(dvdnav_t *this, uint8_t audio_num, subp_attr_t *subp_attr) { 01046 if(!this->started) { 01047 printerr("Virtual DVD machine not started."); 01048 return -1; 01049 } 01050 pthread_mutex_lock(&this->vm_lock); 01051 if (!this->vm->state.pgc) { 01052 printerr("No current PGC."); 01053 pthread_mutex_unlock(&this->vm_lock); 01054 return -1; 01055 } 01056 *subp_attr=vm_get_subp_attr(this->vm, audio_num); 01057 pthread_mutex_unlock(&this->vm_lock); 01058 return DVDNAV_STATUS_OK; 01059 } 01060 01061 int8_t dvdnav_get_active_audio_stream(dvdnav_t *this) { 01062 int8_t retval; 01063 01064 if(!this->started) { 01065 printerr("Virtual DVD machine not started."); 01066 return -1; 01067 } 01068 01069 pthread_mutex_lock(&this->vm_lock); 01070 if (!this->vm->state.pgc) { 01071 printerr("No current PGC."); 01072 pthread_mutex_unlock(&this->vm_lock); 01073 return -1; 01074 } 01075 retval = vm_get_audio_active_stream(this->vm); 01076 pthread_mutex_unlock(&this->vm_lock); 01077 01078 return retval; 01079 } 01080 01081 int8_t dvdnav_set_active_audio_stream(dvdnav_t *this, int8_t stream) { 01082 int8_t retval; 01083 01084 if(!this->started) { 01085 printerr("Virtual DVD machine not started."); 01086 return -1; 01087 } 01088 01089 pthread_mutex_lock(&this->vm_lock); 01090 if (!this->vm->state.pgc) { 01091 printerr("No current PGC."); 01092 pthread_mutex_unlock(&this->vm_lock); 01093 return -1; 01094 } 01095 01096 retval = vm_set_audio_active_stream(this->vm, stream); 01097 pthread_mutex_unlock(&this->vm_lock); 01098 01099 return retval; 01100 } 01101 01102 int8_t dvdnav_get_active_spu_stream(dvdnav_t *this) { 01103 int8_t retval; 01104 01105 if(!this->started) { 01106 printerr("Virtual DVD machine not started."); 01107 return -1; 01108 } 01109 01110 pthread_mutex_lock(&this->vm_lock); 01111 if (!this->vm->state.pgc) { 01112 printerr("No current PGC."); 01113 pthread_mutex_unlock(&this->vm_lock); 01114 return -1; 01115 } 01116 retval = vm_get_subp_active_stream(this->vm, 0); 01117 pthread_mutex_unlock(&this->vm_lock); 01118 01119 return retval; 01120 } 01121 01122 static int8_t dvdnav_is_domain(dvdnav_t *this, domain_t domain) { 01123 int8_t retval; 01124 01125 if(!this->started) { 01126 printerr("Virtual DVD machine not started."); 01127 return -1; 01128 } 01129 01130 pthread_mutex_lock(&this->vm_lock); 01131 retval = (this->vm->state.domain == domain); 01132 pthread_mutex_unlock(&this->vm_lock); 01133 01134 return retval; 01135 } 01136 01137 /* First Play domain. (Menu) */ 01138 int8_t dvdnav_is_domain_fp(dvdnav_t *this) { 01139 return dvdnav_is_domain(this, FP_DOMAIN); 01140 } 01141 /* Video management Menu domain. (Menu) */ 01142 int8_t dvdnav_is_domain_vmgm(dvdnav_t *this) { 01143 return dvdnav_is_domain(this, VMGM_DOMAIN); 01144 } 01145 /* Video Title Menu domain (Menu) */ 01146 int8_t dvdnav_is_domain_vtsm(dvdnav_t *this) { 01147 return dvdnav_is_domain(this, VTSM_DOMAIN); 01148 } 01149 /* Video Title domain (playing movie). */ 01150 int8_t dvdnav_is_domain_vts(dvdnav_t *this) { 01151 return dvdnav_is_domain(this, VTS_DOMAIN); 01152 } 01153 01154 /* Generally delegate angle information handling to VM */ 01155 dvdnav_status_t dvdnav_angle_change(dvdnav_t *this, int32_t angle) { 01156 int32_t num, current; 01157 01158 pthread_mutex_lock(&this->vm_lock); 01159 vm_get_angle_info(this->vm, ¤t, &num); 01160 /* Set angle SPRM if valid */ 01161 if((angle > 0) && (angle <= num)) { 01162 this->vm->state.AGL_REG = angle; 01163 } else { 01164 printerr("Passed an invalid angle number."); 01165 pthread_mutex_unlock(&this->vm_lock); 01166 return DVDNAV_STATUS_ERR; 01167 } 01168 pthread_mutex_unlock(&this->vm_lock); 01169 01170 return DVDNAV_STATUS_OK; 01171 } 01172 01173 dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *this, int32_t *current_angle, 01174 int32_t *number_of_angles) { 01175 pthread_mutex_lock(&this->vm_lock); 01176 vm_get_angle_info(this->vm, current_angle, number_of_angles); 01177 pthread_mutex_unlock(&this->vm_lock); 01178 01179 return DVDNAV_STATUS_OK; 01180 } 01181 01182 pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) { 01183 if(!this) return 0; 01184 return &this->pci; 01185 } 01186 01187 dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) { 01188 if(!this) return 0; 01189 return &this->dsi; 01190 } 01191 01192 uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) { 01193 if(!this) return -1; 01194 return this->position_next.still; 01195 } 01196 01197 user_ops_t dvdnav_get_restrictions(dvdnav_t* this) { 01198 /* 01199 * user_ops_t is a structure of 32 bits. We want to compute 01200 * the union of two of those bitfields so to make this quicker 01201 * than performing 32 ORs, we will access them as 32bits words. 01202 */ 01203 union { 01204 user_ops_t ops_struct; 01205 uint32_t ops_int; 01206 } ops; 01207 01208 ops.ops_int = 0; 01209 01210 if(!this->started) { 01211 printerr("Virtual DVD machine not started."); 01212 return ops.ops_struct; 01213 } 01214 01215 pthread_mutex_lock(&this->vm_lock); 01216 ops.ops_int |= *(uint32_t*)&this->pci.pci_gi.vobu_uop_ctl; 01217 01218 if(this->vm && this->vm->state.pgc) 01219 ops.ops_int |= *(uint32_t*)&this->vm->state.pgc->prohibited_ops; 01220 pthread_mutex_unlock(&this->vm_lock); 01221 01222 return ops.ops_struct; 01223 }
1.7.6.1