int64_t CBDDemuxer::BDByteStreamSeek(void *opaque, int64_t offset, int whence) { CBDDemuxer *demux = (CBDDemuxer *)opaque; BLURAY *bd = demux->m_pBD; int64_t pos = 0; if (whence == SEEK_SET) { pos = offset; } else if (whence == SEEK_CUR) { if (offset == 0) return bd_tell(bd); pos = bd_tell(bd) + offset; } else if (whence == SEEK_END) { pos = bd_get_title_size(bd) - offset; } else if (whence == AVSEEK_SIZE) { return bd_get_title_size(bd); } else return -1; if (pos < 0) pos = 0; int64_t achieved = bd_seek(bd, pos); if (pos > achieved) { offset = pos - achieved; DbgLog((LOG_TRACE, 10, L"BD Seek to %I64d, achieved %I64d, correcting target by %I64d", pos, achieved, offset)); uint8_t *dump_buffer = (uint8_t *)CoTaskMemAlloc(6144); while (offset > 0) { bd_read(bd, dump_buffer, min(offset, 6144)); offset -= 6144; } CoTaskMemFree(dump_buffer); achieved = bd_tell(bd); } return achieved; }
int64_t BDByteStreamSeek(void *opaque, int64_t offset, int whence) { BLURAY *bd = (BLURAY *)opaque; int64_t pos = 0; if (whence == SEEK_SET) { pos = offset; } else if (whence == SEEK_CUR) { if (offset == 0) return bd_tell(bd); pos = bd_tell(bd) + offset; } else if (whence == SEEK_END) { pos = bd_get_title_size(bd) - offset; } else if (whence == AVSEEK_SIZE) { return bd_get_title_size(bd); } else return -1; return bd_seek(bd, pos); }
static void _read_to_eof(BLURAY *bd) { BD_EVENT ev; int bytes; uint64_t total = 0; uint8_t buf[6144]; bd_seek(bd, bd_get_title_size(bd) - 6144); do { bytes = bd_read_ext(bd, buf, 6144, &ev); total += bytes < 0 ? 0 : bytes; _print_event(&ev); } while (bytes > 0); printf("_read_to_eof(): read %"PRIu64" bytes\n", total); }
bool BDRingBuffer::UpdateTitleInfo(uint32_t index) { m_titleChanged = true; m_currentTitleLength = m_currentTitleInfo->duration; m_currentTitleAngleCount = m_currentTitleInfo->angle_count; m_currentAngle = 0; m_titlesize = bd_get_title_size(bdnav); uint32_t chapter_count = m_currentTitleInfo->chapter_count; VERBOSE(VB_IMPORTANT, LOC + QString("Selected title/playlist: index %1. " "Duration: %2 (%3 mins) " "Number of Chapters: %4 Number of Angles: %5 " "Title Size: %6") .arg(index) .arg(m_currentTitleLength) .arg(m_currentTitleLength / (90000 * 60)) .arg(chapter_count) .arg(m_currentTitleAngleCount) .arg(m_titlesize)); VERBOSE(VB_PLAYBACK, LOC + QString("Frame Rate: %1").arg(GetFrameRate())); if (chapter_count) { for (uint i = 0; i < chapter_count; i++) { uint64_t total_secs = GetChapterStartTime(i); uint64_t framenum = GetChapterStartFrame(i); int hours = (int)total_secs / 60 / 60; int minutes = ((int)total_secs / 60) - (hours * 60); double secs = (double)total_secs - (double)(hours * 60 * 60 + minutes * 60); VERBOSE(VB_PLAYBACK, LOC + QString("Chapter %1 found @ [%2:%3:%4]->%5") .arg(QString().sprintf("%02d", i + 1)) .arg(QString().sprintf("%02d", hours)) .arg(QString().sprintf("%02d", minutes)) .arg(QString().sprintf("%06.3f", secs)) .arg(framenum)); } } return true; }
uint64_t BDRingBuffer::GetTotalReadPosition(void) { if (bdnav) return bd_get_title_size(bdnav); return 0; }
bool BDRingBuffer::UpdateTitleInfo(void) { QMutexLocker locker(&m_infoLock); if (!m_currentTitleInfo) return false; m_titleChanged = true; m_currentTitleLength = m_currentTitleInfo->duration; m_currentTitleAngleCount = m_currentTitleInfo->angle_count; m_currentAngle = 0; m_titlesize = bd_get_title_size(bdnav); uint32_t chapter_count = GetNumChapters(); uint64_t total_secs = m_currentTitleLength / 90000; int hours = (int)total_secs / 60 / 60; int minutes = ((int)total_secs / 60) - (hours * 60); double secs = (double)total_secs - (double)(hours * 60 * 60 + minutes * 60); QString duration = QString("%1:%2:%3") .arg(QString().sprintf("%02d", hours)) .arg(QString().sprintf("%02d", minutes)) .arg(QString().sprintf("%02.1f", secs)); VERBOSE(VB_IMPORTANT, LOC + QString("New title info: Index %1 Playlist: %2 Duration: %3 Chapters: %5") .arg(m_currentTitleInfo->idx).arg(m_currentTitleInfo->playlist) .arg(duration).arg(chapter_count)); VERBOSE(VB_IMPORTANT, LOC + QString("New title info: Clips: %6 Angles: %7 Title Size: %8 Frame Rate %9") .arg(m_currentTitleInfo->clip_count) .arg(m_currentTitleAngleCount).arg(m_titlesize) .arg(GetFrameRate())); if (chapter_count) { for (uint i = 0; i < chapter_count; i++) { uint64_t total_secs = GetChapterStartTime(i); uint64_t framenum = GetChapterStartFrame(i); int hours = (int)total_secs / 60 / 60; int minutes = ((int)total_secs / 60) - (hours * 60); double secs = (double)total_secs - (double)(hours * 60 * 60 + minutes * 60); VERBOSE(VB_PLAYBACK, LOC + QString("Chapter %1 found @ [%2:%3:%4]->%5") .arg(QString().sprintf("%02d", i + 1)) .arg(QString().sprintf("%02d", hours)) .arg(QString().sprintf("%02d", minutes)) .arg(QString().sprintf("%06.3f", secs)) .arg(framenum)); } } int still = BLURAY_STILL_NONE; int time = 0; if (m_currentTitleInfo->clip_count) { for (uint i = 0; i < m_currentTitleInfo->clip_count; i++) { VERBOSE(VB_PLAYBACK, LOC + QString("Clip %1 stillmode %2 " "stilltime %3 videostreams %4 " "audiostreams %5 igstreams %6") .arg(i).arg(m_currentTitleInfo->clips[i].still_mode) .arg(m_currentTitleInfo->clips[i].still_time) .arg(m_currentTitleInfo->clips[i].video_stream_count) .arg(m_currentTitleInfo->clips[i].audio_stream_count) .arg(m_currentTitleInfo->clips[i].ig_stream_count)); still |= m_currentTitleInfo->clips[i].still_mode; time = m_currentTitleInfo->clips[i].still_time; } } if (m_currentTitleInfo->clip_count > 1 && still != BLURAY_STILL_NONE) VERBOSE(VB_IMPORTANT, LOC + "Warning: more than 1 clip, following still" " frame analysis may be wrong"); if (still == BLURAY_STILL_TIME) { VERBOSE(VB_PLAYBACK, LOC + QString("Entering still frame (%1 seconds) UNSUPPORTED").arg(time)); } else if (still == BLURAY_STILL_INFINITE) { VERBOSE(VB_PLAYBACK, LOC + "Entering infinite still frame."); } m_stillMode = still; m_stillTime = time; return true; }
static int bluray_stream_open(stream_t *s, int mode, void *opts, int *file_format) { struct stream_priv_s *p = opts; struct bluray_priv_s *b; BLURAY_TITLE_INFO *info = NULL; BLURAY *bd; int title, title_guess, title_count; uint64_t title_size; unsigned int angle = 0; uint64_t max_duration = 0; char *device = NULL; int i; /* find the requested device */ if (p->device) device = p->device; else if (bluray_device) device = bluray_device; if (!device) { mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_BlurayNoDevice); return STREAM_UNSUPPORTED; } /* open device */ bd = bd_open(device, NULL); if (!bd) { mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_CantOpenBluray, device); return STREAM_UNSUPPORTED; } /* check for available titles on disc */ title_count = bd_get_titles(bd, TITLES_RELEVANT, angle); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_BLURAY_TITLES=%d\n", title_count); if (!title_count) { mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_BlurayNoTitles); bd_close(bd); return STREAM_UNSUPPORTED; } /* parse titles information */ title_guess = BLURAY_DEFAULT_TITLE; for (i = 0; i < title_count; i++) { BLURAY_TITLE_INFO *ti; int sec, msec; ti = bd_get_title_info(bd, i, angle); if (!ti) continue; sec = ti->duration / 90000; msec = (ti->duration - sec) % 1000; mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_BLURAY_TITLE_%d_CHAPTERS=%d\n", i + 1, ti->chapter_count); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_BLURAY_TITLE_%d_ANGLE=%d\n", i + 1, ti->angle_count); mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_BLURAY_TITLE_%d_LENGTH=%d.%03d\n", i + 1, sec, msec); mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_BLURAY_TITLE_%d_PLAYLIST=%05d\n", i + 1, ti->playlist); /* try to guess which title may contain the main movie */ if (ti->duration > max_duration) { max_duration = ti->duration; title_guess = i; } bd_free_title_info(ti); } /* Select current title */ title = p->title ? p->title - 1: title_guess; title = FFMIN(title, title_count - 1); bd_select_title(bd, title); title_size = bd_get_title_size(bd); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_BLURAY_CURRENT_TITLE=%d\n", title + 1); /* Get current title information */ info = bd_get_title_info(bd, title, angle); if (!info) goto err_no_info; /* Select angle */ angle = bluray_angle ? bluray_angle : BLURAY_DEFAULT_ANGLE; angle = FFMIN(angle, info->angle_count); if (angle) bd_select_angle(bd, angle); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_BLURAY_CURRENT_ANGLE=%d\n", angle + 1); bd_free_title_info(info); err_no_info: s->fill_buffer = bluray_stream_fill_buffer; s->seek = bluray_stream_seek; s->close = bluray_stream_close; s->control = bluray_stream_control; b = calloc(1, sizeof(struct bluray_priv_s)); b->bd = bd; b->current_angle = angle; b->current_title = title; s->end_pos = title_size; s->sector_size = BLURAY_SECTOR_SIZE; s->flags = mode | MP_STREAM_SEEK; s->priv = b; s->type = STREAMTYPE_BLURAY; s->url = strdup("br://"); mp_msg(MSGT_OPEN, MSGL_V, "Blu-ray successfully opened.\n"); return STREAM_OK; }
static int bluray_stream_control(stream_t *s, int cmd, void *arg) { struct bluray_priv_s *b = s->priv; switch (cmd) { case STREAM_CTRL_GET_NUM_CHAPTERS: { BLURAY_TITLE_INFO *ti; ti = bd_get_title_info(b->bd, b->current_title, b->current_angle); if (!ti) return STREAM_UNSUPPORTED; *((unsigned int *) arg) = ti->chapter_count; bd_free_title_info(ti); return 1; } case STREAM_CTRL_GET_CURRENT_TITLE: { *((unsigned int *) arg) = b->current_title; return 1; } case STREAM_CTRL_GET_CURRENT_CHAPTER: { *((unsigned int *) arg) = bd_get_current_chapter(b->bd); return 1; } case STREAM_CTRL_SEEK_TO_CHAPTER: { BLURAY_TITLE_INFO *ti; int chapter = *((unsigned int *) arg); int64_t pos; int r; ti = bd_get_title_info(b->bd, b->current_title, b->current_angle); if (!ti) return STREAM_UNSUPPORTED; if (chapter < 0 || chapter > ti->chapter_count) { bd_free_title_info(ti); return STREAM_UNSUPPORTED; } pos = bd_chapter_pos(b->bd, chapter); r = bluray_stream_seek(s, pos); bd_free_title_info(ti); return r ? 1 : STREAM_UNSUPPORTED; } case STREAM_CTRL_GET_TIME_LENGTH: { BLURAY_TITLE_INFO *ti = bd_get_title_info(b->bd, b->current_title, b->current_angle); if (!ti) return STREAM_UNSUPPORTED; *(double *)arg = ti->duration / 90000.0; return STREAM_OK; } case STREAM_CTRL_GET_SIZE: *(uint64_t*)arg = bd_get_title_size(b->bd); return STREAM_OK; case STREAM_CTRL_GET_CURRENT_TIME: *(double *)arg = bd_tell_time(b->bd) / 90000.0; return STREAM_OK; case STREAM_CTRL_SEEK_TO_TIME: { int64_t res; double target = *(double*)arg * 90000.0; BLURAY_TITLE_INFO *ti = bd_get_title_info(b->bd, b->current_title, b->current_angle); // clamp to ensure that out-of-bounds seeks do not simply do nothing. target = FFMAX(target, 0); if (ti && ti->duration > 1) target = FFMIN(target, ti->duration - 1); res = bd_seek_time(b->bd, target); if (res < 0) return STREAM_ERROR; s->pos = res; return 1; } case STREAM_CTRL_GET_NUM_ANGLES: { BLURAY_TITLE_INFO *ti; ti = bd_get_title_info(b->bd, b->current_title, b->current_angle); if (!ti) return STREAM_UNSUPPORTED; *((int *) arg) = ti->angle_count; bd_free_title_info(ti); return 1; } case STREAM_CTRL_GET_ANGLE: { *((int *) arg) = b->current_angle; return 1; } case STREAM_CTRL_SET_ANGLE: { BLURAY_TITLE_INFO *ti; int angle = *((int *) arg); ti = bd_get_title_info(b->bd, b->current_title, b->current_angle); if (!ti) return STREAM_UNSUPPORTED; if (angle < 0 || angle > ti->angle_count) { bd_free_title_info(ti); return STREAM_UNSUPPORTED; } b->current_angle = angle; bd_seamless_angle_change(b->bd, angle); bd_free_title_info(ti); return 1; } case STREAM_CTRL_GET_LANG: { struct stream_lang_req *req = arg; const BLURAY_STREAM_INFO *si; int count; BLURAY_TITLE_INFO *ti = get_langs(b, req->type, &si, &count); while (count-- > 0) { if (si->pid == req->id) { memcpy(req->buf, si->lang, 4); req->buf[4] = 0; bd_free_title_info(ti); return STREAM_OK; } si++; } if (ti) bd_free_title_info(ti); return STREAM_ERROR; } default: break; } return STREAM_UNSUPPORTED; }
JNIEXPORT jlong JNICALL Java_org_videolan_Libbluray_getTitleSizeN(JNIEnv * env, jclass cls, jlong np) { BDJAVA* bdj = (BDJAVA*)(intptr_t)np; return bd_get_title_size(bdj->bd); }