00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #if HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif
00025
00026 #include "bluray.h"
00027 #include "register.h"
00028 #include "util/macro.h"
00029 #include "util/logging.h"
00030 #include "util/strutl.h"
00031 #include "bdnav/navigation.h"
00032 #include "bdnav/index_parse.h"
00033 #include "bdnav/meta_parse.h"
00034 #include "bdnav/clpi_parse.h"
00035 #include "hdmv/hdmv_vm.h"
00036 #include "decoders/graphics_controller.h"
00037 #include "file/file.h"
00038 #ifdef DLOPEN_CRYPTO_LIBS
00039 #include "file/dl.h"
00040 #endif
00041 #ifdef USING_BDJAVA
00042 #include "bdj/bdj.h"
00043 #endif
00044
00045 #ifndef DLOPEN_CRYPTO_LIBS
00046 #include <libaacs/aacs.h>
00047 #include <libbdplus/bdplus.h>
00048 #endif
00049 #include <stdlib.h>
00050 #include <inttypes.h>
00051 #include <string.h>
00052 #include <sys/types.h>
00053
00054 #include "mythiowrapper.h"
00055
00056 typedef int (*fptr_int)();
00057 typedef int32_t (*fptr_int32)();
00058 typedef void* (*fptr_p_void)();
00059
00060 #define MAX_EVENTS 31
00061 typedef struct bd_event_queue_s {
00062 unsigned in;
00063 unsigned out;
00064 BD_EVENT ev[MAX_EVENTS+1];
00065 } BD_EVENT_QUEUE;
00066
00067 typedef enum {
00068 title_undef = 0,
00069 title_hdmv,
00070 title_bdj,
00071 } BD_TITLE_TYPE;
00072
00073 typedef struct {
00074
00075 NAV_CLIP *clip;
00076 BD_FILE_H *fp;
00077 uint64_t clip_size;
00078 uint64_t clip_block_pos;
00079 uint64_t clip_pos;
00080
00081
00082 uint16_t int_buf_off;
00083
00084 BD_UO_MASK uo_mask;
00085
00086 } BD_STREAM;
00087
00088 typedef struct {
00089 NAV_CLIP *clip;
00090 uint64_t clip_size;
00091 uint8_t *buf;
00092 } BD_PRELOAD;
00093
00094 struct bluray {
00095
00096
00097 char *device_path;
00098 BLURAY_DISC_INFO disc_info;
00099 INDX_ROOT *index;
00100 META_ROOT *meta;
00101 NAV_TITLE_LIST *title_list;
00102
00103
00104 NAV_TITLE *title;
00105 uint32_t title_idx;
00106 uint64_t s_pos;
00107
00108
00109 BD_STREAM st0;
00110 BD_PRELOAD st_ig;
00111
00112
00113 uint8_t int_buf[6144];
00114
00115
00116 int seamless_angle_change;
00117 uint32_t angle_change_pkt;
00118 uint32_t angle_change_time;
00119 unsigned request_angle;
00120
00121
00122 uint64_t next_chapter_start;
00123
00124
00125 #ifdef DLOPEN_CRYPTO_LIBS
00126 void *h_libaacs;
00127 #endif
00128 void *aacs;
00129 fptr_p_void libaacs_open;
00130 fptr_int libaacs_decrypt_unit;
00131
00132
00133 #ifdef DLOPEN_CRYPTO_LIBS
00134 void *h_libbdplus;
00135 #endif
00136 void *bdplus;
00137 fptr_p_void bdplus_init;
00138 fptr_int32 bdplus_seek;
00139 fptr_int32 bdplus_fixup;
00140
00141
00142 BD_REGISTERS *regs;
00143 BD_EVENT_QUEUE *event_queue;
00144 BD_TITLE_TYPE title_type;
00145
00146 HDMV_VM *hdmv_vm;
00147 uint8_t hdmv_suspended;
00148
00149 void *bdjava;
00150
00151
00152 GRAPHICS_CONTROLLER *graphics_controller;
00153 };
00154
00155 #ifdef DLOPEN_CRYPTO_LIBS
00156 # define DL_CALL(lib,func,param,...) \
00157 do { \
00158 fptr_p_void fptr = (fptr_p_void)dl_dlsym(lib, #func); \
00159 if (fptr) { \
00160 fptr(param, ##__VA_ARGS__); \
00161 } \
00162 } while (0)
00163 #else
00164 # define DL_CALL(lib,func,param,...) \
00165 func (param, ##__VA_ARGS__)
00166 #endif
00167
00168
00169
00170
00171
00172 static void _init_event_queue(BLURAY *bd)
00173 {
00174 if (!bd->event_queue) {
00175 bd->event_queue = calloc(1, sizeof(struct bd_event_queue_s));
00176 } else {
00177 memset(bd->event_queue, 0, sizeof(struct bd_event_queue_s));
00178 }
00179 }
00180
00181 static int _get_event(BLURAY *bd, BD_EVENT *ev)
00182 {
00183 struct bd_event_queue_s *eq = bd->event_queue;
00184
00185 if (eq) {
00186 if (eq->in != eq->out) {
00187 *ev = eq->ev[eq->out];
00188 eq->out = (eq->out + 1) & MAX_EVENTS;
00189 return 1;
00190 }
00191 }
00192
00193 ev->event = BD_EVENT_NONE;
00194
00195 return 0;
00196 }
00197
00198 static int _queue_event(BLURAY *bd, BD_EVENT ev)
00199 {
00200 struct bd_event_queue_s *eq = bd->event_queue;
00201
00202 if (eq) {
00203 unsigned new_in = (eq->in + 1) & MAX_EVENTS;
00204
00205 if (new_in != eq->out) {
00206 eq->ev[eq->in] = ev;
00207 eq->in = new_in;
00208 return 1;
00209 }
00210
00211 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "_queue_event(%d, %d): queue overflow !\n", ev.event, ev.param);
00212 }
00213
00214 return 0;
00215 }
00216
00217
00218
00219
00220
00221 static void _update_stream_psr_by_lang(BD_REGISTERS *regs,
00222 uint32_t psr_lang, uint32_t psr_stream,
00223 uint32_t enable_flag, uint32_t undefined_val,
00224 MPLS_STREAM *streams, unsigned num_streams)
00225 {
00226 uint32_t psr_val;
00227 int stream_idx = -1;
00228 unsigned ii;
00229
00230
00231 psr_val = bd_psr_read(regs, psr_lang);
00232 if (psr_val == 0xffffff) {
00233
00234 return;
00235 }
00236
00237
00238
00239 for (ii = 0; ii < num_streams; ii++) {
00240 if (psr_val == str_to_uint32((const char *)streams[ii].lang, 3)) {
00241 stream_idx = ii;
00242 break;
00243 }
00244 }
00245
00246 if (stream_idx < 0) {
00247
00248 stream_idx = undefined_val - 1;
00249 enable_flag = 0;
00250 }
00251
00252
00253 BD_DEBUG(DBG_BLURAY, "Selected stream %d (language %s)\n", ii, streams[ii].lang);
00254
00255 bd_psr_lock(regs);
00256
00257 psr_val = bd_psr_read(regs, psr_stream) & 0xffff0000;
00258 psr_val |= (stream_idx + 1) | enable_flag;
00259 bd_psr_write(regs, psr_stream, psr_val);
00260
00261 bd_psr_unlock(regs);
00262 }
00263
00264 static void _update_clip_psrs(BLURAY *bd, NAV_CLIP *clip)
00265 {
00266 bd_psr_write(bd->regs, PSR_PLAYITEM, clip->ref);
00267 bd_psr_write(bd->regs, PSR_TIME, clip->in_time);
00268
00269
00270
00271
00272 if (bd->title_type == title_undef) {
00273 MPLS_STN *stn = &clip->title->pl->play_item[clip->ref].stn;
00274
00275 _update_stream_psr_by_lang(bd->regs,
00276 PSR_AUDIO_LANG, PSR_PRIMARY_AUDIO_ID, 0, 0xff,
00277 stn->audio, stn->num_audio);
00278 _update_stream_psr_by_lang(bd->regs,
00279 PSR_PG_AND_SUB_LANG, PSR_PG_STREAM, 0x80000000, 0xfff,
00280 stn->pg, stn->num_pg);
00281 }
00282 }
00283
00284
00285 static void _update_chapter_psr(BLURAY *bd)
00286 {
00287 uint32_t current_chapter = bd_get_current_chapter(bd);
00288 bd->next_chapter_start = bd_chapter_pos(bd, current_chapter + 1);
00289 bd_psr_write(bd->regs, PSR_CHAPTER, current_chapter + 1);
00290 }
00291
00292
00293
00294
00295
00296 static void _close_m2ts(BD_STREAM *st)
00297 {
00298 if (st->fp != NULL) {
00299 file_close(st->fp);
00300 st->fp = NULL;
00301 }
00302
00303
00304 memset(&st->uo_mask, 0, sizeof(st->uo_mask));
00305 }
00306
00307 static int _open_m2ts(BLURAY *bd, BD_STREAM *st)
00308 {
00309 char *f_name;
00310 struct stat buf;
00311
00312 _close_m2ts(st);
00313
00314 f_name = str_printf("%s" DIR_SEP "BDMV" DIR_SEP "STREAM" DIR_SEP "%s",
00315 bd->device_path, st->clip->name);
00316
00317 st->clip_pos = (uint64_t)st->clip->start_pkt * 192;
00318 st->clip_block_pos = (st->clip_pos / 6144) * 6144;
00319
00320 if ((st->fp = file_open(f_name, "rb"))) {
00321
00322
00323
00324
00325
00326 if (mythfile_stat(f_name, &buf) == 0)
00327 st->clip_size = buf.st_size;
00328 else
00329 st->clip_size = 0;
00330
00331 if (st->clip_size) {
00332 file_seek(st->fp, st->clip_block_pos, SEEK_SET);
00333 st->int_buf_off = 6144;
00334 X_FREE(f_name);
00335
00336 if (bd->bdplus) {
00337 DL_CALL(bd->h_libbdplus, bdplus_set_title,
00338 bd->bdplus, st->clip->clip_id);
00339 }
00340
00341 if (bd->aacs) {
00342 uint32_t title = bd_psr_read(bd->regs, PSR_TITLE_NUMBER);
00343 DL_CALL(bd->h_libaacs, aacs_select_title,
00344 bd->aacs, title);
00345 }
00346
00347 if (st == &bd->st0) {
00348 MPLS_PL *pl = st->clip->title->pl;
00349 st->uo_mask = bd_uo_mask_combine(pl->app_info.uo_mask,
00350 pl->play_item[st->clip->ref].uo_mask);
00351
00352 _update_clip_psrs(bd, st->clip);
00353 }
00354
00355 return 1;
00356 }
00357
00358 BD_DEBUG(DBG_BLURAY, "Clip %s empty! (%p)\n", f_name, bd);
00359 }
00360
00361 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open clip %s! (%p)\n",
00362 f_name, bd);
00363
00364 X_FREE(f_name);
00365 return 0;
00366 }
00367
00368 static int _read_block(BLURAY *bd, BD_STREAM *st, uint8_t *buf)
00369 {
00370 const int len = 6144;
00371
00372 if (st->fp) {
00373 BD_DEBUG(DBG_STREAM, "Reading unit [%d bytes] at %"PRIu64"... (%p)\n",
00374 len, st->clip_block_pos, bd);
00375
00376 if (len + st->clip_block_pos <= st->clip_size) {
00377 int read_len;
00378
00379 if ((read_len = file_read(st->fp, buf, len))) {
00380 if (read_len != len)
00381 BD_DEBUG(DBG_STREAM | DBG_CRIT, "Read %d bytes at %"PRIu64" ; requested %d ! (%p)\n", read_len, st->clip_block_pos, len, bd);
00382
00383 if (bd->aacs && bd->libaacs_decrypt_unit) {
00384 if (!bd->libaacs_decrypt_unit(bd->aacs, buf)) {
00385 BD_DEBUG(DBG_AACS | DBG_CRIT, "Unable decrypt unit (AACS)! (%p)\n", bd);
00386
00387 return 0;
00388 }
00389 }
00390
00391 st->clip_block_pos += len;
00392
00393
00394 if (bd->bdplus_fixup && bd->bdplus) {
00395 int32_t numFixes;
00396 numFixes = bd->bdplus_fixup(bd->bdplus, len, buf);
00397 #if 1
00398 if (numFixes) {
00399 BD_DEBUG(DBG_BDPLUS,
00400 "BDPLUS did %u fixups\n", numFixes);
00401 }
00402 #endif
00403
00404 }
00405
00406
00407 if (buf[0] & 0xc0) {
00408 BD_DEBUG(DBG_BLURAY | DBG_CRIT,
00409 "TP header copy permission indicator != 0, unit is still encrypted? (%p)\n", bd);
00410 _queue_event(bd, (BD_EVENT){BD_EVENT_ENCRYPTED, 0});
00411 return 0;
00412 }
00413
00414 BD_DEBUG(DBG_STREAM, "Read unit OK! (%p)\n", bd);
00415
00416 return 1;
00417 }
00418
00419 BD_DEBUG(DBG_STREAM | DBG_CRIT, "Read %d bytes at %"PRIu64" failed ! (%p)\n", len, st->clip_block_pos, bd);
00420
00421 return 0;
00422 }
00423
00424 BD_DEBUG(DBG_STREAM | DBG_CRIT, "Read past EOF ! (%p)\n", bd);
00425
00426 return 0;
00427 }
00428
00429 BD_DEBUG(DBG_BLURAY, "No valid title selected! (%p)\n", bd);
00430
00431 return 0;
00432 }
00433
00434
00435
00436
00437
00438 static void _close_preload(BD_PRELOAD *p)
00439 {
00440 X_FREE(p->buf);
00441 memset(p, 0, sizeof(*p));
00442 }
00443
00444 static int _preload_m2ts(BLURAY *bd, BD_PRELOAD *p)
00445 {
00446
00447
00448 BD_STREAM st;
00449
00450 memset(&st, 0, sizeof(st));
00451 st.clip = p->clip;
00452
00453 if (!_open_m2ts(bd, &st)) {
00454 return 0;
00455 }
00456
00457
00458 p->clip_size = st.clip_size;
00459 p->buf = realloc(p->buf, p->clip_size);
00460
00461
00462
00463 uint8_t *buf = p->buf;
00464 uint8_t *end = p->buf + p->clip_size;
00465
00466 for (; buf < end; buf += 6144) {
00467 if (!_read_block(bd, &st, buf)) {
00468 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "_preload_m2ts(): error loading %s at %"PRIu64"\n",
00469 st.clip->name, (uint64_t)(buf - p->buf));
00470 _close_m2ts(&st);
00471 _close_preload(p);
00472 return 0;
00473 }
00474 }
00475
00476
00477
00478 BD_DEBUG(DBG_BLURAY, "_preload_m2ts(): loaded %"PRIu64" bytes from %s\n",
00479 st.clip_size, st.clip->name);
00480
00481 _close_m2ts(&st);
00482
00483 return 1;
00484 }
00485
00486 static int64_t _seek_stream(BLURAY *bd, BD_STREAM *st,
00487 NAV_CLIP *clip, uint32_t clip_pkt)
00488 {
00489 if (!clip)
00490 return -1;
00491
00492 if (!st->fp || !st->clip || clip->ref != st->clip->ref) {
00493
00494 st->clip = clip;
00495 if (!_open_m2ts(bd, st)) {
00496 return -1;
00497 }
00498 }
00499
00500 st->clip_pos = (uint64_t)clip_pkt * 192;
00501 st->clip_block_pos = (st->clip_pos / 6144) * 6144;
00502
00503 file_seek(st->fp, st->clip_block_pos, SEEK_SET);
00504
00505 st->int_buf_off = 6144;
00506
00507 return st->clip_pos;
00508 }
00509
00510
00511
00512
00513
00514 static void _libaacs_close(BLURAY *bd)
00515 {
00516 if (bd->aacs) {
00517 DL_CALL(bd->h_libaacs, aacs_close, bd->aacs);
00518 bd->aacs = NULL;
00519 }
00520 }
00521
00522 static void _libaacs_unload(BLURAY *bd)
00523 {
00524 _libaacs_close(bd);
00525
00526 #ifdef DLOPEN_CRYPTO_LIBS
00527 if (bd->h_libaacs) {
00528 dl_dlclose(bd->h_libaacs);
00529 bd->h_libaacs = NULL;
00530 }
00531 #endif
00532
00533 bd->libaacs_open = NULL;
00534 bd->libaacs_decrypt_unit = NULL;
00535 }
00536
00537 static int _libaacs_required(BLURAY *bd)
00538 {
00539 BD_FILE_H *fd;
00540 char *tmp;
00541
00542 tmp = str_printf("%s/AACS/Unit_Key_RO.inf", bd->device_path);
00543 fd = file_open(tmp, "rb");
00544 X_FREE(tmp);
00545
00546 if (fd) {
00547 file_close(fd);
00548
00549 BD_DEBUG(DBG_BLURAY, "AACS/Unit_Key_RO.inf found. Disc seems to be AACS protected (%p)\n", bd);
00550 bd->disc_info.aacs_detected = 1;
00551 return 1;
00552 }
00553
00554 BD_DEBUG(DBG_BLURAY, "AACS/Unit_Key_RO.inf not found. No AACS protection (%p)\n", bd);
00555 bd->disc_info.aacs_detected = 0;
00556 return 0;
00557 }
00558
00559 static int _libaacs_load(BLURAY *bd)
00560 {
00561 #ifdef DLOPEN_CRYPTO_LIBS
00562 if (bd->h_libaacs) {
00563 return 1;
00564 }
00565
00566 bd->disc_info.libaacs_detected = 0;
00567 if ((bd->h_libaacs = dl_dlopen("libaacs", "0"))) {
00568
00569 BD_DEBUG(DBG_BLURAY, "Loading libaacs (%p)\n", bd->h_libaacs);
00570
00571 bd->libaacs_open = (fptr_p_void)dl_dlsym(bd->h_libaacs, "aacs_open");
00572 bd->libaacs_decrypt_unit = (fptr_int)dl_dlsym(bd->h_libaacs, "aacs_decrypt_unit");
00573
00574 if (bd->libaacs_open && bd->libaacs_decrypt_unit) {
00575 BD_DEBUG(DBG_BLURAY, "Loaded libaacs (%p)\n", bd->h_libaacs);
00576 bd->disc_info.libaacs_detected = 1;
00577 return 1;
00578
00579 } else {
00580 BD_DEBUG(DBG_BLURAY, "libaacs dlsym failed! (%p)\n", bd->h_libaacs);
00581 }
00582
00583 } else {
00584 BD_DEBUG(DBG_BLURAY, "libaacs not found! (%p)\n", bd);
00585 }
00586
00587 _libaacs_unload(bd);
00588
00589 return 0;
00590
00591 #else
00592 BD_DEBUG(DBG_BLURAY, "Using libaacs via normal linking\n");
00593
00594 bd->libaacs_open = &aacs_open;
00595 bd->libaacs_decrypt_unit = &aacs_decrypt_unit;
00596 bd->disc_info.libaacs_detected = 1;
00597
00598 return 1;
00599 #endif
00600 }
00601
00602 static int _libaacs_open(BLURAY *bd, const char *keyfile_path)
00603 {
00604 _libaacs_close(bd);
00605
00606 if (!_libaacs_required(bd)) {
00607
00608 return 1;
00609 }
00610
00611 if (!_libaacs_load(bd)) {
00612
00613 return 0;
00614 }
00615
00616 bd->aacs = bd->libaacs_open(bd->device_path, keyfile_path);
00617
00618 if (bd->aacs) {
00619 BD_DEBUG(DBG_BLURAY, "Opened libaacs (%p)\n", bd->aacs);
00620 bd->disc_info.aacs_handled = 1;
00621 return 1;
00622 }
00623
00624 BD_DEBUG(DBG_BLURAY, "aacs_open() failed!\n");
00625 bd->disc_info.aacs_handled = 0;
00626
00627 _libaacs_unload(bd);
00628 return 0;
00629 }
00630
00631 static uint8_t *_libaacs_get_vid(BLURAY *bd)
00632 {
00633 if (bd->aacs) {
00634 #ifdef DLOPEN_CRYPTO_LIBS
00635 fptr_p_void fptr = (fptr_p_void)dl_dlsym(bd->h_libaacs, "aacs_get_vid");
00636 if (fptr) {
00637 return (uint8_t*)fptr(bd->aacs);
00638 }
00639 BD_DEBUG(DBG_BLURAY, "aacs_get_vid() dlsym failed! (%p)", bd);
00640 return NULL;
00641 #else
00642 return aacs_get_vid(bd->aacs);
00643 #endif
00644 }
00645
00646 BD_DEBUG(DBG_BLURAY, "_libaacs_get_vid(): libaacs not initialized! (%p)", bd);
00647 return NULL;
00648 }
00649
00650 static void _libbdplus_close(BLURAY *bd)
00651 {
00652 if (bd->bdplus) {
00653 DL_CALL(bd->h_libbdplus, bdplus_free, bd->bdplus);
00654 bd->bdplus = NULL;
00655 }
00656 }
00657
00658 static void _libbdplus_unload(BLURAY *bd)
00659 {
00660 _libbdplus_close(bd);
00661
00662 #ifdef DLOPEN_CRYPTO_LIBS
00663 if (bd->h_libbdplus) {
00664 dl_dlclose(bd->h_libbdplus);
00665 bd->h_libbdplus = NULL;
00666 }
00667 #endif
00668
00669 bd->bdplus_init = NULL;
00670 bd->bdplus_seek = NULL;
00671 bd->bdplus_fixup = NULL;
00672 }
00673
00674 static int _libbdplus_required(BLURAY *bd)
00675 {
00676 BD_FILE_H *fd;
00677 char *tmp;
00678
00679 tmp = str_printf("%s/BDSVM/00000.svm", bd->device_path);
00680 fd = file_open(tmp, "rb");
00681 X_FREE(tmp);
00682
00683 if (fd) {
00684 file_close(fd);
00685
00686 BD_DEBUG(DBG_BLURAY, "BDSVM/00000.svm found. Disc seems to be BD+ protected (%p)\n", bd);
00687 bd->disc_info.bdplus_detected = 1;
00688 return 1;
00689 }
00690
00691 BD_DEBUG(DBG_BLURAY, "BDSVM/00000.svm not found. No BD+ protection (%p)\n", bd);
00692 bd->disc_info.bdplus_detected = 0;
00693 return 0;
00694 }
00695
00696 static int _libbdplus_load(BLURAY *bd)
00697 {
00698 BD_DEBUG(DBG_BDPLUS, "attempting to load libbdplus\n");
00699
00700 #ifdef DLOPEN_CRYPTO_LIBS
00701 if (bd->h_libbdplus) {
00702 return 1;
00703 }
00704
00705 bd->disc_info.libbdplus_detected = 0;
00706 if ((bd->h_libbdplus = dl_dlopen("libbdplus", "0"))) {
00707
00708 BD_DEBUG(DBG_BLURAY, "Loading libbdplus (%p)\n", bd->h_libbdplus);
00709
00710 bd->bdplus_init = (fptr_p_void)dl_dlsym(bd->h_libbdplus, "bdplus_init");
00711 bd->bdplus_seek = (fptr_int32)dl_dlsym(bd->h_libbdplus, "bdplus_seek");
00712 bd->bdplus_fixup = (fptr_int32)dl_dlsym(bd->h_libbdplus, "bdplus_fixup");
00713
00714 if (bd->bdplus_init && bd->bdplus_seek && bd->bdplus_fixup) {
00715 BD_DEBUG(DBG_BLURAY, "Loaded libbdplus (%p)\n", bd->h_libbdplus);
00716 bd->disc_info.libbdplus_detected = 1;
00717 return 1;
00718 }
00719
00720 BD_DEBUG(DBG_BLURAY, "libbdplus dlsym failed! (%p)\n", bd->h_libbdplus);
00721
00722 } else {
00723 BD_DEBUG(DBG_BLURAY, "libbdplus not found! (%p)\n", bd);
00724 }
00725
00726 _libbdplus_unload(bd);
00727
00728 return 0;
00729
00730 #else
00731 BD_DEBUG(DBG_BLURAY,"Using libbdplus via normal linking\n");
00732
00733 bd->bdplus_init = &bdplus_init;
00734 bd->bdplus_seek = &bdplus_seek;
00735 bd->bdplus_fixup = &bdplus_fixup;
00736 bd->disc_info.libbdplus_detected = 1;
00737
00738 return 1;
00739 #endif
00740 }
00741
00742 static int _libbdplus_open(BLURAY *bd, const char *keyfile_path)
00743 {
00744
00745
00746 uint8_t vid[16] = {
00747 0xC5,0x43,0xEF,0x2A,0x15,0x0E,0x50,0xC4,0xE2,0xCA,
00748 0x71,0x65,0xB1,0x7C,0xA7,0xCB};
00749
00750 _libbdplus_close(bd);
00751
00752 if (!_libbdplus_required(bd)) {
00753
00754 return 1;
00755 }
00756
00757 if (!_libbdplus_load(bd)) {
00758
00759 return 0;
00760 }
00761
00762 const uint8_t *aacs_vid = (const uint8_t *)_libaacs_get_vid(bd);
00763 bd->bdplus = bd->bdplus_init(bd->device_path, keyfile_path, aacs_vid ? aacs_vid : vid);
00764
00765 if (bd->bdplus) {
00766 BD_DEBUG(DBG_BLURAY,"libbdplus initialized\n");
00767 bd->disc_info.bdplus_handled = 1;
00768 return 1;
00769 }
00770
00771 BD_DEBUG(DBG_BLURAY,"bdplus_init() failed\n");
00772 bd->disc_info.bdplus_handled = 0;
00773
00774 _libbdplus_unload(bd);
00775 return 0;
00776 }
00777
00778
00779
00780
00781
00782 static int _index_open(BLURAY *bd)
00783 {
00784 if (!bd->index) {
00785 char *file;
00786
00787 file = str_printf("%s/BDMV/index.bdmv", bd->device_path);
00788 bd->index = indx_parse(file);
00789 X_FREE(file);
00790 }
00791
00792 return !!bd->index;
00793 }
00794
00795
00796
00797
00798
00799 static int _meta_open(BLURAY *bd)
00800 {
00801 if (!bd->meta){
00802 bd->meta = meta_parse(bd->device_path);
00803 }
00804
00805 return !!bd->meta;
00806 }
00807
00808
00809
00810
00811 const BLURAY_DISC_INFO *bd_get_disc_info(BLURAY *bd)
00812 {
00813 return &bd->disc_info;
00814 }
00815
00816 static void _fill_disc_info(BLURAY *bd)
00817 {
00818 bd->disc_info.bluray_detected = 0;
00819 bd->disc_info.top_menu_supported = 0;
00820 bd->disc_info.first_play_supported = 0;
00821 bd->disc_info.num_hdmv_titles = 0;
00822 bd->disc_info.num_bdj_titles = 0;
00823 bd->disc_info.num_unsupported_titles = 0;
00824
00825 if (bd->index) {
00826 INDX_PLAY_ITEM *pi;
00827 unsigned ii;
00828
00829 bd->disc_info.bluray_detected = 1;
00830
00831 pi = &bd->index->first_play;
00832 if (pi->object_type == indx_object_type_hdmv && pi->hdmv.id_ref != 0xffff) {
00833 bd->disc_info.first_play_supported = 1;
00834 }
00835
00836 pi = &bd->index->top_menu;
00837 if (pi->object_type == indx_object_type_hdmv && pi->hdmv.id_ref != 0xffff) {
00838 bd->disc_info.top_menu_supported = 1;
00839 }
00840
00841 for (ii = 0; ii < bd->index->num_titles; ii++) {
00842 if (bd->index->titles[ii].object_type == indx_object_type_hdmv) {
00843 bd->disc_info.num_hdmv_titles++;
00844 }
00845 if (bd->index->titles[ii].object_type == indx_object_type_bdj) {
00846 bd->disc_info.num_bdj_titles++;
00847 bd->disc_info.num_unsupported_titles++;
00848 }
00849 }
00850 }
00851 }
00852
00853
00854
00855
00856
00857 BLURAY *bd_open(const char* device_path, const char* keyfile_path)
00858 {
00859 BLURAY *bd = calloc(1, sizeof(BLURAY));
00860
00861 if (device_path) {
00862
00863 bd->device_path = (char*)malloc(strlen(device_path) + 1);
00864 strcpy(bd->device_path, device_path);
00865
00866 _libaacs_open(bd, keyfile_path);
00867
00868 _libbdplus_open(bd, keyfile_path);
00869
00870 _index_open(bd);
00871
00872 bd->meta = NULL;
00873
00874 bd->regs = bd_registers_init();
00875
00876 _fill_disc_info(bd);
00877
00878 BD_DEBUG(DBG_BLURAY, "BLURAY initialized! (%p)\n", bd);
00879 } else {
00880 X_FREE(bd);
00881
00882 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "No device path provided!\n");
00883 }
00884
00885 return bd;
00886 }
00887
00888 void bd_close(BLURAY *bd)
00889 {
00890 bd_stop_bdj(bd);
00891
00892 _libaacs_unload(bd);
00893
00894 _libbdplus_unload(bd);
00895
00896 _close_m2ts(&bd->st0);
00897 _close_preload(&bd->st_ig);
00898
00899 if (bd->title_list != NULL) {
00900 nav_free_title_list(bd->title_list);
00901 }
00902 if (bd->title != NULL) {
00903 nav_title_close(bd->title);
00904 }
00905
00906 hdmv_vm_free(&bd->hdmv_vm);
00907
00908 gc_free(&bd->graphics_controller);
00909 indx_free(&bd->index);
00910 bd_registers_free(bd->regs);
00911
00912 X_FREE(bd->event_queue);
00913 X_FREE(bd->device_path);
00914
00915 BD_DEBUG(DBG_BLURAY, "BLURAY destroyed! (%p)\n", bd);
00916
00917 X_FREE(bd);
00918 }
00919
00920
00921
00922
00923
00924 static int64_t _seek_internal(BLURAY *bd,
00925 NAV_CLIP *clip, uint32_t title_pkt, uint32_t clip_pkt)
00926 {
00927 if (_seek_stream(bd, &bd->st0, clip, clip_pkt) >= 0) {
00928
00929
00930 bd->s_pos = (uint64_t)title_pkt * 192;
00931
00932
00933 _update_chapter_psr(bd);
00934
00935 BD_DEBUG(DBG_BLURAY, "Seek to %"PRIu64" (%p)\n",
00936 bd->s_pos, bd);
00937
00938 if (bd->bdplus_seek && bd->bdplus) {
00939 bd->bdplus_seek(bd->bdplus, bd->st0.clip_block_pos);
00940 }
00941 }
00942
00943 return bd->s_pos;
00944 }
00945
00946
00947 static void _change_angle(BLURAY *bd)
00948 {
00949 if (bd->seamless_angle_change) {
00950 bd->st0.clip = nav_set_angle(bd->title, bd->st0.clip, bd->request_angle);
00951 bd->seamless_angle_change = 0;
00952 bd_psr_write(bd->regs, PSR_ANGLE_NUMBER, bd->title->angle + 1);
00953
00954
00955 _close_m2ts(&bd->st0);
00956 }
00957 }
00958
00959 int64_t bd_seek_time(BLURAY *bd, uint64_t tick)
00960 {
00961 uint32_t clip_pkt, out_pkt;
00962 NAV_CLIP *clip;
00963
00964 tick /= 2;
00965
00966 if (bd->title &&
00967 tick < bd->title->duration) {
00968
00969 _change_angle(bd);
00970
00971
00972 clip = nav_time_search(bd->title, tick, &clip_pkt, &out_pkt);
00973
00974 return _seek_internal(bd, clip, out_pkt, clip_pkt);
00975 }
00976
00977 return bd->s_pos;
00978 }
00979
00980 uint64_t bd_tell_time(BLURAY *bd)
00981 {
00982 uint32_t clip_pkt = 0, out_pkt = 0, out_time = 0;
00983
00984 if (bd && bd->title) {
00985 nav_packet_search(bd->title, bd->s_pos / 192, &clip_pkt, &out_pkt, &out_time);
00986 }
00987
00988 return ((uint64_t)out_time) * 2;
00989 }
00990
00991 int64_t bd_seek_chapter(BLURAY *bd, unsigned chapter)
00992 {
00993 uint32_t clip_pkt, out_pkt;
00994 NAV_CLIP *clip;
00995
00996 if (bd->title &&
00997 chapter < bd->title->chap_list.count) {
00998
00999 _change_angle(bd);
01000
01001
01002 clip = nav_chapter_search(bd->title, chapter, &clip_pkt, &out_pkt);
01003
01004 return _seek_internal(bd, clip, out_pkt, clip_pkt);
01005 }
01006
01007 return bd->s_pos;
01008 }
01009
01010 int64_t bd_chapter_pos(BLURAY *bd, unsigned chapter)
01011 {
01012 uint32_t clip_pkt, out_pkt;
01013
01014 if (bd->title &&
01015 chapter < bd->title->chap_list.count) {
01016
01017
01018 nav_chapter_search(bd->title, chapter, &clip_pkt, &out_pkt);
01019 return (int64_t)out_pkt * 192;
01020 }
01021
01022 return -1;
01023 }
01024
01025 uint32_t bd_get_current_chapter(BLURAY *bd)
01026 {
01027 if (bd->title) {
01028 return nav_chapter_get_current(bd->st0.clip, bd->st0.clip_pos / 192);
01029 }
01030
01031 return 0;
01032 }
01033
01034 int64_t bd_seek_playitem(BLURAY *bd, unsigned clip_ref)
01035 {
01036 uint32_t clip_pkt, out_pkt;
01037 NAV_CLIP *clip;
01038
01039 if (bd->title &&
01040 clip_ref < bd->title->clip_list.count) {
01041
01042 _change_angle(bd);
01043
01044 clip = &bd->title->clip_list.clip[clip_ref];
01045 clip_pkt = clip->start_pkt;
01046 out_pkt = clip->pos;
01047
01048 return _seek_internal(bd, clip, out_pkt, clip_pkt);
01049 }
01050
01051 return bd->s_pos;
01052 }
01053
01054 int64_t bd_seek_mark(BLURAY *bd, unsigned mark)
01055 {
01056 uint32_t clip_pkt, out_pkt;
01057 NAV_CLIP *clip;
01058
01059 if (bd->title &&
01060 mark < bd->title->mark_list.count) {
01061
01062 _change_angle(bd);
01063
01064
01065 clip = nav_mark_search(bd->title, mark, &clip_pkt, &out_pkt);
01066
01067 return _seek_internal(bd, clip, out_pkt, clip_pkt);
01068 }
01069
01070 return bd->s_pos;
01071 }
01072
01073 int64_t bd_seek(BLURAY *bd, uint64_t pos)
01074 {
01075 uint32_t pkt, clip_pkt, out_pkt, out_time;
01076 NAV_CLIP *clip;
01077
01078 if (bd->title &&
01079 pos < (uint64_t)bd->title->packets * 192) {
01080
01081 pkt = pos / 192;
01082
01083 _change_angle(bd);
01084
01085
01086 clip = nav_packet_search(bd->title, pkt, &clip_pkt, &out_pkt, &out_time);
01087
01088 return _seek_internal(bd, clip, out_pkt, clip_pkt);
01089 }
01090
01091 return bd->s_pos;
01092 }
01093
01094 uint64_t bd_get_title_size(BLURAY *bd)
01095 {
01096 if (bd && bd->title) {
01097 return (uint64_t)bd->title->packets * 192;
01098 }
01099 return UINT64_C(0);
01100 }
01101
01102 uint64_t bd_tell(BLURAY *bd)
01103 {
01104 return bd ? bd->s_pos : INT64_C(0);
01105 }
01106
01107
01108
01109
01110
01111 static int64_t _clip_seek_time(BLURAY *bd, uint64_t tick)
01112 {
01113 uint32_t clip_pkt, out_pkt;
01114
01115 if (tick < bd->st0.clip->out_time) {
01116
01117
01118 nav_clip_time_search(bd->st0.clip, tick, &clip_pkt, &out_pkt);
01119
01120 return _seek_internal(bd, bd->st0.clip, out_pkt, clip_pkt);
01121 }
01122
01123 return bd->s_pos;
01124 }
01125
01126 int bd_read(BLURAY *bd, unsigned char *buf, int len)
01127 {
01128 BD_STREAM *st = &bd->st0;
01129 int out_len;
01130
01131 if (st->fp) {
01132 out_len = 0;
01133 BD_DEBUG(DBG_STREAM, "Reading [%d bytes] at %"PRIu64"... (%p)\n", len, bd->s_pos, bd);
01134
01135 while (len > 0) {
01136 uint32_t clip_pkt;
01137
01138 unsigned int size = len;
01139
01140 clip_pkt = st->clip_pos / 192;
01141 if (bd->seamless_angle_change) {
01142 if (clip_pkt >= bd->angle_change_pkt) {
01143 if (clip_pkt >= st->clip->end_pkt) {
01144 st->clip = nav_next_clip(bd->title, st->clip);
01145 if (!_open_m2ts(bd, st)) {
01146 return -1;
01147 }
01148 bd->s_pos = st->clip->pos;
01149 } else {
01150 _change_angle(bd);
01151 _clip_seek_time(bd, bd->angle_change_time);
01152 }
01153 bd->seamless_angle_change = 0;
01154 } else {
01155 uint64_t angle_pos;
01156
01157 angle_pos = bd->angle_change_pkt * 192;
01158 if (angle_pos - st->clip_pos < size)
01159 {
01160 size = angle_pos - st->clip_pos;
01161 }
01162 }
01163 }
01164 if (st->int_buf_off == 6144 || clip_pkt >= st->clip->end_pkt) {
01165
01166
01167 if (st->clip == NULL) {
01168
01169
01170 _queue_event(bd, (BD_EVENT){BD_EVENT_END_OF_TITLE, 0});
01171 return 0;
01172 }
01173 if (clip_pkt >= st->clip->end_pkt) {
01174
01175
01176 if (out_len) {
01177 return out_len;
01178 }
01179
01180 MPLS_PI *pi = &st->clip->title->pl->play_item[st->clip->ref];
01181
01182
01183 if (pi->still_mode == BLURAY_STILL_INFINITE) {
01184 _queue_event(bd, (BD_EVENT){BD_EVENT_STILL_TIME, 0});
01185 return 0;
01186 }
01187 if (pi->still_mode == BLURAY_STILL_TIME) {
01188 if (bd->event_queue) {
01189 _queue_event(bd, (BD_EVENT){BD_EVENT_STILL_TIME, pi->still_time});
01190 return 0;
01191 }
01192 }
01193
01194
01195 st->clip = nav_next_clip(bd->title, st->clip);
01196 if (st->clip == NULL) {
01197 BD_DEBUG(DBG_BLURAY|DBG_STREAM, "End of title (%p)\n", bd);
01198 _queue_event(bd, (BD_EVENT){BD_EVENT_END_OF_TITLE, 0});
01199 return 0;
01200 }
01201 if (!_open_m2ts(bd, st)) {
01202 return -1;
01203 }
01204 }
01205
01206 if (_read_block(bd, st, bd->int_buf)) {
01207
01208 st->int_buf_off = st->clip_pos % 6144;
01209
01210 } else {
01211 return out_len;
01212 }
01213 }
01214 if (size > (unsigned int)6144 - st->int_buf_off) {
01215 size = 6144 - st->int_buf_off;
01216 }
01217 memcpy(buf, bd->int_buf + st->int_buf_off, size);
01218 buf += size;
01219 len -= size;
01220 out_len += size;
01221 st->clip_pos += size;
01222 st->int_buf_off += size;
01223 bd->s_pos += size;
01224 }
01225
01226
01227 if (bd->s_pos > bd->next_chapter_start) {
01228 _update_chapter_psr(bd);
01229 }
01230
01231 BD_DEBUG(DBG_STREAM, "%d bytes read OK! (%p)\n", out_len, bd);
01232
01233 return out_len;
01234 }
01235
01236 BD_DEBUG(DBG_STREAM | DBG_CRIT, "bd_read(): no valid title selected! (%p)\n", bd);
01237
01238 return -1;
01239 }
01240
01241 int bd_read_skip_still(BLURAY *bd)
01242 {
01243 BD_STREAM *st = &bd->st0;
01244
01245 if (st->clip) {
01246 MPLS_PI *pi = &st->clip->title->pl->play_item[st->clip->ref];
01247
01248 if (pi->still_mode == BLURAY_STILL_TIME) {
01249 st->clip = nav_next_clip(bd->title, st->clip);
01250 if (st->clip) {
01251 return _open_m2ts(bd, st);
01252 }
01253 }
01254 }
01255
01256 return 0;
01257 }
01258
01259
01260
01261
01262
01263 static int _find_ig_stream(BLURAY *bd, uint16_t *pid, int *sub_path_idx)
01264 {
01265 MPLS_PI *pi = &bd->title->pl->play_item[0];
01266 unsigned ig_stream = bd_psr_read(bd->regs, PSR_IG_STREAM_ID);
01267
01268 if (ig_stream > 0 && ig_stream <= pi->stn.num_ig) {
01269 ig_stream--;
01270 if (pi->stn.ig[ig_stream].stream_type == 2) {
01271 *sub_path_idx = pi->stn.ig[ig_stream].subpath_id;
01272 }
01273 *pid = pi->stn.ig[ig_stream].pid;
01274
01275 BD_DEBUG(DBG_BLURAY, "_find_ig_stream(): current IG stream pid 0x%04x sub-path %d\n",
01276 *pid, *sub_path_idx);
01277 return 1;
01278 }
01279
01280 return 0;
01281 }
01282
01283 static int _preload_ig_subpath(BLURAY *bd)
01284 {
01285 int ig_subpath = -1;
01286 uint16_t ig_pid = 0;
01287
01288 _find_ig_stream(bd, &ig_pid, &ig_subpath);
01289
01290 if (!bd->graphics_controller) {
01291 return 0;
01292 }
01293
01294 if (ig_subpath < 0) {
01295 return 0;
01296 }
01297
01298 bd->st_ig.clip = &bd->title->sub_path[ig_subpath].clip_list.clip[0];
01299
01300 if (!_preload_m2ts(bd, &bd->st_ig)) {
01301 return 0;
01302 }
01303
01304 gc_decode_ts(bd->graphics_controller, ig_pid, bd->st_ig.buf, bd->st_ig.clip_size / 6144, -1);
01305
01306 return 1;
01307 }
01308
01309 static int _preload_subpaths(BLURAY *bd)
01310 {
01311 if (bd->title->pl->sub_count <= 0) {
01312 return 0;
01313 }
01314
01315 return _preload_ig_subpath(bd);
01316 }
01317
01318
01319
01320
01321
01322 static void _close_playlist(BLURAY *bd)
01323 {
01324 if (bd->graphics_controller) {
01325 gc_run(bd->graphics_controller, GC_CTRL_RESET, 0, NULL);
01326 }
01327
01328 _close_m2ts(&bd->st0);
01329 _close_preload(&bd->st_ig);
01330
01331 if (bd->title) {
01332 nav_title_close(bd->title);
01333 bd->title = NULL;
01334 }
01335 }
01336
01337 static int _open_playlist(BLURAY *bd, const char *f_name, unsigned angle)
01338 {
01339 _close_playlist(bd);
01340
01341 bd->title = nav_title_open(bd->device_path, f_name, angle);
01342 if (bd->title == NULL) {
01343 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open title %s! (%p)\n",
01344 f_name, bd);
01345 return 0;
01346 }
01347
01348 bd->seamless_angle_change = 0;
01349 bd->s_pos = 0;
01350
01351 bd->next_chapter_start = bd_chapter_pos(bd, 1);
01352
01353 bd_psr_write(bd->regs, PSR_PLAYLIST, atoi(bd->title->name));
01354 bd_psr_write(bd->regs, PSR_ANGLE_NUMBER, bd->title->angle + 1);
01355 bd_psr_write(bd->regs, PSR_CHAPTER, 1);
01356
01357
01358 bd->st0.clip = nav_next_clip(bd->title, NULL);
01359 if (_open_m2ts(bd, &bd->st0)) {
01360 BD_DEBUG(DBG_BLURAY, "Title %s selected! (%p)\n", f_name, bd);
01361
01362 _preload_subpaths(bd);
01363
01364 return 1;
01365 }
01366 return 0;
01367 }
01368
01369 int bd_select_playlist(BLURAY *bd, uint32_t playlist)
01370 {
01371 char *f_name = str_printf("%05d.mpls", playlist);
01372 int result;
01373
01374 if (bd->title_list) {
01375
01376 unsigned i;
01377 for (i = 0; i < bd->title_list->count; i++) {
01378 if (playlist == bd->title_list->title_info[i].mpls_id) {
01379 bd->title_idx = i;
01380 break;
01381 }
01382 }
01383 }
01384
01385 result = _open_playlist(bd, f_name, 0);
01386
01387 X_FREE(f_name);
01388 return result;
01389 }
01390
01391
01392
01393
01394 int bd_select_title(BLURAY *bd, uint32_t title_idx)
01395 {
01396 const char *f_name;
01397
01398
01399 if (bd->title_list == NULL) {
01400 BD_DEBUG(DBG_BLURAY, "Title list not yet read! (%p)\n", bd);
01401 return 0;
01402 }
01403 if (bd->title_list->count <= title_idx) {
01404 BD_DEBUG(DBG_BLURAY, "Invalid title index %d! (%p)\n", title_idx, bd);
01405 return 0;
01406 }
01407
01408 bd->title_idx = title_idx;
01409 f_name = bd->title_list->title_info[title_idx].name;
01410
01411 return _open_playlist(bd, f_name, 0);
01412 }
01413
01414 uint32_t bd_get_current_title(BLURAY *bd)
01415 {
01416 return bd->title_idx;
01417 }
01418
01419 int bd_select_angle(BLURAY *bd, unsigned angle)
01420 {
01421 unsigned orig_angle;
01422
01423 if (bd->title == NULL) {
01424 BD_DEBUG(DBG_BLURAY, "Title not yet selected! (%p)\n", bd);
01425 return 0;
01426 }
01427
01428 orig_angle = bd->title->angle;
01429
01430 bd->st0.clip = nav_set_angle(bd->title, bd->st0.clip, angle);
01431
01432 if (orig_angle == bd->title->angle) {
01433 return 1;
01434 }
01435
01436 bd_psr_write(bd->regs, PSR_ANGLE_NUMBER, bd->title->angle + 1);
01437
01438 if (!_open_m2ts(bd, &bd->st0)) {
01439 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "Error selecting angle %d ! (%p)\n", angle, bd);
01440 return 0;
01441 }
01442
01443 return 1;
01444 }
01445
01446 unsigned bd_get_current_angle(BLURAY *bd)
01447 {
01448 if (bd->title) {
01449 return bd->title->angle;
01450 }
01451 return 0;
01452 }
01453
01454
01455 void bd_seamless_angle_change(BLURAY *bd, unsigned angle)
01456 {
01457 uint32_t clip_pkt;
01458
01459 clip_pkt = (bd->st0.clip_pos + 191) / 192;
01460 bd->angle_change_pkt = nav_angle_change_search(bd->st0.clip, clip_pkt,
01461 &bd->angle_change_time);
01462 bd->request_angle = angle;
01463 bd->seamless_angle_change = 1;
01464 }
01465
01466
01467
01468
01469
01470 uint32_t bd_get_titles(BLURAY *bd, uint8_t flags, uint32_t min_title_length)
01471 {
01472 if (!bd) {
01473 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_get_titles(NULL) failed (%p)\n", bd);
01474 return 0;
01475 }
01476
01477 if (bd->title_list != NULL) {
01478 nav_free_title_list(bd->title_list);
01479 }
01480 bd->title_list = nav_get_title_list(bd->device_path, flags, min_title_length);
01481
01482 if (!bd->title_list) {
01483 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "nav_get_title_list(%s) failed (%p)\n", bd->device_path, bd);
01484 return 0;
01485 }
01486
01487 return bd->title_list->count;
01488 }
01489
01490 static void _copy_streams(NAV_CLIP *clip, BLURAY_STREAM_INFO *streams, MPLS_STREAM *si, int count)
01491 {
01492 int ii;
01493
01494 for (ii = 0; ii < count; ii++) {
01495 streams[ii].coding_type = si[ii].coding_type;
01496 streams[ii].format = si[ii].format;
01497 streams[ii].rate = si[ii].rate;
01498 streams[ii].char_code = si[ii].char_code;
01499 memcpy(streams[ii].lang, si[ii].lang, 4);
01500 streams[ii].pid = si[ii].pid;
01501 streams[ii].aspect = nav_lookup_aspect(clip, si[ii].pid);
01502 }
01503 }
01504
01505 static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, uint32_t playlist)
01506 {
01507 BLURAY_TITLE_INFO *title_info;
01508 unsigned int ii;
01509
01510 title_info = calloc(1, sizeof(BLURAY_TITLE_INFO));
01511 title_info->idx = title_idx;
01512 title_info->playlist = playlist;
01513 title_info->duration = (uint64_t)title->duration * 2;
01514 title_info->angle_count = title->angle_count;
01515 title_info->chapter_count = title->chap_list.count;
01516 title_info->chapters = calloc(title_info->chapter_count, sizeof(BLURAY_TITLE_CHAPTER));
01517 for (ii = 0; ii < title_info->chapter_count; ii++) {
01518 title_info->chapters[ii].idx = ii;
01519 title_info->chapters[ii].start = (uint64_t)title->chap_list.mark[ii].title_time * 2;
01520 title_info->chapters[ii].duration = (uint64_t)title->chap_list.mark[ii].duration * 2;
01521 title_info->chapters[ii].offset = (uint64_t)title->chap_list.mark[ii].title_pkt * 192L;
01522 }
01523 title_info->clip_count = title->clip_list.count;
01524 title_info->clips = calloc(title_info->clip_count, sizeof(BLURAY_CLIP_INFO));
01525 for (ii = 0; ii < title_info->clip_count; ii++) {
01526 MPLS_PI *pi = &title->pl->play_item[ii];
01527 BLURAY_CLIP_INFO *ci = &title_info->clips[ii];
01528 NAV_CLIP *nc = &title->clip_list.clip[ii];
01529
01530 ci->pkt_count = nc->end_pkt - nc->start_pkt;
01531 ci->still_mode = pi->still_mode;
01532 ci->still_time = pi->still_time;
01533 ci->video_stream_count = pi->stn.num_video;
01534 ci->audio_stream_count = pi->stn.num_audio;
01535 ci->pg_stream_count = pi->stn.num_pg + pi->stn.num_pip_pg;
01536 ci->ig_stream_count = pi->stn.num_ig;
01537 ci->sec_video_stream_count = pi->stn.num_secondary_video;
01538 ci->sec_audio_stream_count = pi->stn.num_secondary_audio;
01539 ci->video_streams = calloc(ci->video_stream_count, sizeof(BLURAY_STREAM_INFO));
01540 ci->audio_streams = calloc(ci->audio_stream_count, sizeof(BLURAY_STREAM_INFO));
01541 ci->pg_streams = calloc(ci->pg_stream_count, sizeof(BLURAY_STREAM_INFO));
01542 ci->ig_streams = calloc(ci->ig_stream_count, sizeof(BLURAY_STREAM_INFO));
01543 ci->sec_video_streams = calloc(ci->sec_video_stream_count, sizeof(BLURAY_STREAM_INFO));
01544 ci->sec_audio_streams = calloc(ci->sec_audio_stream_count, sizeof(BLURAY_STREAM_INFO));
01545 _copy_streams(nc, ci->video_streams, pi->stn.video, ci->video_stream_count);
01546 _copy_streams(nc, ci->audio_streams, pi->stn.audio, ci->audio_stream_count);
01547 _copy_streams(nc, ci->pg_streams, pi->stn.pg, ci->pg_stream_count);
01548 _copy_streams(nc, ci->ig_streams, pi->stn.ig, ci->ig_stream_count);
01549 _copy_streams(nc, ci->sec_video_streams, pi->stn.secondary_video, ci->sec_video_stream_count);
01550 _copy_streams(nc, ci->sec_audio_streams, pi->stn.secondary_audio, ci->sec_audio_stream_count);
01551 }
01552
01553 return title_info;
01554 }
01555
01556 static BLURAY_TITLE_INFO *_get_title_info(BLURAY *bd, uint32_t title_idx, uint32_t playlist, const char *mpls_name,
01557 unsigned angle)
01558 {
01559 NAV_TITLE *title;
01560 BLURAY_TITLE_INFO *title_info;
01561
01562 title = nav_title_open(bd->device_path, mpls_name, angle);
01563 if (title == NULL) {
01564 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open title %s! (%p)\n",
01565 mpls_name, bd);
01566 return NULL;
01567 }
01568
01569 title_info = _fill_title_info(title, title_idx, playlist);
01570
01571 nav_title_close(title);
01572 return title_info;
01573 }
01574
01575 BLURAY_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx, unsigned angle)
01576 {
01577 if (bd->title_list == NULL) {
01578 BD_DEBUG(DBG_BLURAY, "Title list not yet read! (%p)\n", bd);
01579 return NULL;
01580 }
01581 if (bd->title_list->count <= title_idx) {
01582 BD_DEBUG(DBG_BLURAY, "Invalid title index %d! (%p)\n", title_idx, bd);
01583 return NULL;
01584 }
01585
01586 return _get_title_info(bd,
01587 title_idx, bd->title_list->title_info[title_idx].mpls_id,
01588 bd->title_list->title_info[title_idx].name,
01589 angle);
01590 }
01591
01592 BLURAY_TITLE_INFO* bd_get_playlist_info(BLURAY *bd, uint32_t playlist, unsigned angle)
01593 {
01594 char *f_name = str_printf("%05d.mpls", playlist);
01595 BLURAY_TITLE_INFO *title_info;
01596
01597 title_info = _get_title_info(bd, 0, playlist, f_name, angle);
01598
01599 X_FREE(f_name);
01600
01601 return title_info;
01602 }
01603
01604 void bd_free_title_info(BLURAY_TITLE_INFO *title_info)
01605 {
01606 unsigned int ii;
01607
01608 X_FREE(title_info->chapters);
01609 for (ii = 0; ii < title_info->clip_count; ii++) {
01610 X_FREE(title_info->clips[ii].video_streams);
01611 X_FREE(title_info->clips[ii].audio_streams);
01612 X_FREE(title_info->clips[ii].pg_streams);
01613 X_FREE(title_info->clips[ii].ig_streams);
01614 X_FREE(title_info->clips[ii].sec_video_streams);
01615 X_FREE(title_info->clips[ii].sec_audio_streams);
01616 }
01617 X_FREE(title_info->clips);
01618 X_FREE(title_info);
01619 }
01620
01621
01622
01623
01624
01625 int bd_set_player_setting(BLURAY *bd, uint32_t idx, uint32_t value)
01626 {
01627 static const struct { uint32_t idx; uint32_t psr; } map[] = {
01628 { BLURAY_PLAYER_SETTING_PARENTAL, PSR_PARENTAL },
01629 { BLURAY_PLAYER_SETTING_AUDIO_CAP, PSR_AUDIO_CAP },
01630 { BLURAY_PLAYER_SETTING_AUDIO_LANG, PSR_AUDIO_LANG },
01631 { BLURAY_PLAYER_SETTING_PG_LANG, PSR_PG_AND_SUB_LANG },
01632 { BLURAY_PLAYER_SETTING_MENU_LANG, PSR_MENU_LANG },
01633 { BLURAY_PLAYER_SETTING_COUNTRY_CODE, PSR_COUNTRY },
01634 { BLURAY_PLAYER_SETTING_REGION_CODE, PSR_REGION },
01635 { BLURAY_PLAYER_SETTING_VIDEO_CAP, PSR_VIDEO_CAP },
01636 { BLURAY_PLAYER_SETTING_TEXT_CAP, PSR_TEXT_CAP },
01637 { BLURAY_PLAYER_SETTING_PLAYER_PROFILE, PSR_PROFILE_VERSION },
01638 };
01639
01640 unsigned i;
01641
01642 if (idx == BLURAY_PLAYER_SETTING_PLAYER_PROFILE) {
01643 value = ((value & 0xf) << 16) | 0x0200;
01644 }
01645
01646 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
01647 if (idx == map[i].idx) {
01648 return !bd_psr_setting_write(bd->regs, idx, value);
01649 }
01650 }
01651
01652 return 0;
01653 }
01654
01655 int bd_set_player_setting_str(BLURAY *bd, uint32_t idx, const char *s)
01656 {
01657 switch (idx) {
01658 case BLURAY_PLAYER_SETTING_AUDIO_LANG:
01659 case BLURAY_PLAYER_SETTING_PG_LANG:
01660 case BLURAY_PLAYER_SETTING_MENU_LANG:
01661 return bd_set_player_setting(bd, idx, str_to_uint32(s, 3));
01662
01663 case BLURAY_PLAYER_SETTING_COUNTRY_CODE:
01664 return bd_set_player_setting(bd, idx, str_to_uint32(s, 2));
01665
01666 default:
01667 return 0;
01668 }
01669 }
01670
01671
01672
01673
01674
01675 int bd_start_bdj(BLURAY *bd, const char *start_object)
01676 {
01677 #ifdef USING_BDJAVA
01678 if (bd->bdjava == NULL) {
01679 bd->bdjava = bdj_open(bd->device_path, start_object, bd, bd->regs);
01680 return !!bd->bdjava;
01681 } else {
01682 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "BD-J is already running (%p)\n", bd);
01683 return 1;
01684 }
01685 #else
01686 BD_DEBUG(DBG_BLURAY | DBG_CRIT, "%s.bdjo: BD-J not compiled in (%p)\n", start_object, bd);
01687 #endif
01688 return 0;
01689 }
01690
01691 void bd_stop_bdj(BLURAY *bd)
01692 {
01693 if (bd->bdjava != NULL) {
01694 #ifdef USING_BDJAVA
01695 bdj_close((BDJAVA*)bd->bdjava);
01696 #else
01697 BD_DEBUG(DBG_BLURAY, "BD-J not compiled in (%p)\n", bd);
01698 #endif
01699 bd->bdjava = NULL;
01700 }
01701 }
01702
01703
01704
01705
01706
01707 static void _process_psr_restore_event(BLURAY *bd, BD_PSR_EVENT *ev)
01708 {
01709
01710
01711
01712
01713 BD_DEBUG(DBG_BLURAY, "PSR restore: psr%u = %u (%p)\n", ev->psr_idx, ev->new_val, bd);
01714
01715 switch (ev->psr_idx) {
01716 case PSR_ANGLE_NUMBER:
01717
01718 return;
01719 case PSR_TITLE_NUMBER:
01720
01721 _queue_event(bd, (BD_EVENT){BD_EVENT_TITLE, ev->new_val});
01722 return;
01723 case PSR_CHAPTER:
01724
01725 return;
01726 case PSR_PLAYLIST:
01727 bd_select_playlist(bd, ev->new_val);
01728 nav_set_angle(bd->title, bd->st0.clip, bd_psr_read(bd->regs, PSR_ANGLE_NUMBER) - 1);
01729 return;
01730 case PSR_PLAYITEM:
01731 bd_seek_playitem(bd, ev->new_val);
01732 return;
01733 case PSR_TIME:
01734 bd_seek_time(bd, ((int64_t)ev->new_val) << 1);
01735 return;
01736
01737 case PSR_SELECTED_BUTTON_ID:
01738 case PSR_MENU_PAGE_ID:
01739
01740 return;
01741
01742 default:
01743
01744 return;
01745 }
01746 }
01747
01748
01749
01750
01751
01752 static void _process_psr_write_event(BLURAY *bd, BD_PSR_EVENT *ev)
01753 {
01754 if (ev->ev_type == BD_PSR_WRITE) {
01755 BD_DEBUG(DBG_BLURAY, "PSR write: psr%u = %u (%p)\n", ev->psr_idx, ev->new_val, bd);
01756 }
01757
01758 switch (ev->psr_idx) {
01759
01760
01761
01762 case PSR_ANGLE_NUMBER: _queue_event(bd, (BD_EVENT){BD_EVENT_ANGLE, ev->new_val}); break;
01763 case PSR_TITLE_NUMBER: _queue_event(bd, (BD_EVENT){BD_EVENT_TITLE, ev->new_val}); break;
01764 case PSR_PLAYLIST: _queue_event(bd, (BD_EVENT){BD_EVENT_PLAYLIST, ev->new_val}); break;
01765 case PSR_PLAYITEM: _queue_event(bd, (BD_EVENT){BD_EVENT_PLAYITEM, ev->new_val}); break;
01766 case PSR_CHAPTER: _queue_event(bd, (BD_EVENT){BD_EVENT_CHAPTER, ev->new_val}); break;
01767
01768 default:;
01769 }
01770 }
01771
01772 static void _process_psr_change_event(BLURAY *bd, BD_PSR_EVENT *ev)
01773 {
01774 BD_DEBUG(DBG_BLURAY, "PSR change: psr%u = %u (%p)\n", ev->psr_idx, ev->new_val, bd);
01775
01776 _process_psr_write_event(bd, ev);
01777
01778 switch (ev->psr_idx) {
01779
01780
01781
01782 case PSR_IG_STREAM_ID:
01783 _queue_event(bd, (BD_EVENT){BD_EVENT_IG_STREAM, ev->new_val});
01784 break;
01785
01786 case PSR_PRIMARY_AUDIO_ID:
01787 _queue_event(bd, (BD_EVENT){BD_EVENT_AUDIO_STREAM, ev->new_val});
01788 break;
01789
01790 case PSR_PG_STREAM:
01791 if ((ev->new_val & 0x80000fff) != (ev->old_val & 0x80000fff)) {
01792 _queue_event(bd, (BD_EVENT){BD_EVENT_PG_TEXTST, !!(ev->new_val & 0x80000000)});
01793 _queue_event(bd, (BD_EVENT){BD_EVENT_PG_TEXTST_STREAM, ev->new_val & 0xfff});
01794 }
01795 break;
01796
01797 case PSR_SECONDARY_AUDIO_VIDEO:
01798
01799 if ((ev->new_val & 0x8f00ff00) != (ev->old_val & 0x8f00ff00)) {
01800 _queue_event(bd, (BD_EVENT){BD_EVENT_SECONDARY_VIDEO, !!(ev->new_val & 0x80000000)});
01801 _queue_event(bd, (BD_EVENT){BD_EVENT_SECONDARY_VIDEO_SIZE, (ev->new_val >> 24) & 0xf});
01802 _queue_event(bd, (BD_EVENT){BD_EVENT_SECONDARY_VIDEO_STREAM, (ev->new_val & 0xff00) >> 8});
01803 }
01804
01805 if ((ev->new_val & 0x400000ff) != (ev->old_val & 0x400000ff)) {
01806 _queue_event(bd, (BD_EVENT){BD_EVENT_SECONDARY_AUDIO, !!(ev->new_val & 0x40000000)});
01807 _queue_event(bd, (BD_EVENT){BD_EVENT_SECONDARY_AUDIO_STREAM, ev->new_val & 0xff});
01808 }
01809 break;
01810
01811 default:;
01812 }
01813 }
01814
01815 static void _process_psr_event(void *handle, BD_PSR_EVENT *ev)
01816 {
01817 BLURAY *bd = (BLURAY*)handle;
01818
01819 switch(ev->ev_type) {
01820 case BD_PSR_WRITE:
01821 _process_psr_write_event(bd, ev);
01822 break;
01823 case BD_PSR_CHANGE:
01824 _process_psr_change_event(bd, ev);
01825 break;
01826 case BD_PSR_RESTORE:
01827 _process_psr_restore_event(bd, ev);
01828 break;
01829
01830 case BD_PSR_SAVE:
01831 BD_DEBUG(DBG_BLURAY, "PSR save event (%p)\n", bd);
01832 break;
01833 default:
01834 BD_DEBUG(DBG_BLURAY, "PSR event %d: psr%u = %u (%p)\n", ev->ev_type, ev->psr_idx, ev->new_val, bd);
01835 break;
01836 }
01837 }
01838
01839 static void _queue_initial_psr_events(BLURAY *bd)
01840 {
01841 const uint32_t psrs[] = {
01842 PSR_ANGLE_NUMBER,
01843 PSR_TITLE_NUMBER,
01844 PSR_CHAPTER,
01845 PSR_PLAYLIST,
01846 PSR_PLAYITEM,
01847 PSR_IG_STREAM_ID,
01848 PSR_PRIMARY_AUDIO_ID,
01849 PSR_PG_STREAM,
01850 PSR_SECONDARY_AUDIO_VIDEO,
01851 };
01852 unsigned ii;
01853
01854 for (ii = 0; ii < sizeof(psrs) / sizeof(psrs[0]); ii++) {
01855 BD_PSR_EVENT ev = {
01856 .ev_type = BD_PSR_CHANGE,
01857 .psr_idx = psrs[ii],
01858 .old_val = 0,
01859 .new_val = bd_psr_read(bd->regs, psrs[ii]),
01860 };
01861
01862 _process_psr_change_event(bd, &ev);
01863 }
01864 }
01865
01866 static int _play_bdj(BLURAY *bd, const char *name)
01867 {
01868 bd->title_type = title_bdj;
01869
01870 #ifdef USING_BDJAVA
01871 bd_stop_bdj(bd);
01872 return bd_start_bdj(bd, name);
01873 #else
01874 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "_bdj_play(BDMV/BDJ/%s.jar) not implemented (%p)\n", name, bd);
01875 return 0;
01876 #endif
01877 }
01878
01879 static int _play_hdmv(BLURAY *bd, unsigned id_ref)
01880 {
01881 int result = 1;
01882
01883 bd->title_type = title_hdmv;
01884
01885 #ifdef USING_BDJAVA
01886 bd_stop_bdj(bd);
01887 #endif
01888
01889 if (!bd->hdmv_vm) {
01890 bd->hdmv_vm = hdmv_vm_init(bd->device_path, bd->regs, bd->index);
01891 }
01892
01893 if (hdmv_vm_select_object(bd->hdmv_vm, id_ref)) {
01894 result = 0;
01895 }
01896
01897 bd->hdmv_suspended = !hdmv_vm_running(bd->hdmv_vm);
01898
01899 return result;
01900 }
01901
01902 static int _play_title(BLURAY *bd, unsigned title)
01903 {
01904
01905 if (title == BLURAY_TITLE_FIRST_PLAY) {
01906 INDX_PLAY_ITEM *p = &bd->index->first_play;
01907
01908 bd_psr_write(bd->regs, PSR_TITLE_NUMBER, 0xffff);
01909
01910 if (p->object_type == indx_object_type_hdmv) {
01911 if (p->hdmv.id_ref == 0xffff) {
01912
01913 bd->title_type = title_hdmv;
01914 return 1;
01915 }
01916 return _play_hdmv(bd, p->hdmv.id_ref);
01917 }
01918
01919 if (p->object_type == indx_object_type_bdj) {
01920 return _play_bdj(bd, p->bdj.name);
01921 }
01922
01923 return 0;
01924 }
01925
01926
01927 if (bd->title_type == title_undef) {
01928 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_call_title(): bd_play() not called !\n");
01929 return 0;
01930 }
01931
01932
01933 if (title == BLURAY_TITLE_TOP_MENU) {
01934 INDX_PLAY_ITEM *p = &bd->index->top_menu;
01935
01936 bd_psr_write(bd->regs, PSR_TITLE_NUMBER, 0);
01937
01938 if (p->object_type == indx_object_type_hdmv) {
01939 if (p->hdmv.id_ref == 0xffff) {
01940
01941 bd->title_type = title_hdmv;
01942 return 0;
01943 }
01944 return _play_hdmv(bd, p->hdmv.id_ref);
01945 }
01946
01947 if (p->object_type == indx_object_type_bdj) {
01948 return _play_bdj(bd, p->bdj.name);
01949 }
01950
01951 return 0;
01952 }
01953
01954
01955 if (title > 0 && title <= bd->index->num_titles) {
01956 INDX_TITLE *t = &bd->index->titles[title-1];
01957
01958 bd_psr_write(bd->regs, PSR_TITLE_NUMBER, title);
01959
01960 if (t->object_type == indx_object_type_hdmv) {
01961 return _play_hdmv(bd, t->hdmv.id_ref);
01962 } else {
01963 return _play_bdj(bd, t->bdj.name);
01964 }
01965 }
01966
01967 return 0;
01968 }
01969
01970 int bd_play(BLURAY *bd)
01971 {
01972
01973
01974 bd->title_type = title_undef;
01975
01976 if (bd->hdmv_vm) {
01977 hdmv_vm_free(&bd->hdmv_vm);
01978 }
01979
01980 _init_event_queue(bd);
01981
01982 bd_psr_lock(bd->regs);
01983 bd_psr_register_cb(bd->regs, _process_psr_event, bd);
01984 _queue_initial_psr_events(bd);
01985 bd_psr_unlock(bd->regs);
01986
01987 return _play_title(bd, BLURAY_TITLE_FIRST_PLAY);
01988 }
01989
01990 int bd_play_title(BLURAY *bd, unsigned title)
01991 {
01992 if (bd->title_type == title_undef && title != BLURAY_TITLE_FIRST_PLAY) {
01993 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_play_title(): bd_play() not called\n");
01994 return 0;
01995 }
01996
01997 if (bd->st0.uo_mask.title_search) {
01998 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "title search masked by stream\n");
01999 return 0;
02000 }
02001
02002 if (bd->title_type == title_hdmv) {
02003 if (hdmv_vm_get_uo_mask(bd->hdmv_vm) & HDMV_TITLE_SEARCH_MASK) {
02004 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "title search masked by movie object\n");
02005 return 0;
02006 }
02007 }
02008
02009 return _play_title(bd, title);
02010 }
02011
02012 int bd_menu_call(BLURAY *bd, int64_t pts)
02013 {
02014 if (pts >= 0) {
02015 bd_psr_write(bd->regs, PSR_TIME, (uint32_t)(((uint64_t)pts) >> 1));
02016 }
02017
02018 if (bd->title_type == title_undef) {
02019 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_menu_call(): bd_play() not called\n");
02020 return 0;
02021 }
02022
02023 if (bd->st0.uo_mask.menu_call) {
02024 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "menu call masked by stream\n");
02025 return 0;
02026 }
02027
02028 if (bd->title_type == title_hdmv) {
02029 if (hdmv_vm_get_uo_mask(bd->hdmv_vm) & HDMV_MENU_CALL_MASK) {
02030 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "menu call masked by movie object\n");
02031 return 0;
02032 }
02033
02034 if (hdmv_vm_suspend_pl(bd->hdmv_vm) < 0) {
02035 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_menu_call(): error storing playback location\n");
02036 }
02037 }
02038
02039 return _play_title(bd, BLURAY_TITLE_TOP_MENU);
02040 }
02041
02042 static int _run_gc(BLURAY *bd, gc_ctrl_e msg, uint32_t param)
02043 {
02044 int result = -1;
02045
02046 if (bd && bd->graphics_controller && bd->hdmv_vm) {
02047 GC_NAV_CMDS cmds = {-1, NULL, -1};
02048
02049 result = gc_run(bd->graphics_controller, msg, param, &cmds);
02050
02051 if (cmds.num_nav_cmds > 0) {
02052 hdmv_vm_set_object(bd->hdmv_vm, cmds.num_nav_cmds, cmds.nav_cmds);
02053 bd->hdmv_suspended = !hdmv_vm_running(bd->hdmv_vm);
02054 }
02055 }
02056
02057 return result;
02058 }
02059
02060 static void _process_hdmv_vm_event(BLURAY *bd, HDMV_EVENT *hev)
02061 {
02062 BD_DEBUG(DBG_BLURAY, "HDMV event: %d %d\n", hev->event, hev->param);
02063
02064 switch (hev->event) {
02065 case HDMV_EVENT_TITLE:
02066 _close_playlist(bd);
02067 _play_title(bd, hev->param);
02068 break;
02069
02070 case HDMV_EVENT_PLAY_PL:
02071 bd_select_playlist(bd, hev->param);
02072
02073 _run_gc(bd, GC_CTRL_NOP, 0);
02074 break;
02075
02076 case HDMV_EVENT_PLAY_PI:
02077 _queue_event(bd, (BD_EVENT){BD_EVENT_SEEK, 0});
02078 bd_seek_playitem(bd, hev->param);
02079 break;
02080
02081 case HDMV_EVENT_PLAY_PM:
02082 _queue_event(bd, (BD_EVENT){BD_EVENT_SEEK, 0});
02083 bd_seek_mark(bd, hev->param);
02084 break;
02085
02086 case HDMV_EVENT_PLAY_STOP:
02087
02088 _close_playlist(bd);
02089 break;
02090
02091 case HDMV_EVENT_STILL:
02092 _queue_event(bd, (BD_EVENT){BD_EVENT_STILL, hev->param});
02093 break;
02094
02095 case HDMV_EVENT_ENABLE_BUTTON:
02096 _run_gc(bd, GC_CTRL_ENABLE_BUTTON, hev->param);
02097 break;
02098
02099 case HDMV_EVENT_DISABLE_BUTTON:
02100 _run_gc(bd, GC_CTRL_DISABLE_BUTTON, hev->param);
02101 break;
02102
02103 case HDMV_EVENT_SET_BUTTON_PAGE:
02104 _run_gc(bd, GC_CTRL_SET_BUTTON_PAGE, hev->param);
02105 break;
02106
02107 case HDMV_EVENT_POPUP_OFF:
02108 _run_gc(bd, GC_CTRL_POPUP, 0);
02109 break;
02110
02111 case HDMV_EVENT_IG_END:
02112 _run_gc(bd, GC_CTRL_IG_END, 0);
02113 break;
02114
02115 case HDMV_EVENT_END:
02116 case HDMV_EVENT_NONE:
02117 default:
02118 break;
02119 }
02120 }
02121
02122 static int _run_hdmv(BLURAY *bd)
02123 {
02124 HDMV_EVENT hdmv_ev;
02125
02126
02127 if (hdmv_vm_run(bd->hdmv_vm, &hdmv_ev) < 0) {
02128 _queue_event(bd, (BD_EVENT){BD_EVENT_ERROR, 0});
02129 bd->hdmv_suspended = !hdmv_vm_running(bd->hdmv_vm);
02130 return -1;
02131 }
02132
02133
02134 do {
02135 _process_hdmv_vm_event(bd, &hdmv_ev);
02136
02137 } while (!hdmv_vm_get_event(bd->hdmv_vm, &hdmv_ev));
02138
02139
02140 bd->hdmv_suspended = !hdmv_vm_running(bd->hdmv_vm);
02141
02142 return 0;
02143 }
02144
02145 int bd_read_ext(BLURAY *bd, unsigned char *buf, int len, BD_EVENT *event)
02146 {
02147 if (_get_event(bd, event)) {
02148 return 0;
02149 }
02150
02151
02152 if (!bd->hdmv_suspended && bd->title_type == title_hdmv) {
02153
02154 while (!bd->hdmv_suspended) {
02155
02156 if (_run_hdmv(bd) < 0) {
02157 BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_read_ext(): HDMV VM error\n");
02158 bd->title_type = title_undef;
02159 return -1;
02160 }
02161 if (_get_event(bd, event)) {
02162 return 0;
02163 }
02164 }
02165 }
02166
02167 if (len < 1) {
02168
02169 return 0;
02170 }
02171
02172 int bytes = bd_read(bd, buf, len);
02173
02174 if (bytes == 0) {
02175
02176
02177 if (!bd->st0.clip && bd->title_type == title_hdmv) {
02178 hdmv_vm_resume(bd->hdmv_vm);
02179 bd->hdmv_suspended = !hdmv_vm_running(bd->hdmv_vm);
02180 BD_DEBUG(DBG_BLURAY, "bd_read_ext(): reached end of playlist. hdmv_suspended=%d\n", bd->hdmv_suspended);
02181 }
02182 }
02183
02184 _get_event(bd, event);
02185
02186 return bytes;
02187 }
02188
02189 int bd_get_event(BLURAY *bd, BD_EVENT *event)
02190 {
02191 if (!bd->event_queue) {
02192 _init_event_queue(bd);
02193
02194 bd_psr_register_cb(bd->regs, _process_psr_event, bd);
02195 _queue_initial_psr_events(bd);
02196 }
02197
02198 if (event) {
02199 return _get_event(bd, event);
02200 }
02201
02202 return 0;
02203 }
02204
02205
02206
02207
02208
02209 void bd_set_scr(BLURAY *bd, int64_t pts)
02210 {
02211 if (pts >= 0) {
02212 bd_psr_write(bd->regs, PSR_TIME, (uint32_t)(((uint64_t)pts) >> 1));
02213 }
02214 }
02215
02216 int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y)
02217 {
02218 bd_set_scr(bd, pts);
02219
02220 return _run_gc(bd, GC_CTRL_MOUSE_MOVE, (x << 16) | y);
02221 }
02222
02223 int bd_user_input(BLURAY *bd, int64_t pts, uint32_t key)
02224 {
02225 bd_set_scr(bd, pts);
02226
02227 return _run_gc(bd, GC_CTRL_VK_KEY, key);
02228 }
02229
02230 void bd_register_overlay_proc(BLURAY *bd, void *handle, bd_overlay_proc_f func)
02231 {
02232 if (!bd) {
02233 return;
02234 }
02235
02236 gc_free(&bd->graphics_controller);
02237
02238 if (func) {
02239 bd->graphics_controller = gc_init(bd->regs, handle, func);
02240 }
02241 }
02242
02243
02244
02245
02246
02247 struct meta_dl *bd_get_meta(BLURAY *bd)
02248 {
02249 if (!bd) {
02250 return NULL;
02251 }
02252
02253 if (!bd->meta) {
02254 _meta_open(bd);
02255 }
02256
02257 uint32_t psr_menu_lang = bd_psr_read(bd->regs, PSR_MENU_LANG);
02258
02259 if (psr_menu_lang != 0 && psr_menu_lang != 0xffffff) {
02260 const char language_code[] = {(psr_menu_lang >> 16) & 0xff, (psr_menu_lang >> 8) & 0xff, psr_menu_lang & 0xff, 0 };
02261 return meta_get(bd->meta, language_code);
02262 }
02263 else {
02264 return meta_get(bd->meta, NULL);
02265 }
02266 }
02267
02268 struct clpi_cl *bd_get_clpi(BLURAY *bd, unsigned clip_ref)
02269 {
02270 NAV_CLIP *clip;
02271
02272 if (bd->title && clip_ref < bd->title->clip_list.count) {
02273 clip = &bd->title->clip_list.clip[clip_ref];
02274 CLPI_CL *cl = (CLPI_CL*) calloc(1, sizeof(CLPI_CL));
02275 return clpi_copy(cl, clip->cl);
02276 }
02277 return NULL;
02278 }
02279
02280 void bd_free_clpi(struct clpi_cl *cl)
02281 {
02282 clpi_free(cl);
02283 }