MythTV  0.26-pre
bluray.c
Go to the documentation of this file.
00001 /*
00002  * This file is part of libbluray
00003  * Copyright (C) 2009-2010  Obliter0n
00004  * Copyright (C) 2009-2010  John Stebbins
00005  * Copyright (C) 2010       hpi1
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library. If not, see
00019  * <http://www.gnu.org/licenses/>.
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  /* 2^n - 1 */
00061 typedef struct bd_event_queue_s {
00062     unsigned in;  /* next free slot */
00063     unsigned out; /* next event */
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     /* current clip */
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     /* current aligned unit */
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     /* current disc */
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     /* current playlist */
00104     NAV_TITLE      *title;
00105     uint32_t       title_idx;
00106     uint64_t       s_pos;
00107 
00108     /* streams */
00109     BD_STREAM      st0; /* main path */
00110     BD_PRELOAD     st_ig; /* preloaded IG stream sub path */
00111 
00112     /* buffer for bd_read(): current aligned unit of main stream (st0) */
00113     uint8_t        int_buf[6144];
00114 
00115     /* seamless angle change request */
00116     int            seamless_angle_change;
00117     uint32_t       angle_change_pkt;
00118     uint32_t       angle_change_time;
00119     unsigned       request_angle;
00120 
00121     /* chapter tracking */
00122     uint64_t       next_chapter_start;
00123 
00124     /* aacs */
00125 #ifdef DLOPEN_CRYPTO_LIBS
00126     void           *h_libaacs;   // library handle
00127 #endif
00128     void           *aacs;
00129     fptr_p_void    libaacs_open;
00130     fptr_int       libaacs_decrypt_unit;
00131 
00132     /* BD+ */
00133 #ifdef DLOPEN_CRYPTO_LIBS
00134     void           *h_libbdplus; // library handle
00135 #endif
00136     void           *bdplus;
00137     fptr_p_void    bdplus_init;
00138     fptr_int32     bdplus_seek;
00139     fptr_int32     bdplus_fixup;
00140 
00141     /* player state */
00142     BD_REGISTERS   *regs;       // player registers
00143     BD_EVENT_QUEUE *event_queue; // navigation mode event queue
00144     BD_TITLE_TYPE  title_type;  // type of current title (in navigation mode)
00145 
00146     HDMV_VM        *hdmv_vm;
00147     uint8_t        hdmv_suspended;
00148 
00149     void           *bdjava;
00150 
00151     /* graphics */
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  * Navigation mode event queue
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 + * PSR utils
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     /* get preferred language */
00231     psr_val = bd_psr_read(regs, psr_lang);
00232     if (psr_val == 0xffffff) {
00233         /* language setting not initialized */
00234         return;
00235     }
00236 
00237     /* find stream */
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         /* requested language not found */
00248         stream_idx = undefined_val - 1;
00249         enable_flag = 0;
00250     }
00251     /* update PSR */
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     /* Update selected audio and subtitle stream PSRs when not using menus.
00270      * Selection is based on language setting PSRs and clip STN.
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  * clip access (BD_STREAM)
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     /* reset UO mask */
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 // Original libbluray code
00322 //        file_seek(st->fp, 0, SEEK_END);
00323 //        if ((st->clip_size = file_tell(st->fp))) {
00324 // New 'stat' and modified 'if' to minimize RingBuffer seeking
00325 // Optimize here for now until we can optimize in the RingBuffer itself
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                     } // decrypt
00389                 } // aacs
00390 
00391                 st->clip_block_pos += len;
00392 
00393                 // bdplus fixup, if required.
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                 /* Check TP_extra_header Copy_permission_indicator. If != 0, unit is still encrypted. */
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  * clip preload (BD_PRELOAD)
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     /* setup and open BD_STREAM */
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     /* allocate buffer */
00458     p->clip_size = st.clip_size;
00459     p->buf       = realloc(p->buf, p->clip_size);
00460 
00461     /* read clip to buffer */
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         // The position is in a new clip
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  * libaacs and libbdplus open / close
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         /* no AACS */
00608         return 1; /* no error if libaacs is not needed */
00609     }
00610 
00611     if (!_libaacs_load(bd)) {
00612         /* no libaacs */
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     // Take a quick stab to see if we want/need bdplus
00745     // we should fix this, and add various string functions.
00746     uint8_t vid[16] = {
00747         0xC5,0x43,0xEF,0x2A,0x15,0x0E,0x50,0xC4,0xE2,0xCA,
00748         0x71,0x65,0xB1,0x7C,0xA7,0xCB}; // FIXME
00749 
00750     _libbdplus_close(bd);
00751 
00752     if (!_libbdplus_required(bd)) {
00753         /* no BD+ */
00754         return 1; /* no error if libbdplus is not needed */
00755     }
00756 
00757     if (!_libbdplus_load(bd)) {
00758         /* no libbdplus */
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  * index open
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  * meta open
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  * disc info
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  * open / close
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  * seeking and current position
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         /* update title position */
00930         bd->s_pos = (uint64_t)title_pkt * 192;
00931 
00932         /* chapter tracking */
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 /* _change_angle() should be used only before call to _seek_internal() ! */
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         /* force re-opening .m2ts file in _seek_internal() */
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         // Find the closest access unit to the requested position
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         // Find the closest access unit to the requested position
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         // Find the closest access unit to the requested position
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         // Find the closest access unit to the requested position
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         // Find the closest access unit to the requested position
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  * read
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         // Find the closest access unit to the requested position
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             // Do we need to read more data?
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                 // Do we need to get the next clip?
01167                 if (st->clip == NULL) {
01168                     // We previously reached the last clip.  Nothing
01169                     // else to read.
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                     // split read()'s at clip boundary
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                     // handle still mode clips
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                     // find next clip
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         /* chapter tracking */
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  * preloader for asynchronous sub paths
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  * select title / angle
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     // Get the initial clip of the playlist
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         /* update current title */
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 // Select a title for playback
01392 // The title index is an index into the list
01393 // established by bd_get_titles()
01394 int bd_select_title(BLURAY *bd, uint32_t title_idx)
01395 {
01396     const char *f_name;
01397 
01398     // Open the playlist
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  * title lists
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  * player settings
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;  /* version fixed to BD-RO Part 3, version 2.0 */
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  * bdj
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  * Navigation mode interface
01705  */
01706 
01707 static void _process_psr_restore_event(BLURAY *bd, BD_PSR_EVENT *ev)
01708 {
01709     /* PSR restore events are handled internally.
01710      * Restore stored playback position.
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             /* can't set angle before playlist is opened */
01718             return;
01719         case PSR_TITLE_NUMBER:
01720             /* pass to the application */
01721             _queue_event(bd, (BD_EVENT){BD_EVENT_TITLE, ev->new_val});
01722             return;
01723         case PSR_CHAPTER:
01724             /* will be selected automatically */
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             /* handled by graphics controller */
01740             return;
01741 
01742         default:
01743             /* others: ignore */
01744             return;
01745     }
01746 }
01747 
01748 /*
01749  * notification events to APP
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         /* current playback position */
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         /* stream selection */
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             /* secondary video */
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             /* secondary audio */
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     /* first play object ? */
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); /* 5.2.3.3 */
01909 
01910         if (p->object_type == indx_object_type_hdmv) {
01911             if (p->hdmv.id_ref == 0xffff) {
01912                 /* no first play title (5.2.3.3) */
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     /* bd_play not called ? */
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     /* top menu ? */
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); /* 5.2.3.3 */
01937 
01938         if (p->object_type == indx_object_type_hdmv) {
01939             if (p->hdmv.id_ref == 0xffff) {
01940                 /* no top menu (5.2.3.3) */
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     /* valid title from disc index ? */
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); /* 5.2.3.3 */
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     /* reset player state */
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             /* initialize menus */
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             // stop current playlist
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     /* run VM */
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     /* process all events */
02134     do {
02135         _process_hdmv_vm_event(bd, &hdmv_ev);
02136 
02137     } while (!hdmv_vm_get_event(bd->hdmv_vm, &hdmv_ev));
02138 
02139     /* update VM state */
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     /* run HDMV VM ? */
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         /* just polled events ? */
02169         return 0;
02170     }
02171 
02172     int bytes = bd_read(bd, buf, len);
02173 
02174     if (bytes == 0) {
02175 
02176         // if no next clip (=end of title), resume HDMV VM
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  * user interaction
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends