STDMETHODIMP CBDDemuxer::SetTitle(int idx) { HRESULT hr = S_OK; int ret; // return values if (m_pTitle) { bd_free_title_info(m_pTitle); } // Init Event Queue bd_get_event(m_pBD, nullptr); // Select title m_pTitle = bd_get_title_info(m_pBD, idx, 0); ret = bd_select_title(m_pBD, idx); if (ret == 0) { return E_FAIL; } if (m_pb) { av_free(m_pb->buffer); av_free(m_pb); } uint8_t *buffer = (uint8_t *)av_mallocz(BD_READ_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); m_pb = avio_alloc_context(buffer, BD_READ_BUFFER_SIZE, 0, this, BDByteStreamRead, nullptr, BDByteStreamSeek); SafeRelease(&m_lavfDemuxer); SAFE_CO_FREE(m_rtOffset); m_lavfDemuxer = new CLAVFDemuxer(m_pLock, m_pSettings); m_lavfDemuxer->AddRef(); m_lavfDemuxer->SetBluRay(this); if (FAILED(hr = m_lavfDemuxer->OpenInputStream(m_pb, nullptr, "mpegts", TRUE))) { SafeRelease(&m_lavfDemuxer); return hr; } m_lavfDemuxer->SeekByte(0, 0); // Process any events that occured during opening ProcessBDEvents(); // Reset EOS protection m_EndOfStreamPacketFlushProtection = FALSE; // space for storing stream offsets m_rtOffset = (REFERENCE_TIME *)CoTaskMemAlloc(sizeof(REFERENCE_TIME) * m_lavfDemuxer->GetNumStreams()); if (!m_rtOffset) return E_OUTOFMEMORY; memset(m_rtOffset, 0, sizeof(REFERENCE_TIME) * m_lavfDemuxer->GetNumStreams()); DbgLog((LOG_TRACE, 20, L"Opened BD title with %d clips and %d chapters", m_pTitle->clip_count, m_pTitle->chapter_count)); return S_OK; }
bool BDRingBuffer::SwitchTitle(uint32_t index) { if (!bdnav) return false; m_infoLock.lock(); m_currentTitleInfo = GetTitleInfo(index); m_infoLock.unlock(); bd_select_title(bdnav, index); return UpdateTitleInfo(); }
/*********************************************************************** * hb_bd_start *********************************************************************** * Title and chapter start at 1 **********************************************************************/ int hb_bd_start( hb_bd_t * d, hb_title_t *title ) { BD_EVENT event; d->pkt_count = title->block_count; // Calling bd_get_event initializes libbluray event queue. bd_select_title( d->bd, d->title_info[title->index - 1]->idx ); bd_get_event( d->bd, &event ); d->chapter = 1; d->stream = hb_bd_stream_open( title ); if ( d->stream == NULL ) { return 0; } return 1; }
bool BDRingBuffer::SwitchTitle(uint32_t index) { if (!bdnav) return false; if (m_currentTitleInfo) bd_free_title_info(m_currentTitleInfo); m_currentTitleInfo = bd_get_title_info(bdnav, index); if (!m_currentTitleInfo) return false; bd_select_title(bdnav, index); return UpdateTitleInfo(index); }
STDMETHODIMP CBDDemuxer::SetTitle(int idx) { HRESULT hr = S_OK; int ret; // return values if (m_pTitle) { bd_free_title_info(m_pTitle); } // Init Event Queue bd_get_event(m_pBD, nullptr); // Select title m_pTitle = bd_get_title_info(m_pBD, idx, 0); ret = bd_select_title(m_pBD, idx); if (ret == 0) { return E_FAIL; } MPLS_PL * mpls = bd_get_title_mpls(m_pBD); if (mpls) { for (int i = 0; i < mpls->ext_sub_count; i++) { if (mpls->ext_sub_path[i].type == 8 && mpls->ext_sub_path[i].sub_playitem_count == mpls->list_count) { DbgLog((LOG_TRACE, 20, L"CBDDemuxer::SetTitle(): Enabling BD3D MVC demuxing")); DbgLog((LOG_TRACE, 20, L" -> MVC_Base_view_R_flag: %d", m_pTitle->mvc_base_view_r_flag)); m_MVCPlayback = TRUE; m_MVCExtensionSubPathIndex = i; break; } } } CloseMVCExtensionDemuxer(); if (m_pb) { av_free(m_pb->buffer); av_free(m_pb); } uint8_t *buffer = (uint8_t *)av_mallocz(BD_READ_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); m_pb = avio_alloc_context(buffer, BD_READ_BUFFER_SIZE, 0, this, BDByteStreamRead, nullptr, BDByteStreamSeek); SafeRelease(&m_lavfDemuxer); SAFE_CO_FREE(m_StreamClip); SAFE_CO_FREE(m_rtOffset); m_lavfDemuxer = new CLAVFDemuxer(m_pLock, m_pSettings); m_lavfDemuxer->AddRef(); m_lavfDemuxer->SetBluRay(this); if (FAILED(hr = m_lavfDemuxer->OpenInputStream(m_pb, nullptr, "mpegts", TRUE))) { SafeRelease(&m_lavfDemuxer); return hr; } if (m_MVCPlayback && !m_lavfDemuxer->m_bH264MVCCombine) { DbgLog((LOG_TRACE, 10, L"CBDDemuxer::SetTitle(): MVC demuxing was requested, but main demuxer did not activate MVC mode, disabling.")); CloseMVCExtensionDemuxer(); m_MVCPlayback = FALSE; } m_lavfDemuxer->SeekByte(0, 0); // Process any events that occured during opening ProcessBDEvents(); // Reset EOS protection m_EndOfStreamPacketFlushProtection = FALSE; // space for storing stream offsets m_StreamClip = (uint16_t *)CoTaskMemAlloc(sizeof(*m_StreamClip) * m_lavfDemuxer->GetNumStreams()); if (!m_StreamClip) return E_OUTOFMEMORY; memset(m_StreamClip, -1, sizeof(*m_StreamClip) * m_lavfDemuxer->GetNumStreams()); m_rtOffset = (REFERENCE_TIME *)CoTaskMemAlloc(sizeof(*m_rtOffset) * m_lavfDemuxer->GetNumStreams()); if (!m_rtOffset) return E_OUTOFMEMORY; memset(m_rtOffset, 0, sizeof(*m_rtOffset) * m_lavfDemuxer->GetNumStreams()); DbgLog((LOG_TRACE, 20, L"Opened BD title with %d clips and %d chapters", m_pTitle->clip_count, m_pTitle->chapter_count)); return S_OK; }
int main(int argc, char *argv[]) { int title_no = -1; int playlist = -1; int angle = 0; char *bdpath = NULL, *dest = NULL; FILE *out; int opt; int verbose = 0; int64_t total = 0; int64_t pos, end_pos = -1; size_t size, wrote; int bytes; int title_count; BLURAY *bd; int chapter_start = 0; int chapter_end = -1; uint8_t buf[BUF_SIZE]; char *keyfile = NULL; BLURAY_TITLE_INFO *ti; do { opt = getopt(argc, argv, OPTS); switch (opt) { case -1: if (optind < argc && bdpath == NULL) { bdpath = argv[optind]; optind++; opt = 1; } else if (optind < argc && dest == NULL) { dest = argv[optind]; optind++; opt = 1; } break; case 'c': { int match; match = sscanf(optarg, "%d-%d", &chapter_start, &chapter_end); if (match == 1) { chapter_end = chapter_start + 1; } chapter_start--; chapter_end--; } break; case 'k': keyfile = optarg; break; case 'a': angle = atoi(optarg); angle--; break; case 't': if (playlist >= 0) { _usage(argv[0]); } title_no = atoi(optarg); title_no--; break; case 'p': if (title_no >= 0) { _usage(argv[0]); } playlist = atoi(optarg); break; case 'v': verbose = 1; break; default: _usage(argv[0]); break; } } while (opt != -1); if (title_no < 0 && playlist < 0) { _usage(argv[0]); } if (optind < argc) { _usage(argv[0]); } bd = bd_open(bdpath, keyfile); if (bd == NULL) { fprintf(stderr, "Failed to open disc: %s\n", bdpath); return 1; } title_count = bd_get_titles(bd, TITLES_RELEVANT, 0); if (title_count <= 0) { fprintf(stderr, "No titles found: %s\n", bdpath); return 1; } if (title_no >= 0) { if (!bd_select_title(bd, title_no)) { fprintf(stderr, "Failed to open title: %d\n", title_no); return 1; } ti = bd_get_title_info(bd, title_no, angle); } else { if (!bd_select_playlist(bd, playlist)) { fprintf(stderr, "Failed to open playlist: %d\n", playlist); return 1; } ti = bd_get_playlist_info(bd, playlist, angle); } if (dest) { out = fopen(dest, "wb"); if (out == NULL) { fprintf(stderr, "Failed to open destination: %s\n", dest); return 1; } } else { out = stdout; } if (angle >= (int)ti->angle_count) { fprintf(stderr, "Invalid angle %d > angle count %d. Using angle 1.\n", angle+1, ti->angle_count); angle = 0; } bd_select_angle(bd, angle); if (chapter_start >= (int)ti->chapter_count) { fprintf(stderr, "First chapter %d > chapter count %d\n", chapter_start+1, ti->chapter_count); return 1; } if (chapter_end >= (int)ti->chapter_count) { chapter_end = -1; } if (chapter_end >= 0) { end_pos = bd_chapter_pos(bd, chapter_end); } bd_free_title_info(ti); bd_seek_chapter(bd, chapter_start); pos = bd_tell(bd); while (end_pos < 0 || pos < end_pos) { size = BUF_SIZE; if (size > (size_t)(end_pos - pos)) { size = end_pos - pos; } bytes = bd_read(bd, buf, size); if (bytes <= 0) { break; } pos = bd_tell(bd); wrote = fwrite(buf, 1, bytes, out); if (wrote != (size_t)bytes) { fprintf(stderr, "read/write sizes do not match: %d/%zu\n", bytes, wrote); } if (wrote == 0) { if (ferror(out)) { perror("Write error"); } break; } total += wrote; } if (verbose) { fprintf(stderr, "Wrote %"PRId64" bytes\n", total); } bd_close(bd); fclose(out); return 0; }
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; }