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
00026
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>
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
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
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
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) ) );
00086
00087 pthread_mutex_init(&this->vm_lock, NULL);
00088
00089 printerr("");
00090
00091
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
00108 strncpy(this->path, path, MAX_PATH_LEN - 1);
00109 this->path[MAX_PATH_LEN - 1] = '\0';
00110
00111
00112 this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS);
00113
00114
00115 this->cache = dvdnav_read_cache_new(this);
00116
00117
00118
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
00145 if(this->vm)
00146 vm_free_vm(this->vm);
00147
00148 pthread_mutex_destroy(&this->vm_lock);
00149
00150
00151
00152
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
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
00226
00227
00228
00229
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) {
00238 int32_t nStuffingBytes;
00239
00240 bMpeg1 = (p[4] & 0x40) == 0;
00241
00242 if (bMpeg1) {
00243 p += 12;
00244 } else {
00245 nStuffingBytes = p[0xD] & 0x07;
00246 p += 14 + nStuffingBytes;
00247 }
00248 }
00249
00250 if (p[3] == 0xbb) {
00251 nHeaderLen = (p[4] << 8) | p[5];
00252 p += 6 + nHeaderLen;
00253 }
00254
00255
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) {
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
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
00294
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;
00301 vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea;
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 #if 0
00316
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
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
00330 #if 0
00331 if((num_angle < angle) && (angle != 1)) {
00332 fprintf(MSG_OUT, "libdvdnav: angle ends!\n");
00333
00334
00335
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
00364
00365
00366
00367
00368
00369
00370
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
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
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
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
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
00454 vm_get_angle_info(this->vm, ¤t, &num_angles);
00455 if (num_angles > 1) {
00456 int32_t result, block;
00457
00458
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
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
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
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
00484 this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block;
00485 this->vobu.vobu_next = 0;
00486
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
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
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
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
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
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
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;
00580 this->position_current.spu_channel = -1;
00581 this->position_current.audio_channel = -1; ;
00582
00583 pthread_mutex_unlock(&this->vm_lock);
00584 return DVDNAV_STATUS_OK;
00585 }
00586
00587
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
00609 first_cell_nr = state->pgc->program_map[state->pgN-1];
00610
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
00636 this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block;
00637 this->vobu.vobu_next = 0;
00638
00639 this->vobu.vobu_length = 0;
00640 this->vobu.blockN = 0;
00641
00642
00643 this->spu_clut_changed = 1;
00644 this->position_current.spu_channel = -1;
00645 this->position_current.audio_channel = -1;
00646
00647 pthread_mutex_unlock(&this->vm_lock);
00648 return DVDNAV_STATUS_OK;
00649 }
00650
00651
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
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
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
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
00721 if (this->vobu.blockN >= this->vobu.vobu_length) {
00722
00723
00724 if(this->vobu.vobu_next == SRI_END_OF_CELL) {
00725
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
00732
00733
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
00739 vm_get_next_cell(this->vm);
00740 this->position_current.still = 0;
00741 this->skip_still = 0;
00742 this->sync_wait_skip = 0;
00743 }
00744 }
00745
00746 (*event) = DVDNAV_NOP;
00747 (*len) = 0;
00748 pthread_mutex_unlock(&this->vm_lock);
00749 return DVDNAV_STATUS_OK;
00750 }
00751
00752
00753
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
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
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
00776
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
00783
00784
00785 dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1);
00786
00787
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
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
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;
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:
00935 case 3:
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;
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
01138 int8_t dvdnav_is_domain_fp(dvdnav_t *this) {
01139 return dvdnav_is_domain(this, FP_DOMAIN);
01140 }
01141
01142 int8_t dvdnav_is_domain_vmgm(dvdnav_t *this) {
01143 return dvdnav_is_domain(this, VMGM_DOMAIN);
01144 }
01145
01146 int8_t dvdnav_is_domain_vtsm(dvdnav_t *this) {
01147 return dvdnav_is_domain(this, VTSM_DOMAIN);
01148 }
01149
01150 int8_t dvdnav_is_domain_vts(dvdnav_t *this) {
01151 return dvdnav_is_domain(this, VTS_DOMAIN);
01152 }
01153
01154
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
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
01200
01201
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 }