Commit 9dc89ff0 authored by j45's avatar j45

Integrate libbdnav usage into bluray.c

bd_select_title() now selects a playlist index rather than an m2ts file.
The playlist must be initialized with a call to bd_get_titles() prior
to selecting a title.  bd_read() now works with read sizes other than 6144.
bd_seek() seeks to a position relative to the mpls rather than the m2ts.

Basic usage is now:

bd = bd_open(device, key_path);
num_titles = bd_get_titles(bd, TITLES_ALL);
// determine title index to play by presenting user with 
// information obtained through bd_get_title_info()
bd_select_title(bd, title_idx);
while ((len = bd_read(bd, buf, buf_sz)) > 0)
{
	// play buf
}
parent 6c242463
......@@ -21,6 +21,46 @@
#include "util/logging.h"
#include "util/strutl.h"
#include "file/dl.h"
#include "libbdnav/navigation.h"
static int _open_m2ts(BLURAY *bd)
{
char *f_name;
f_name = str_printf("%s" DIR_SEP "BDMV" DIR_SEP "STREAM" DIR_SEP "%s",
bd->device_path, bd->clip->name);
bd->clip_pos = (uint64_t)bd->clip->start_pkt * 192;
bd->clip_block_pos = (bd->clip_pos / 6144) * 6144;
if (bd->fp != NULL) {
file_close(bd->fp);
}
if ((bd->fp = file_open(f_name, "rb"))) {
file_seek(bd->fp, 0, SEEK_END);
if ((bd->clip_size = file_tell(bd->fp))) {
file_seek(bd->fp, bd->clip_block_pos, SEEK_SET);
bd->int_buf_off = 6144;
X_FREE(f_name);
if (bd->h_libbdplus && bd->bdplus) {
fptr_p_void bdplus_set_title;
bdplus_set_title = dl_dlsym(bd->h_libbdplus, "bdplus_set_title");
if (bdplus_set_title)
bdplus_set_title(bd->bdplus, bd->clip->clip_id);
}
return 1;
}
DEBUG(DBG_BLURAY, "Clip %s empty! (0x%08x)\n", f_name, bd);
}
DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open clip %s! (0x%08x)\n",
f_name, bd);
X_FREE(f_name);
return 0;
}
BLURAY *bd_open(const char* device_path, const char* keyfile_path)
{
......@@ -38,7 +78,6 @@ BLURAY *bd_open(const char* device_path, const char* keyfile_path)
//if ((bd->h_libaacs = dlopen("libaacs.so", RTLD_LAZY))) {
if ((bd->h_libaacs = dl_dlopen("aacs"))) {
fptr_p_void fptr;
uint8_t *vid;
DEBUG(DBG_BLURAY, "Downloaded libaacs (0x%08x)\n", bd->h_libaacs);
......@@ -121,6 +160,13 @@ void bd_close(BLURAY *bd)
file_close(bd->fp);
}
if (bd->title_list != NULL) {
nav_free_title_list(bd->title_list);
}
if (bd->title != NULL) {
nav_title_close(bd->title);
}
X_FREE(bd->device_path);
DEBUG(DBG_BLURAY, "BLURAY destroyed! (0x%08x)\n", bd);
......@@ -128,12 +174,89 @@ void bd_close(BLURAY *bd)
X_FREE(bd);
}
uint64_t bd_seek(BLURAY *bd, uint64_t pos)
int _read_block(BLURAY *bd)
{
const int len = 6144;
if (bd->fp) {
DEBUG(DBG_BLURAY, "Reading unit [%d bytes] at %"PRIu64"... (%p)\n",
len, bd->clip_block_pos, bd);
if (len + bd->clip_block_pos <= bd->clip_size) {
int read_len;
if ((read_len = file_read(bd->fp, bd->int_buf, len))) {
if (read_len != len)
DEBUG(DBG_BLURAY | DBG_CRIT, "Read %d bytes at %"PRIu64" ; requested %d ! (%p)\n", read_len, bd->clip_block_pos, len, bd);
if (bd->h_libaacs && bd->aacs) {
// FIXME: calling dlsym for every read() call.
if ((bd->libaacs_decrypt_unit = dl_dlsym(bd->h_libaacs, "aacs_decrypt_unit"))) {
if (!bd->libaacs_decrypt_unit(bd->aacs, bd->int_buf, len, bd->clip_block_pos)) {
DEBUG(DBG_BLURAY, "Unable decrypt unit! (0x%08x)\n", bd);
return 0;
} // decrypt
} // dlsym
} // aacs
bd->clip_block_pos += len;
// bdplus fixup, if required.
if (bd->bdplus_fixup && bd->bdplus) {
int32_t numFixes;
numFixes = bd->bdplus_fixup(bd->bdplus, len, bd->int_buf);
#if 0
if (numFixes) {
DEBUG(DBG_BLURAY,
"BDPLUS did %u fixups\n", numFixes);
}
#endif
}
DEBUG(DBG_BLURAY, "Read unit OK! (%p)\n", bd);
return 1;
}
DEBUG(DBG_BLURAY | DBG_CRIT, "Read %d bytes at %"PRIu64" failed ! (%p)\n", len, bd->clip_block_pos, bd);
return 0;
}
DEBUG(DBG_BLURAY | DBG_CRIT, "Read past EOF ! (%p)\n", bd);
return 0;
}
DEBUG(DBG_BLURAY, "No valid title selected! (%p)\n", bd);
return 0;
}
int64_t bd_seek(BLURAY *bd, uint64_t pos)
{
uint32_t pkt, clip_pkt, out_pkt, out_time;
NAV_CLIP *clip;
if (pos < bd->s_size) {
bd->s_pos = pos - (pos % 6144);
pkt = pos / 192;
// Find the closest access unit to the requested position
clip = nav_packet_search(bd->title, pkt, &clip_pkt, &out_pkt, &out_time);
if (clip->ref != bd->clip->ref) {
// The position is in a new clip
bd->clip = clip;
if (!_open_m2ts(bd)) {
return -1;
}
}
bd->s_pos = (uint64_t)out_pkt * 192;
bd->clip_pos = (uint64_t)clip_pkt * 192;
bd->clip_block_pos = (bd->clip_pos / 6144) * 6144;
file_seek(bd->fp, bd->s_pos, SEEK_SET);
file_seek(bd->fp, bd->clip_block_pos, SEEK_SET);
bd->int_buf_off = 6144;
......@@ -142,6 +265,7 @@ uint64_t bd_seek(BLURAY *bd, uint64_t pos)
if (bd->bdplus_seek && bd->bdplus)
bd->bdplus_seek(bd->bdplus, bd->s_pos);
return bd->s_pos;
}
return bd->s_pos;
......@@ -149,101 +273,177 @@ uint64_t bd_seek(BLURAY *bd, uint64_t pos)
int bd_read(BLURAY *bd, unsigned char *buf, int len)
{
if (bd->fp) {
int out_len = 0;
DEBUG(DBG_BLURAY, "Reading unit [%d bytes] at %ld... (0x%08x)\n", len, bd->s_pos, bd);
if (len + bd->s_pos <= bd->s_size) {
while (out_len < len) {
if (bd->int_buf_off == 6144) {
int read_len;
if ((read_len = file_read(bd->fp, buf, len))) {
if (bd->h_libaacs && bd->aacs) {
// FIXME: calling dlsym for every read() call.
if ((bd->libaacs_decrypt_unit = dl_dlsym(bd->h_libaacs, "aacs_decrypt_unit"))) {
if (!bd->libaacs_decrypt_unit(bd->aacs, buf, len, bd->s_pos)) {
DEBUG(DBG_BLURAY, "Unable decrypt unit! (0x%08x)\n", bd);
return 0;
} // decrypt
} // dlsym
} // aacs
// bdplus fixup, if required.
if (bd->bdplus_fixup && bd->bdplus) {
int32_t numFixes;
numFixes = bd->bdplus_fixup(bd->bdplus,
len,
buf);
#if 0
if (numFixes) {
DEBUG(DBG_BLURAY,
"BDPLUS did %u fixups\n", numFixes);
}
#endif
}
int size;
int out_len;
bd->s_pos += len;
if (bd->fp) {
out_len = 0;
DEBUG(DBG_BLURAY, "Reading [%d bytes] at %"PRIu64"... (%p)\n", len, bd->s_pos, bd);
while (len > 0) {
uint32_t clip_pkt;
// Do we need to read more data?
clip_pkt = bd->clip_pos / 192;
if (bd->int_buf_off == 6144 || clip_pkt >= bd->clip->end_pkt) {
// Do we need to get the next clip?
if (clip_pkt >= bd->clip->end_pkt) {
bd->clip = nav_next_clip(bd->title, bd->clip);
if (bd->clip == NULL) {
DEBUG(DBG_BLURAY, "End of title (0x%08x)\n", bd);
return out_len;
}
if (!_open_m2ts(bd)) {
return -1;
}
}
if (_read_block(bd)) {
bd->int_buf_off = bd->clip_pos % 6144;
} else {
return out_len;
}
}
if (len > 6144 - bd->int_buf_off) {
size = 6144 - bd->int_buf_off;
} else {
size = len;
}
memcpy(buf, bd->int_buf + bd->int_buf_off, size);
buf += size;
len -= size;
out_len += size;
bd->clip_pos += size;
bd->int_buf_off += size;
bd->s_pos += size;
}
DEBUG(DBG_BLURAY, "%d bytes read OK! (0x%08x)\n", len, bd);
DEBUG(DBG_BLURAY, "%d bytes read OK! (%p)\n", out_len, bd);
return len;
} // read
} // int_buf
bd->int_buf_off = 0;
return out_len;
}
} // while
} // s_size
} // if ->fp
DEBUG(DBG_BLURAY, "No valid title selected! (0x%08x)\n", bd->s_pos);
DEBUG(DBG_BLURAY, "No valid title selected! (%p)\n", bd);
return 0;
return -1;
}
int bd_select_title(BLURAY *bd, uint32_t title)
// Select a title for playback
// The title index is an index into the list
// established by bd_get_titles()
int bd_select_title(BLURAY *bd, uint32_t title_idx)
{
char f_name[100];
char *f_name;
memset(f_name, 0, sizeof(f_name));
snprintf(f_name, 100, "%s/BDMV/STREAM/%05u.m2ts", bd->device_path, title);
// Open the playlist
if (bd->title_list == NULL) {
DEBUG(DBG_BLURAY, "Title list not yet read! (0x%08x)\n", bd);
return 0;
}
if (bd->title_list->count <= title_idx) {
DEBUG(DBG_BLURAY, "Invalid title index %d! (0x%08x)\n", title_idx, bd);
return 0;
}
f_name = bd->title_list->title_info[title_idx].name;
bd->title = nav_title_open(bd->device_path, f_name);
if (bd->title == NULL) {
DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open title %s! (0x%08x)\n",
f_name, bd);
return 0;
}
bd->s_size = 0;
bd->s_pos = 0;
bd->s_size = (uint64_t)bd->title->packets * 192;
if ((bd->fp = file_open(f_name, "rb"))) {
file_seek(bd->fp, 0, SEEK_END);
if ((bd->s_size = file_tell(bd->fp))) {
bd_seek(bd, 0);
// Get the initial clip of the playlist
bd->clip = nav_next_clip(bd->title, NULL);
if (_open_m2ts(bd)) {
DEBUG(DBG_BLURAY, "Title %s selected! (0x%08x)\n", f_name, bd);
return 1;
}
return 0;
}
DEBUG(DBG_BLURAY, "Title %s selected! (0x%08x)\n", f_name, bd);
uint64_t bd_get_title_size(BLURAY *bd)
{
return bd ? bd->s_size : UINT64_C(0);
}
if (bd->h_libbdplus && bd->bdplus) {
fptr_p_void bdplus_set_title;
bdplus_set_title = dl_dlsym(bd->h_libbdplus, "bdplus_set_title");
if (bdplus_set_title)
bdplus_set_title(bd->bdplus, title);
}
uint64_t bd_tell(BLURAY *bd)
{
return bd ? bd->s_pos : INT64_C(0);
}
return 1;
}
// This must be called after bd_open() and before bd_select_title().
// Populates the title list in BLURAY.
// Filtering of the returned list is controled throught flags
// TITLES_ALL - all titles
// TITLES_FILTER_DUP_TITLE - remove duplicate titles
// TITLES_FILTER_DUP_CLIP - remove titles that have duplicated clips
// TITLES_RELEVANT - remove dup titles and clips
//
// Returns the number of titles found
uint32_t bd_get_titles(BLURAY *bd, uint8_t flags)
{
if (!bd) {
DEBUG(DBG_BLURAY | DBG_CRIT, "bd_get_titles(NULL) failed (%p)\n", bd);
return 0;
}
DEBUG(DBG_BLURAY, "Title %s empty! (0x%08x)\n", f_name, bd);
if (bd->title_list != NULL) {
nav_free_title_list(bd->title_list);
}
bd->title_list = nav_get_title_list(bd->device_path, flags);
DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to select title %s! (0x%08x)\n", f_name, bd);
if (!bd->title_list) {
DEBUG(DBG_BLURAY | DBG_CRIT, "nav_get_title_list(%s) failed (%p)\n", bd->device_path, bd);
return 0;
}
return 0;
return bd->title_list->count;
}
uint64_t bd_get_title_size(BLURAY *bd)
BD_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx)
{
return bd->s_size;
NAV_TITLE *title;
BD_TITLE_INFO *title_info;
int ii;
if (bd->title_list == NULL) {
DEBUG(DBG_BLURAY, "Title list not yet read! (0x%08x)\n", bd);
return NULL;
}
if (bd->title_list->count <= title_idx) {
DEBUG(DBG_BLURAY, "Invalid title index %d! (0x%08x)\n", title_idx, bd);
return NULL;
}
title = nav_title_open(bd->device_path, bd->title_list->title_info[title_idx].name);
if (title == NULL) {
DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open title %s! (0x%08x)\n",
bd->title_list->title_info[title_idx].name, bd);
return NULL;
}
title_info = calloc(1, sizeof(BD_TITLE_INFO));
title_info->idx = title_idx;
title_info->duration = (uint64_t)title->duration * 2;
title_info->angle_count = title->angle_count;
title_info->chapter_count = title->chap_list.count;
title_info->chapters = calloc(title_info->chapter_count, sizeof(BD_TITLE_CHAPTER));
for (ii = 0; ii < title_info->chapter_count; ii++) {
title_info->chapters[ii].idx = ii;
title_info->chapters[ii].start = (uint64_t)title->chap_list.chapter[ii].title_time * 2;
title_info->chapters[ii].duration = (uint64_t)title->chap_list.chapter[ii].duration * 2;
title_info->chapters[ii].offset = (uint64_t)title->chap_list.chapter[ii].title_pkt * 192;
}
nav_title_close(title);
return title_info;
}
uint64_t bd_tell(BLURAY *bd)
void bd_free_title_info(BD_TITLE_INFO *title_info)
{
return bd->s_pos;
X_FREE(title_info->chapters);
X_FREE(title_info);
}
......@@ -6,6 +6,7 @@
#include <unistd.h>
#include "file/file.h"
#include "libbdnav/navigation.h"
typedef int (*fptr_int)();
typedef int32_t (*fptr_int32)();
......@@ -14,9 +15,15 @@ typedef void* (*fptr_p_void)();
typedef struct bluray BLURAY;
struct bluray {
char *device_path;
FILE_H *fp;
NAV_TITLE_LIST *title_list;
NAV_TITLE *title;
uint64_t s_size;
uint64_t s_pos;
NAV_CLIP *clip;
FILE_H *fp;
uint64_t clip_size;
uint64_t clip_block_pos;
uint64_t clip_pos;
void *aacs, *bdplus;
fptr_int32 bdplus_seek; // frequently called
fptr_int32 bdplus_fixup; // frequently called
......@@ -26,13 +33,32 @@ struct bluray {
uint16_t int_buf_off;
};
typedef struct bd_chapter {
uint32_t idx;
uint64_t start;
uint64_t duration;
uint64_t offset;
} BD_TITLE_CHAPTER;
typedef struct bd_title_info {
uint32_t idx;
uint64_t duration;
uint32_t angle_count;
uint32_t chapter_count;
BD_TITLE_CHAPTER *chapters;
} BD_TITLE_INFO;
uint32_t bd_get_titles(BLURAY *bd, uint8_t flags);
BD_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx);
void bd_free_title_info(BD_TITLE_INFO *title_info);
BLURAY *bd_open(const char* device_path, const char* keyfile_path); // Init libbluray objs
void bd_close(BLURAY *bd); // Free libbluray objs
uint64_t bd_seek(BLURAY *bd, uint64_t pos); // Seek to pos in currently selected title file
int64_t bd_seek(BLURAY *bd, uint64_t pos); // Seek to pos in currently selected title file
int bd_read(BLURAY *bd, unsigned char *buf, int len); // Read from currently selected title file, decrypt if possible
int bd_select_title(BLURAY *bd, uint32_t title); // Select an m2ts file (title is the file number, e.g. title = 123 will select 00123.m2ts)
int bd_select_title(BLURAY *bd, uint32_t title); // TODO: FIX THE COMMENT
uint64_t bd_get_title_size(BLURAY *bd); // Returns file size in bytes of currently selected title, 0 in no title selected
uint64_t bd_tell(BLURAY *bd); // Return current pos
......
......@@ -205,11 +205,11 @@ _show_details(MPLS_PL *pl, int level)
_show_stream(&pi->stn.audio[jj], level + 2);
}
for (jj = 0; jj < (pi->stn.num_pg + pi->stn.num_pip_pg); jj++) {
if (jj < pi->stn.num_pg) {
if (jj < pi->stn.num_pg) {
indent_printf(level+1, "Presentation Graphics Stream %d:", jj);
} else {
} else {
indent_printf(level+1, "PIP Presentation Graphics Stream %d:", jj);
}
}
_show_stream(&pi->stn.pg[jj], level + 2);
}
for (jj = 0; jj < pi->stn.num_secondary_video; jj++) {
......
......@@ -34,7 +34,7 @@ void dir_close_posix(DIR_H *dir)
int dir_read_posix(DIR_H *dir, DIRENT *entry)
{
struct dirent e, *p_e;
int result;
int result;
result = readdir_r((DIR*)dir->internal, &e, &p_e);
if (result) {
......
......@@ -96,6 +96,98 @@ _pl_duration(MPLS_PL *pl)
return duration;
}
NAV_TITLE_LIST* nav_get_title_list(char *root, uint32_t flags)
{
DIR_H *dir;
DIRENT ent;
char *path = NULL;
MPLS_PL **pl_list = NULL;
MPLS_PL *pl = NULL;
int ii, pl_list_size = 0;
int res;
NAV_TITLE_LIST *title_list;
int title_info_alloc = 100;
title_list = calloc(1, sizeof(NAV_TITLE_LIST));
title_list->title_info = calloc(title_info_alloc, sizeof(NAV_TITLE_INFO));
DEBUG(DBG_NAV, "Root: %s:\n", root);
path = str_printf("%s" DIR_SEP "BDMV" DIR_SEP "PLAYLIST", root);
dir = dir_open(path);
if (dir == NULL) {
DEBUG(DBG_NAV, "Failed to open dir: %s\n", path);
X_FREE(path);
return NULL;;
}
X_FREE(path);
ii = 0;
for (res = dir_read(dir, &ent); !res; res = dir_read(dir, &ent)) {
if (ent.d_name[0] == '.') {
continue;
}
path = str_printf("%s" DIR_SEP "BDMV" DIR_SEP "PLAYLIST" DIR_SEP "%s",
root, ent.d_name);
if (ii >= pl_list_size) {
MPLS_PL **tmp = NULL;
pl_list_size += 100;
tmp = realloc(pl_list, pl_list_size * sizeof(MPLS_PL*));
if (tmp == NULL) {
break;
}
pl_list = tmp;
}
pl = mpls_parse(path, 0);
X_FREE(path);
if (pl != NULL) {
if ((flags & TITLES_FILTER_DUP_TITLE) &&
!_filter_dup(pl_list, ii, pl)) {
mpls_free(pl);
continue;
}
if ((flags & TITLES_FILTER_DUP_CLIP) && !_filter_repeats(pl, 2)) {
mpls_free(pl);
continue;
}
if (ii >= title_info_alloc) {
NAV_TITLE_INFO *tmp = NULL;
title_info_alloc += 100;
tmp = realloc(title_list->title_info,
title_info_alloc * sizeof(NAV_TITLE_INFO));
if (tmp == NULL) {
break;
}
title_list->title_info = tmp;
}
pl_list[ii] = pl;
strncpy(title_list->title_info[ii].name, ent.d_name, 11);
title_list->title_info[ii].name[10] = '\0';
title_list->title_info[ii].ref = ii;
title_list->title_info[ii].mpls_id = atoi(ent.d_name);
title_list->title_info[ii].duration = _pl_duration(pl_list[ii]);
ii++;
}
}
dir_close(dir);
title_list->count = ii;
for (ii = 0; ii < title_list->count; ii++) {
mpls_free(pl_list[ii]);
}
return title_list;
}
void nav_free_title_list(NAV_TITLE_LIST *title_list)
{
X_FREE(title_list->title_info);
X_FREE(title_list);
}
char* nav_find_main_title(char *root)
{
DIR_H *dir;
......@@ -110,10 +202,6 @@ char* nav_find_main_title(char *root)
DEBUG(DBG_NAV, "Root: %s:\n", root);
path = str_printf("%s" DIR_SEP "BDMV" DIR_SEP "PLAYLIST", root);
if (path == NULL) {
fprintf(stderr, "Failed to find playlist path: %s\n", path);
return NULL;
}
dir = dir_open(path);
if (dir == NULL) {
......@@ -171,7 +259,7 @@ char* nav_find_main_title(char *root)
}
static void
_extrapolate(NAV_TITLE *title)
_extrapolate_title(NAV_TITLE *title)
{
uint64_t duration = 0;
uint64_t pkt = 0;
......@@ -185,6 +273,9 @@ _extrapolate(NAV_TITLE *title)
for (ii = 0; ii < title->clip_list.count; ii++) {
clip = &title->clip_list.clip[ii];
pi = &pl->play_item[ii];
if (pi->angle_count > title->angle_count) {
title->angle_count = pi->angle_count;
}
clip->title_time = duration;
clip->duration = pi->out_time - pi->in_time;
......@@ -242,7 +333,7 @@ NAV_TITLE* nav_title_open(char *root, char *playlist)
char *path;
int ii, chapters = 0;
title = malloc(sizeof(NAV_TITLE));
title = calloc(1, sizeof(NAV_TITLE));
if (title == NULL) {
return NULL;
}
......@@ -251,6 +342,7 @@ NAV_TITLE* nav_title_open(char *root, char *playlist)
title->name[10] = '\0';
path = str_printf("%s" DIR_SEP "BDMV" DIR_SEP "PLAYLIST" DIR_SEP "%s",
root, playlist);