00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025
00026
00027
00028
00029
00030 #include "dvdnav_internal.h"
00031 #include "read_cache.h"
00032 #include "nav_read.h"
00033
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036
00037
00038 #ifndef _WIN32
00039 #include <sys/time.h>
00040 #endif
00041
00042 #include "remap.h"
00043
00044 static dvdnav_status_t dvdnav_clear(dvdnav_t * this) {
00045
00046
00047 if (this->file) DVDCloseFile(this->file);
00048 this->file = NULL;
00049
00050 memset(&this->pci,0,sizeof(this->pci));
00051 memset(&this->dsi,0,sizeof(this->dsi));
00052 this->last_cmd_nav_lbn = SRI_END_OF_CELL;
00053
00054
00055 this->position_current.still = 0;
00056 this->skip_still = 0;
00057 this->sync_wait = 0;
00058 this->sync_wait_skip = 0;
00059 this->spu_clut_changed = 0;
00060 this->started = 0;
00061
00062 dvdnav_read_cache_clear(this->cache);
00063
00064 return DVDNAV_STATUS_OK;
00065 }
00066
00067 dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) {
00068 dvdnav_t *this;
00069 struct timeval time;
00070
00071
00072 fprintf(MSG_OUT, "libdvdnav: Using dvdnav version %s from http://xine.sf.net\n", "0.1.10-xine");
00073
00074 (*dest) = NULL;
00075 this = (dvdnav_t*)malloc(sizeof(dvdnav_t));
00076 if(!this)
00077 return DVDNAV_STATUS_ERR;
00078 memset(this, 0, (sizeof(dvdnav_t) ) );
00079
00080 pthread_mutex_init(&this->vm_lock, NULL);
00081
00082 printerr("");
00083
00084
00085 this->vm = vm_new_vm();
00086 if(!this->vm) {
00087 printerr("Error initialising the DVD VM.");
00088 pthread_mutex_destroy(&this->vm_lock);
00089 free(this);
00090 return DVDNAV_STATUS_ERR;
00091 }
00092 if(!vm_reset(this->vm, path)) {
00093 printerr("Error starting the VM / opening the DVD device.");
00094 pthread_mutex_destroy(&this->vm_lock);
00095 vm_free_vm(this->vm);
00096 free(this);
00097 return DVDNAV_STATUS_ERR;
00098 }
00099
00100
00101 strncpy(this->path, path, MAX_PATH_LEN);
00102
00103
00104 this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), 0, DVD_READ_MENU_VOBS);
00105
00106
00107 this->cache = dvdnav_read_cache_new(this);
00108
00109
00110
00111 gettimeofday(&time, NULL);
00112 srand(time.tv_usec);
00113
00114 dvdnav_clear(this);
00115
00116 (*dest) = this;
00117 return DVDNAV_STATUS_OK;
00118 }
00119
00120 dvdnav_status_t dvdnav_close(dvdnav_t *this) {
00121
00122 #ifdef LOG_DEBUG
00123 fprintf(MSG_OUT, "libdvdnav: close:called\n");
00124 #endif
00125
00126 if(!this) {
00127 printerr("Passed a NULL pointer.");
00128 return DVDNAV_STATUS_ERR;
00129 }
00130
00131 if (this->file) {
00132 DVDCloseFile(this->file);
00133 #ifdef LOG_DEBUG
00134 fprintf(MSG_OUT, "libdvdnav: close:file closing\n");
00135 #endif
00136 this->file = NULL;
00137 }
00138
00139
00140 if(this->vm)
00141 vm_free_vm(this->vm);
00142
00143 pthread_mutex_destroy(&this->vm_lock);
00144
00145
00146
00147
00148 if(this->cache)
00149 dvdnav_read_cache_free(this->cache);
00150 else
00151 free(this);
00152
00153 return DVDNAV_STATUS_OK;
00154 }
00155
00156 dvdnav_status_t dvdnav_reset(dvdnav_t *this) {
00157 dvdnav_status_t result;
00158
00159 #ifdef LOG_DEBUG
00160 fprintf(MSG_OUT, "libdvdnav: reset:called\n");
00161 #endif
00162
00163 if(!this) {
00164 printerr("Passed a NULL pointer.");
00165 return DVDNAV_STATUS_ERR;
00166 }
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 result = dvdnav_clear(this);
00182
00183 pthread_mutex_unlock(&this->vm_lock);
00184 return result;
00185 }
00186
00187 dvdnav_status_t dvdnav_path(dvdnav_t *this, const char** path) {
00188
00189 if(!this || !path) {
00190 printerr("Passed a NULL pointer.");
00191 return DVDNAV_STATUS_ERR;
00192 }
00193
00194 (*path) = this->path;
00195
00196 return DVDNAV_STATUS_OK;
00197 }
00198
00199 const char* dvdnav_err_to_string(dvdnav_t *this) {
00200
00201 if(!this)
00202 return "Hey! You gave me a NULL pointer you naughty person!";
00203
00204 return this->err_str;
00205 }
00206
00207
00208 int64_t dvdnav_convert_time(dvd_time_t *time) {
00209 int64_t result;
00210 int64_t frames;
00211
00212 result = (time->hour >> 4 ) * 10 * 60 * 60 * 90000;
00213 result += (time->hour & 0x0f) * 60 * 60 * 90000;
00214 result += (time->minute >> 4 ) * 10 * 60 * 90000;
00215 result += (time->minute & 0x0f) * 60 * 90000;
00216 result += (time->second >> 4 ) * 10 * 90000;
00217 result += (time->second & 0x0f) * 90000;
00218
00219 frames = ((time->frame_u & 0x30) >> 4) * 10;
00220 frames += ((time->frame_u & 0x0f) ) ;
00221
00222 if (time->frame_u & 0x80)
00223 result += frames * 3000;
00224 else
00225 result += frames * 3600;
00226
00227 return result;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237 static int32_t dvdnav_decode_packet(dvdnav_t *this, uint8_t *p, dsi_t *nav_dsi, pci_t *nav_pci) {
00238 int32_t bMpeg1 = 0;
00239 uint32_t nHeaderLen;
00240 uint32_t nPacketLen;
00241 uint32_t nStreamID;
00242
00243 if (p[3] == 0xBA) {
00244 int32_t nStuffingBytes;
00245
00246 bMpeg1 = (p[4] & 0x40) == 0;
00247
00248 if (bMpeg1) {
00249 p += 12;
00250 } else {
00251 nStuffingBytes = p[0xD] & 0x07;
00252 p += 14 + nStuffingBytes;
00253 }
00254 }
00255
00256 if (p[3] == 0xbb) {
00257 nHeaderLen = (p[4] << 8) | p[5];
00258 p += 6 + nHeaderLen;
00259 }
00260
00261
00262 if (p[0] || p[1] || (p[2] != 1)) {
00263 fprintf(MSG_OUT, "libdvdnav: demux error! %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]);
00264 return 0;
00265 }
00266
00267 nPacketLen = p[4] << 8 | p[5];
00268 nStreamID = p[3];
00269
00270 nHeaderLen = 6;
00271 p += nHeaderLen;
00272
00273 if (nStreamID == 0xbf) {
00274 #if 0
00275 int32_t i;
00276 fprintf(MSG_OUT, "libdvdnav: nav packet=%u\n",p-p_start-6);
00277 for(i=0;i<80;i++)
00278 fprintf(MSG_OUT, "%02x ",p[i-6]);
00279 fprintf(MSG_OUT, "\n");
00280 #endif
00281
00282 if(p[0] == 0x00) {
00283 navRead_PCI(nav_pci, p+1);
00284 }
00285
00286 p += nPacketLen;
00287
00288
00289 if(p[6] == 0x01) {
00290 nPacketLen = p[4] << 8 | p[5];
00291 p += 6;
00292 navRead_DSI(nav_dsi, p+1);
00293 }
00294 return 1;
00295 }
00296 return 0;
00297 }
00298
00299
00300
00301
00302 static int32_t dvdnav_get_vobu(dvdnav_t *this, dsi_t *nav_dsi, pci_t *nav_pci, dvdnav_vobu_t *vobu) {
00303 uint32_t next;
00304 int32_t angle, num_angle;
00305
00306 vobu->vobu_start = nav_dsi->dsi_gi.nv_pck_lbn;
00307 vobu->vobu_length = nav_dsi->dsi_gi.vobu_ea;
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 #if 0
00322
00323 if(nav_dsi->vobu_sri.next_vobu != SRI_END_OF_CELL ) {
00324 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
00325 } else {
00326 vobu->vobu_next = vobu->vobu_length;
00327 }
00328 #else
00329
00330 vobu->vobu_next = ( nav_dsi->vobu_sri.next_vobu & 0x3fffffff );
00331 #endif
00332
00333 vm_get_angle_info(this->vm, &angle, &num_angle);
00334
00335
00336 #if 0
00337 if((num_angle < angle) && (angle != 1)) {
00338 fprintf(MSG_OUT, "libdvdnav: angle ends!\n");
00339
00340
00341
00342 dvdnav_angle_change(this, 1);
00343 }
00344 #endif
00345
00346 if(num_angle != 0) {
00347
00348 if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) {
00349 if((next & 0x3fffffff) != 0) {
00350 if(next & 0x80000000)
00351 vobu->vobu_next = - (int32_t)(next & 0x3fffffff);
00352 else
00353 vobu->vobu_next = + (int32_t)(next & 0x3fffffff);
00354 }
00355 } else if((next = nav_dsi->sml_agli.data[angle-1].address) != 0) {
00356 vobu->vobu_length = nav_dsi->sml_pbi.ilvu_ea;
00357
00358 if((next & 0x80000000) && (next != 0x7fffffff))
00359 vobu->vobu_next = - (int32_t)(next & 0x3fffffff);
00360 else
00361 vobu->vobu_next = + (int32_t)(next & 0x3fffffff);
00362 }
00363 }
00364
00365 return 1;
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 dvdnav_status_t dvdnav_get_next_block(dvdnav_t *this, uint8_t *buf,
00380 int32_t *event, int32_t *len) {
00381 unsigned char *block;
00382 dvdnav_status_t status;
00383
00384 block = buf;
00385 status = dvdnav_get_next_cache_block(this, &block, event, len);
00386 if (status == DVDNAV_STATUS_OK && block != buf) {
00387
00388 memcpy(buf, block, DVD_VIDEO_LB_LEN);
00389 dvdnav_free_cache_block(this, block);
00390 }
00391 return status;
00392 }
00393
00394 dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *this, uint8_t **buf,
00395 int32_t *event, int32_t *len) {
00396 dvd_state_t *state;
00397 int32_t result;
00398
00399 if(!this || !event || !len || !buf || !*buf) {
00400 printerr("Passed a NULL pointer.");
00401 return DVDNAV_STATUS_ERR;
00402 }
00403
00404 pthread_mutex_lock(&this->vm_lock);
00405
00406 if(!this->started) {
00407
00408 if (!vm_start(this->vm)) {
00409 pthread_mutex_unlock(&this->vm_lock);
00410 printerr("Encrypted or faulty DVD");
00411 return DVDNAV_STATUS_ERR;
00412 }
00413 this->started = 1;
00414 }
00415
00416 state = &(this->vm->state);
00417 (*event) = DVDNAV_NOP;
00418 (*len) = 0;
00419
00420
00421 if(this->vm->stopped) {
00422 vm_stop(this->vm);
00423 (*event) = DVDNAV_STOP;
00424 this->started = 0;
00425 pthread_mutex_unlock(&this->vm_lock);
00426 return DVDNAV_STATUS_OK;
00427 }
00428
00429 vm_position_get(this->vm, &this->position_next);
00430
00431 #ifdef LOG_DEBUG
00432 fprintf(MSG_OUT, "libdvdnav: POS-NEXT ");
00433 vm_position_print(this->vm, &this->position_next);
00434 fprintf(MSG_OUT, "libdvdnav: POS-CUR ");
00435 vm_position_print(this->vm, &this->position_current);
00436 #endif
00437
00438
00439 if(this->position_current.hop_channel != this->position_next.hop_channel) {
00440 (*event) = DVDNAV_HOP_CHANNEL;
00441 #ifdef LOG_DEBUG
00442 fprintf(MSG_OUT, "libdvdnav: HOP_CHANNEL\n");
00443 #endif
00444 if (this->position_next.hop_channel - this->position_current.hop_channel >= HOP_SEEK) {
00445 int32_t num_angles = 0, current;
00446
00447
00448 vm_get_angle_info(this->vm, ¤t, &num_angles);
00449 if (num_angles > 1) {
00450 int32_t result, block;
00451
00452
00453 block = this->position_next.cell_start + this->position_next.block;
00454 result = dvdnav_read_cache_block(this->cache, block, 1, buf);
00455 if(result <= 0) {
00456 printerr("Error reading NAV packet.");
00457 pthread_mutex_unlock(&this->vm_lock);
00458 return DVDNAV_STATUS_ERR;
00459 }
00460
00461 if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
00462 printerr("Expected NAV packet but none found.");
00463 pthread_mutex_unlock(&this->vm_lock);
00464 return DVDNAV_STATUS_ERR;
00465 }
00466 dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
00467
00468 if (this->vobu.vobu_next != SRI_END_OF_CELL) {
00469 this->vobu.vobu_start += this->vobu.vobu_next;
00470 this->vobu.vobu_next = 0;
00471 }
00472
00473 this->vm->state.blockN = this->vobu.vobu_start - this->position_next.cell_start;
00474 }
00475 }
00476 this->position_current.hop_channel = this->position_next.hop_channel;
00477
00478 this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block;
00479 this->vobu.vobu_next = 0;
00480
00481 this->vobu.vobu_length = 0;
00482 this->vobu.blockN = 0;
00483 this->sync_wait = 0;
00484 pthread_mutex_unlock(&this->vm_lock);
00485 return DVDNAV_STATUS_OK;
00486 }
00487
00488
00489 if(this->position_current.button != this->position_next.button) {
00490 dvdnav_highlight_event_t *hevent = (dvdnav_highlight_event_t *)*buf;
00491
00492 (*event) = DVDNAV_HIGHLIGHT;
00493 #ifdef LOG_DEBUG
00494 fprintf(MSG_OUT, "libdvdnav: HIGHLIGHT\n");
00495 #endif
00496 (*len) = sizeof(dvdnav_highlight_event_t);
00497 hevent->display = 1;
00498 hevent->buttonN = this->position_next.button;
00499 this->position_current.button = this->position_next.button;
00500 pthread_mutex_unlock(&this->vm_lock);
00501 return DVDNAV_STATUS_OK;
00502 }
00503
00504
00505 if(this->sync_wait) {
00506 (*event) = DVDNAV_WAIT;
00507 #ifdef LOG_DEBUG
00508 fprintf(MSG_OUT, "libdvdnav: WAIT\n");
00509 #endif
00510 (*len) = 0;
00511 pthread_mutex_unlock(&this->vm_lock);
00512 return DVDNAV_STATUS_OK;
00513 }
00514
00515
00516 if((this->position_current.vts != this->position_next.vts) ||
00517 (this->position_current.domain != this->position_next.domain)) {
00518 dvd_read_domain_t domain;
00519 int32_t vtsN;
00520 dvdnav_vts_change_event_t *vts_event = (dvdnav_vts_change_event_t *)*buf;
00521
00522 if(this->file) {
00523 DVDCloseFile(this->file);
00524 this->file = NULL;
00525 }
00526
00527 vts_event->old_vtsN = this->position_current.vts;
00528 vts_event->old_domain = this->position_current.domain;
00529
00530
00531 switch(this->position_next.domain) {
00532 case FP_DOMAIN:
00533 case VMGM_DOMAIN:
00534 domain = DVD_READ_MENU_VOBS;
00535 vtsN = 0;
00536 break;
00537 case VTSM_DOMAIN:
00538 domain = DVD_READ_MENU_VOBS;
00539 vtsN = this->position_next.vts;
00540 break;
00541 case VTS_DOMAIN:
00542 domain = DVD_READ_TITLE_VOBS;
00543 vtsN = this->position_next.vts;
00544 break;
00545 default:
00546 printerr("Unknown domain when changing VTS.");
00547 pthread_mutex_unlock(&this->vm_lock);
00548 return DVDNAV_STATUS_ERR;
00549 }
00550
00551 this->position_current.vts = this->position_next.vts;
00552 this->position_current.domain = this->position_next.domain;
00553 dvdnav_read_cache_clear(this->cache);
00554 this->file = DVDOpenFile(vm_get_dvd_reader(this->vm), vtsN, domain);
00555 vts_event->new_vtsN = this->position_next.vts;
00556 vts_event->new_domain = this->position_next.domain;
00557
00558
00559 if(this->file == NULL) {
00560 printerrf("Error opening vtsN=%i, domain=%i.", vtsN, domain);
00561 pthread_mutex_unlock(&this->vm_lock);
00562 return DVDNAV_STATUS_ERR;
00563 }
00564
00565
00566 (*event) = DVDNAV_VTS_CHANGE;
00567 #ifdef LOG_DEBUG
00568 fprintf(MSG_OUT, "libdvdnav: VTS_CHANGE\n");
00569 #endif
00570 (*len) = sizeof(dvdnav_vts_change_event_t);
00571
00572 this->spu_clut_changed = 1;
00573 this->position_current.cell = -1;
00574 this->position_current.spu_channel = -1;
00575 this->position_current.audio_channel = -1; ;
00576
00577 pthread_mutex_unlock(&this->vm_lock);
00578 return DVDNAV_STATUS_OK;
00579 }
00580
00581
00582 if( (this->position_current.cell != this->position_next.cell) ||
00583 (this->position_current.cell_restart != this->position_next.cell_restart) ||
00584 (this->position_current.cell_start != this->position_next.cell_start) ) {
00585 dvdnav_cell_change_event_t *cell_event = (dvdnav_cell_change_event_t *)*buf;
00586 int32_t first_cell_nr, last_cell_nr, i;
00587 dvd_state_t *state = &this->vm->state;
00588
00589 (*event) = DVDNAV_CELL_CHANGE;
00590 #ifdef LOG_DEBUG
00591 fprintf(MSG_OUT, "libdvdnav: CELL_CHANGE\n");
00592 #endif
00593 (*len) = sizeof(dvdnav_cell_change_event_t);
00594
00595 cell_event->cellN = state->cellN;
00596 cell_event->pgN = state->pgN;
00597 cell_event->cell_length =
00598 dvdnav_convert_time(&state->pgc->cell_playback[state->cellN-1].playback_time);
00599
00600 cell_event->pg_length = 0;
00601
00602 first_cell_nr = state->pgc->program_map[state->pgN-1];
00603
00604 if(state->pgN < state->pgc->nr_of_programs)
00605 last_cell_nr = state->pgc->program_map[state->pgN] - 1;
00606 else
00607 last_cell_nr = state->pgc->nr_of_cells;
00608 for (i = first_cell_nr; i <= last_cell_nr; i++)
00609 cell_event->pg_length +=
00610 dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
00611 cell_event->pgc_length = dvdnav_convert_time(&state->pgc->playback_time);
00612
00613 cell_event->cell_start = 0;
00614 for (i = 1; i < state->cellN; i++)
00615 cell_event->cell_start +=
00616 dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
00617
00618 cell_event->pg_start = 0;
00619 for (i = 1; i < state->pgc->program_map[state->pgN-1]; i++)
00620 cell_event->pg_start +=
00621 dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
00622
00623 this->position_current.cell = this->position_next.cell;
00624 this->position_current.cell_restart = this->position_next.cell_restart;
00625 this->position_current.cell_start = this->position_next.cell_start;
00626 this->position_current.block = this->position_next.block;
00627
00628
00629 this->vobu.vobu_start = this->position_next.cell_start + this->position_next.block;
00630 this->vobu.vobu_next = 0;
00631
00632 this->vobu.vobu_length = 0;
00633 this->vobu.blockN = 0;
00634
00635
00636 this->spu_clut_changed = 1;
00637 this->position_current.spu_channel = -1;
00638 this->position_current.audio_channel = -1;
00639
00640 pthread_mutex_unlock(&this->vm_lock);
00641 return DVDNAV_STATUS_OK;
00642 }
00643
00644
00645 if(this->spu_clut_changed) {
00646 (*event) = DVDNAV_SPU_CLUT_CHANGE;
00647 #ifdef LOG_DEBUG
00648 fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n");
00649 #endif
00650 (*len) = 16 * sizeof(uint32_t);
00651 memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
00652 this->spu_clut_changed = 0;
00653 pthread_mutex_unlock(&this->vm_lock);
00654 return DVDNAV_STATUS_OK;
00655 }
00656
00657
00658 if(this->position_current.spu_channel != this->position_next.spu_channel) {
00659 dvdnav_spu_stream_change_event_t *stream_change = (dvdnav_spu_stream_change_event_t *)*buf;
00660
00661 (*event) = DVDNAV_SPU_STREAM_CHANGE;
00662 #ifdef LOG_DEBUG
00663 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE\n");
00664 #endif
00665 (*len) = sizeof(dvdnav_spu_stream_change_event_t);
00666 stream_change->physical_wide = vm_get_subp_active_stream(this->vm, 0);
00667 stream_change->physical_letterbox = vm_get_subp_active_stream(this->vm, 1);
00668 stream_change->physical_pan_scan = vm_get_subp_active_stream(this->vm, 2);
00669 this->position_current.spu_channel = this->position_next.spu_channel;
00670 #ifdef LOG_DEBUG
00671 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_wide=%d\n",stream_change->physical_wide);
00672 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_letterbox=%d\n",stream_change->physical_letterbox);
00673 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE stream_id_pan_scan=%d\n",stream_change->physical_pan_scan);
00674 fprintf(MSG_OUT, "libdvdnav: SPU_STREAM_CHANGE returning DVDNAV_STATUS_OK\n");
00675 #endif
00676 pthread_mutex_unlock(&this->vm_lock);
00677 return DVDNAV_STATUS_OK;
00678 }
00679
00680
00681 if(this->position_current.audio_channel != this->position_next.audio_channel) {
00682 dvdnav_audio_stream_change_event_t *stream_change = (dvdnav_audio_stream_change_event_t *)*buf;
00683
00684 (*event) = DVDNAV_AUDIO_STREAM_CHANGE;
00685 #ifdef LOG_DEBUG
00686 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE\n");
00687 #endif
00688 (*len) = sizeof(dvdnav_audio_stream_change_event_t);
00689 stream_change->physical = vm_get_audio_active_stream( this->vm );
00690 this->position_current.audio_channel = this->position_next.audio_channel;
00691 #ifdef LOG_DEBUG
00692 fprintf(MSG_OUT, "libdvdnav: AUDIO_STREAM_CHANGE stream_id=%d returning DVDNAV_STATUS_OK\n",stream_change->physical);
00693 #endif
00694 pthread_mutex_unlock(&this->vm_lock);
00695 return DVDNAV_STATUS_OK;
00696 }
00697
00698
00699 if(this->position_current.still != 0) {
00700 dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)*buf;
00701
00702 (*event) = DVDNAV_STILL_FRAME;
00703 #ifdef LOG_DEBUG
00704 fprintf(MSG_OUT, "libdvdnav: STILL_FRAME\n");
00705 #endif
00706 (*len) = sizeof(dvdnav_still_event_t);
00707 still_event->length = this->position_current.still;
00708 pthread_mutex_unlock(&this->vm_lock);
00709 return DVDNAV_STATUS_OK;
00710 }
00711
00712
00713 if (this->vobu.blockN >= this->vobu.vobu_length) {
00714
00715
00716 if(this->vobu.vobu_next == SRI_END_OF_CELL) {
00717
00718 #ifdef LOG_DEBUG
00719 fprintf(MSG_OUT, "libdvdnav: Still set to %x\n", this->position_next.still);
00720 #endif
00721 this->position_current.still = this->position_next.still;
00722
00723
00724
00725
00726 if ((this->position_current.still || this->pci.hli.hl_gi.hli_ss) && !this->sync_wait_skip) {
00727 this->sync_wait = 1;
00728 } else {
00729 if( this->position_current.still == 0 || this->skip_still ) {
00730
00731 vm_get_next_cell(this->vm);
00732 this->position_current.still = 0;
00733 this->skip_still = 0;
00734 this->sync_wait_skip = 0;
00735 }
00736 }
00737
00738 (*event) = DVDNAV_NOP;
00739 (*len) = 0;
00740 pthread_mutex_unlock(&this->vm_lock);
00741 return DVDNAV_STATUS_OK;
00742 }
00743
00744
00745
00746 if (this->vm->map) {
00747 this->vobu.vobu_next = remap_block( this->vm->map,
00748 this->vm->state.domain, this->vm->state.TTN_REG,
00749 this->vm->state.pgN,
00750 this->vobu.vobu_start, this->vobu.vobu_next);
00751 }
00752
00753
00754 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.vobu_next, 1, buf);
00755
00756 if(result <= 0) {
00757 printerr("Error reading NAV packet.");
00758 pthread_mutex_unlock(&this->vm_lock);
00759 return DVDNAV_STATUS_ERR;
00760 }
00761
00762 if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
00763 printerr("Expected NAV packet but none found.");
00764 pthread_mutex_unlock(&this->vm_lock);
00765 return DVDNAV_STATUS_ERR;
00766 }
00767
00768
00769
00770 this->vm->state.blockN = this->vobu.vobu_start - this->position_current.cell_start;
00771
00772 dvdnav_get_vobu(this, &this->dsi, &this->pci, &this->vobu);
00773 this->vobu.blockN = 0;
00774
00775
00776
00777 dvdnav_pre_cache_blocks(this->cache, this->vobu.vobu_start+1, this->vobu.vobu_length+1);
00778
00779
00780 if (this->last_cmd_nav_lbn == this->pci.pci_gi.nv_pck_lbn)
00781 this->last_cmd_nav_lbn = SRI_END_OF_CELL;
00782
00783
00784 (*event) = DVDNAV_NAV_PACKET;
00785 #ifdef LOG_DEBUG
00786 fprintf(MSG_OUT, "libdvdnav: NAV_PACKET\n");
00787 #endif
00788 (*len) = 2048;
00789 pthread_mutex_unlock(&this->vm_lock);
00790 return DVDNAV_STATUS_OK;
00791 }
00792
00793
00794 if(!this->file) {
00795 printerr("Attempting to read without opening file.");
00796 pthread_mutex_unlock(&this->vm_lock);
00797 return DVDNAV_STATUS_ERR;
00798 }
00799
00800 this->vobu.blockN++;
00801 result = dvdnav_read_cache_block(this->cache, this->vobu.vobu_start + this->vobu.blockN, 1, buf);
00802 if(result <= 0) {
00803 printerr("Error reading from DVD.");
00804 pthread_mutex_unlock(&this->vm_lock);
00805 return DVDNAV_STATUS_ERR;
00806 }
00807 (*event) = DVDNAV_BLOCK_OK;
00808 (*len) = 2048;
00809
00810 pthread_mutex_unlock(&this->vm_lock);
00811 return DVDNAV_STATUS_OK;
00812 }
00813
00814 dvdnav_status_t dvdnav_get_title_string(dvdnav_t *this, const char **title_str) {
00815
00816 if(!this || !title_str) {
00817 printerr("Passed a NULL pointer.");
00818 return DVDNAV_STATUS_ERR;
00819 }
00820
00821 (*title_str) = this->vm->dvd_name;
00822 return DVDNAV_STATUS_OK;
00823 }
00824
00825 dvdnav_status_t dvdnav_get_serial_number(dvdnav_t *this, const char **serial_str) {
00826
00827 if(!this || !serial_str) {
00828 printerr("Passed a NULL pointer.");
00829 return DVDNAV_STATUS_ERR;
00830 }
00831
00832 (*serial_str) = this->vm->serial_number;
00833 return DVDNAV_STATUS_OK;
00834 }
00835
00836 uint8_t dvdnav_get_video_aspect(dvdnav_t *this) {
00837 uint8_t retval;
00838
00839 if(!this) {
00840 printerr("Passed a NULL pointer.");
00841 return -1;
00842 }
00843 if(!this->started) {
00844 printerr("Virtual DVD machine not started.");
00845 return -1;
00846 }
00847
00848 pthread_mutex_lock(&this->vm_lock);
00849 retval = (uint8_t)vm_get_video_aspect(this->vm);
00850 pthread_mutex_unlock(&this->vm_lock);
00851
00852 return retval;
00853 }
00854
00855 uint8_t dvdnav_get_video_scale_permission(dvdnav_t *this) {
00856 uint8_t retval;
00857
00858 if(!this) {
00859 printerr("Passed a NULL pointer.");
00860 return -1;
00861 }
00862 if(!this->started) {
00863 printerr("Virtual DVD machine not started.");
00864 return -1;
00865 }
00866
00867 pthread_mutex_lock(&this->vm_lock);
00868 retval = (uint8_t)vm_get_video_scale_permission(this->vm);
00869 pthread_mutex_unlock(&this->vm_lock);
00870
00871 return retval;
00872 }
00873
00874 uint8_t dvdnav_get_video_format(dvdnav_t *this) {
00875 uint8_t retval;
00876
00877 if(!this) {
00878 printerr("Passed a NULL pointer.");
00879 return -1;
00880 }
00881 if(!this->started) {
00882 printerr("Virtual DVD machine not started.");
00883 return -1;
00884 }
00885
00886 pthread_mutex_lock(&this->vm_lock);
00887 retval = (uint8_t)vm_get_video_format(this->vm);
00888 pthread_mutex_unlock(&this->vm_lock);
00889
00890 return retval;
00891 }
00892
00893 uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *this, uint8_t stream) {
00894 audio_attr_t attr;
00895
00896 if(!this) {
00897 printerr("Passed a NULL pointer.");
00898 return -1;
00899 }
00900 if(!this->started) {
00901 printerr("Virtual DVD machine not started.");
00902 return -1;
00903 }
00904
00905 pthread_mutex_lock(&this->vm_lock);
00906 attr = vm_get_audio_attr(this->vm, stream);
00907 pthread_mutex_unlock(&this->vm_lock);
00908
00909 if(attr.lang_type != 1)
00910 return 0xffff;
00911
00912 return attr.lang_code;
00913 }
00914
00915 unsigned char dvdnav_audio_get_channels(dvdnav_t *this, uint8_t stream){
00916 audio_attr_t attr;
00917
00918 if(!this) {
00919 printerr("Passed a NULL pointer.");
00920 return 0xff;
00921 }
00922 if(!this->started) {
00923 printerr("Virtual DVD machine not started.");
00924 return 0xff;
00925 }
00926
00927 pthread_mutex_lock(&this->vm_lock);
00928 attr = vm_get_audio_attr(this->vm, stream);
00929 pthread_mutex_unlock(&this->vm_lock);
00930
00931 return attr.channels;
00932
00933 }
00934
00935
00936
00937
00938
00939 unsigned char dvdnav_audio_get_format(dvdnav_t *this, uint8_t stream){
00940 audio_attr_t attr;
00941
00942 if(!this) {
00943 printerr("Passed a NULL pointer.");
00944 return 0xff;
00945 }
00946 if(!this->started) {
00947 printerr("Virtual DVD machine not started.");
00948 return 0xff;
00949 }
00950
00951 pthread_mutex_lock(&this->vm_lock);
00952 attr = vm_get_audio_attr(this->vm, stream);
00953 pthread_mutex_unlock(&this->vm_lock);
00954
00955 return attr.audio_format;
00956 }
00957
00958
00959
00960
00961 int dvdnav_subp_get_stream_count(dvdnav_t *this) {
00962 int count = 0;
00963 if (!this) {
00964 printerr("Passed a NULL pointer.");
00965 return 0;
00966 }
00967 if(!this->started) {
00968 printerr("Virtual DVD machine not started.");
00969 return 0;
00970 }
00971
00972 pthread_mutex_lock(&this->vm_lock);
00973 count = vm_get_subp_stream_count(this->vm);
00974 pthread_mutex_unlock(&this->vm_lock);
00975
00976 return count;
00977 }
00978
00979
00980
00981
00982 int dvdnav_audio_get_stream_count(dvdnav_t *this) {
00983 int count = 0;
00984 if (!this) {
00985 printerr("Passed a NULL pointer.");
00986 return 0;
00987 }
00988 if(!this->started) {
00989 printerr("Virtual DVD machine not started.");
00990 return 0;
00991 }
00992
00993 pthread_mutex_lock(&this->vm_lock);
00994 count = vm_get_audio_stream_count(this->vm);
00995 pthread_mutex_unlock(&this->vm_lock);
00996
00997 return count;
00998 }
00999
01000 uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *this, uint8_t stream) {
01001 subp_attr_t attr;
01002
01003 if(!this) {
01004 printerr("Passed a NULL pointer.");
01005 return -1;
01006 }
01007 if(!this->started) {
01008 printerr("Virtual DVD machine not started.");
01009 return -1;
01010 }
01011
01012 pthread_mutex_lock(&this->vm_lock);
01013 attr = vm_get_subp_attr(this->vm, stream);
01014 pthread_mutex_unlock(&this->vm_lock);
01015
01016 if(attr.type != 1)
01017 return 0xffff;
01018
01019 return attr.lang_code;
01020 }
01021
01022 int8_t dvdnav_get_audio_logical_stream(dvdnav_t *this, uint8_t audio_num) {
01023 int8_t retval;
01024
01025 if(!this) {
01026 printerr("Passed a NULL pointer.");
01027 return -1;
01028 }
01029 if(!this->started) {
01030 printerr("Virtual DVD machine not started.");
01031 return -1;
01032 }
01033
01034 pthread_mutex_lock(&this->vm_lock);
01035 if (!this->vm->state.pgc) {
01036 printerr("No current PGC.");
01037 pthread_mutex_unlock(&this->vm_lock);
01038 return -1;
01039 }
01040 retval = vm_get_audio_stream(this->vm, audio_num);
01041 pthread_mutex_unlock(&this->vm_lock);
01042
01043 return retval;
01044 }
01045
01046 int8_t dvdnav_get_spu_logical_stream(dvdnav_t *this, uint8_t subp_num) {
01047 int8_t retval;
01048
01049 if(!this) {
01050 printerr("Passed a NULL pointer.");
01051 return -1;
01052 }
01053 if(!this->started) {
01054 printerr("Virtual DVD machine not started.");
01055 return -1;
01056 }
01057
01058 pthread_mutex_lock(&this->vm_lock);
01059 if (!this->vm->state.pgc) {
01060 printerr("No current PGC.");
01061 pthread_mutex_unlock(&this->vm_lock);
01062 return -1;
01063 }
01064 retval = vm_get_subp_stream(this->vm, subp_num, 0);
01065 pthread_mutex_unlock(&this->vm_lock);
01066
01067 return retval;
01068 }
01069
01070 int8_t dvdnav_get_active_audio_stream(dvdnav_t *this) {
01071 int8_t retval;
01072
01073 if(!this) {
01074 printerr("Passed a NULL pointer.");
01075 return -1;
01076 }
01077 if(!this->started) {
01078 printerr("Virtual DVD machine not started.");
01079 return -1;
01080 }
01081
01082 pthread_mutex_lock(&this->vm_lock);
01083 if (!this->vm->state.pgc) {
01084 printerr("No current PGC.");
01085 pthread_mutex_unlock(&this->vm_lock);
01086 return -1;
01087 }
01088 retval = vm_get_audio_active_stream(this->vm);
01089 pthread_mutex_unlock(&this->vm_lock);
01090
01091 return retval;
01092 }
01093
01094 int8_t dvdnav_get_active_spu_stream(dvdnav_t *this) {
01095 int8_t retval;
01096
01097 if(!this) {
01098 printerr("Passed a NULL pointer.");
01099 return -1;
01100 }
01101 if(!this->started) {
01102 printerr("Virtual DVD machine not started.");
01103 return -1;
01104 }
01105
01106 pthread_mutex_lock(&this->vm_lock);
01107 if (!this->vm->state.pgc) {
01108 printerr("No current PGC.");
01109 pthread_mutex_unlock(&this->vm_lock);
01110 return -1;
01111 }
01112 retval = vm_get_subp_active_stream(this->vm, 0);
01113 pthread_mutex_unlock(&this->vm_lock);
01114
01115 return retval;
01116 }
01117
01118 static int8_t dvdnav_is_domain(dvdnav_t *this, domain_t domain) {
01119 int8_t retval;
01120
01121 if(!this) {
01122 printerr("Passed a NULL pointer.");
01123 return -1;
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 if(!this) {
01159 printerr("Passed a NULL pointer.");
01160 return DVDNAV_STATUS_ERR;
01161 }
01162
01163 pthread_mutex_lock(&this->vm_lock);
01164 vm_get_angle_info(this->vm, ¤t, &num);
01165
01166 if((angle > 0) && (angle <= num)) {
01167 this->vm->state.AGL_REG = angle;
01168 } else {
01169 printerr("Passed an invalid angle number.");
01170 pthread_mutex_unlock(&this->vm_lock);
01171 return DVDNAV_STATUS_ERR;
01172 }
01173 pthread_mutex_unlock(&this->vm_lock);
01174
01175 return DVDNAV_STATUS_OK;
01176 }
01177
01178 dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *this, int32_t *current_angle,
01179 int32_t *number_of_angles) {
01180 if(!this || !current_angle || !number_of_angles) {
01181 printerr("Passed a NULL pointer.");
01182 return DVDNAV_STATUS_ERR;
01183 }
01184
01185 pthread_mutex_lock(&this->vm_lock);
01186 vm_get_angle_info(this->vm, current_angle, number_of_angles);
01187 pthread_mutex_unlock(&this->vm_lock);
01188
01189 return DVDNAV_STATUS_OK;
01190 }
01191
01192 pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) {
01193 if(!this) return 0;
01194 return &this->pci;
01195 }
01196
01197 dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) {
01198 if(!this) return 0;
01199 return &this->dsi;
01200 }
01201
01202 uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) {
01203 if(!this) return -1;
01204 return this->position_next.still;
01205 }
01206