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; }
static uint64_t align_to_next_packet(BLURAY *bd, uint8_t *pkt) { uint8_t buf[MAX_HOLE]; uint64_t pos = 0; uint64_t start = bd_tell(bd); uint64_t orig; uint64_t off = 192; memcpy(buf, pkt, 192); if ( start >= 192 ) { start -= 192; } orig = start; while (1) { if (bd_read(bd, buf+off, sizeof(buf)-off) == sizeof(buf)-off) { const uint8_t *bp = buf; int i; for ( i = sizeof(buf) - 8 * 192; --i >= 0; ++bp ) { if ( have_ts_sync( bp, 192 ) ) { break; } } if ( i >= 0 ) { pos = ( bp - buf ); break; } off = 8 * 192; memcpy(buf, buf + sizeof(buf) - off, off); start += sizeof(buf) - off; } else { return 0; } } off = start + pos - 4; // bd_seek seeks to the nearest access unit *before* the requested position // we don't want to seek backwards, so we need to read until we get // past that position. bd_seek(bd, off); while (off > bd_tell(bd)) { if (bd_read(bd, buf, 192) != 192) { break; } } return start - orig + pos; }
int BDRingBuffer::safe_read(void *data, uint sz) { int result = 0; if (m_isHDMVNavigation) { HandleBDEvents(); while (result == 0) { BD_EVENT event; result = bd_read_ext(bdnav, (unsigned char *)data, sz, &event); HandleBDEvent(event); if (result == 0) HandleBDEvents(); } } else { result = bd_read(bdnav, (unsigned char *)data, sz); } m_currentTime = bd_tell(bdnav); return result; }
STDMETHODIMP CBDDemuxer::Seek(REFERENCE_TIME rTime) { int64_t prev = bd_tell(m_pBD); int64_t target = bd_find_seek_point(m_pBD, ConvertDSTimeTo90Khz(rTime)); m_EndOfStreamPacketFlushProtection = FALSE; DbgLog((LOG_TRACE, 1, "Seek Request: %I64u (time); %I64u (byte), %I64u (prev byte)", rTime, target, prev)); HRESULT hr = m_lavfDemuxer->SeekByte(target + 4, AVSEEK_FLAG_BACKWARD); if (m_MVCPlayback && m_MVCFormatContext) { // Re-open to switch clip if needed CloseMVCExtensionDemuxer(); if (FAILED(OpenMVCExtensionDemuxer(m_NewClip))) return E_FAIL; // Adjust for clip offset int64_t seek_pts = 0; if (rTime > 0) { AVStream *stream = m_MVCFormatContext->streams[m_MVCStreamIndex]; rTime -= m_rtNewOffset; rTime -= 10000000; // seek one second before the target to ensure the MVC queue isn't out of sync for too long seek_pts = m_lavfDemuxer->ConvertRTToTimestamp(rTime, stream->time_base.num, stream->time_base.den); } if (seek_pts < 0) seek_pts = 0; av_seek_frame(m_MVCFormatContext, m_MVCStreamIndex, seek_pts, AVSEEK_FLAG_BACKWARD); } return hr; }
static int next_packet( BLURAY *bd, uint8_t *pkt ) { int result; while ( 1 ) { result = bd_read( bd, pkt, 192 ); if ( result < 0 ) { return -1; } if ( result < 192 ) { return 0; } // Sync byte is byte 4. 0-3 are timestamp. if (pkt[4] == 0x47) { return 1; } // lost sync - back up to where we started then try to re-establish. uint64_t pos = bd_tell(bd); uint64_t pos2 = align_to_next_packet(bd, pkt); if ( pos2 == 0 ) { hb_log( "next_packet: eof while re-establishing sync @ %"PRId64, pos ); return 0; } hb_log( "next_packet: sync lost @ %"PRId64", regained after %"PRId64" bytes", pos, pos2 ); } }
__int64 CDVDInputStreamBluray::Seek(__int64 offset, int whence) { #if LIBBLURAY_BYTESEEK if(whence == SEEK_POSSIBLE) return 1; else if(whence == SEEK_CUR) { if(offset == 0) return m_dll->bd_tell(m_bd); else offset += bd_tell(m_bd); } else if(whence == SEEK_END) offset += m_dll->bd_get_title_size(m_bd); else if(whence != SEEK_SET) return -1; int64_t pos = m_dll->bd_seek(m_bd, offset); if(pos < 0) { CLog::Log(LOGERROR, "CDVDInputStreamBluray::Seek - seek to %"PRId64", failed with %"PRId64, offset, pos); return -1; } if(pos != offset) CLog::Log(LOGWARNING, "CDVDInputStreamBluray::Seek - seek to %"PRId64", ended at %"PRId64, offset, pos); return offset; #else if(whence == SEEK_POSSIBLE) return 0; return -1; #endif }
STDMETHODIMP CBDDemuxer::Seek(REFERENCE_TIME rTime) { int64_t prev = bd_tell(m_pBD); int64_t target = bd_find_seek_point(m_pBD, ConvertDSTimeTo90Khz(rTime)); DbgLog((LOG_TRACE, 1, "Seek Request: %I64u (time); %I64u (byte), %I64u (prev byte)", rTime, target, prev)); return m_lavfDemuxer->SeekByte(target, AVSEEK_FLAG_BACKWARD); }
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 int bluray_stream_seek(stream_t *s, int64_t pos) { struct bluray_priv_s *b = s->priv; int64_t p; p = bd_seek(b->bd, pos); // bd_seek does not say what happens on errors, // so be extra paranoid. // bd_seek also does not seek exactly to the requested // position, so allow for some fuzz. if (p < 0 || p > pos || p + 20*1024*1024 < pos) { s->pos = bd_tell(b->bd); return 0; } s->pos = p; return 1; }
long long BDRingBuffer::GetReadPosition(void) const { if (bdnav) return bd_tell(bdnav); return 0; }
/*********************************************************************** * hb_bd_read *********************************************************************** * **********************************************************************/ hb_buffer_t * hb_bd_read( hb_bd_t * d ) { int result; int error_count = 0; uint8_t buf[192]; BD_EVENT event; uint64_t pos; hb_buffer_t * out = NULL; uint8_t discontinuity; while ( 1 ) { discontinuity = 0; result = next_packet( d->bd, buf ); if ( result < 0 ) { hb_error("bd: Read Error"); pos = bd_tell( d->bd ); bd_seek( d->bd, pos + 192 ); error_count++; if (error_count > 10) { hb_error("bd: Error, too many consecutive read errors"); hb_set_work_error(d->h, HB_ERROR_READ); return NULL; } continue; } else if ( result == 0 ) { return NULL; } error_count = 0; while ( bd_get_event( d->bd, &event ) ) { switch ( event.event ) { case BD_EVENT_CHAPTER: // The muxers expect to only get chapter 2 and above // They write chapter 1 when chapter 2 is detected. if (event.param > d->chapter) { d->next_chap = event.param; } break; case BD_EVENT_PLAYITEM: discontinuity = 1; hb_deep_log(2, "bd: Playitem %u", event.param); break; case BD_EVENT_STILL: bd_read_skip_still( d->bd ); break; default: break; } } // buf+4 to skip the BD timestamp at start of packet if (d->chapter != d->next_chap) { d->chapter = d->next_chap; out = hb_ts_decode_pkt(d->stream, buf+4, d->chapter, discontinuity); } else { out = hb_ts_decode_pkt(d->stream, buf+4, 0, discontinuity); } if (out != NULL) { return out; } } return NULL; }
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; }
/*********************************************************************** * hb_bd_read *********************************************************************** * **********************************************************************/ hb_buffer_t * hb_bd_read( hb_bd_t * d ) { int result; int error_count = 0; uint8_t buf[192]; BD_EVENT event; uint64_t pos; hb_buffer_t * b; uint8_t discontinuity; int new_chap = 0; discontinuity = 0; while ( 1 ) { if ( d->next_chap != d->chapter ) { new_chap = d->chapter = d->next_chap; } result = next_packet( d->bd, buf ); if ( result < 0 ) { hb_error("bd: Read Error"); pos = bd_tell( d->bd ); bd_seek( d->bd, pos + 192 ); error_count++; if (error_count > 10) { hb_error("bd: Error, too many consecutive read errors"); return 0; } continue; } else if ( result == 0 ) { return 0; } error_count = 0; while ( bd_get_event( d->bd, &event ) ) { switch ( event.event ) { case BD_EVENT_CHAPTER: // The muxers expect to only get chapter 2 and above // They write chapter 1 when chapter 2 is detected. d->next_chap = event.param; break; case BD_EVENT_PLAYITEM: discontinuity = 1; hb_deep_log(2, "bd: Playitem %u", event.param); break; case BD_EVENT_STILL: bd_read_skip_still( d->bd ); break; default: break; } } // buf+4 to skip the BD timestamp at start of packet b = hb_ts_decode_pkt( d->stream, buf+4 ); if ( b ) { b->s.discontinuity = discontinuity; b->s.new_chap = new_chap; return b; } } return NULL; }
JNIEXPORT jlong JNICALL Java_org_videolan_Libbluray_tellN(JNIEnv * env, jclass cls, jlong np) { BDJAVA* bdj = (BDJAVA*)(intptr_t)np; return bd_tell(bdj->bd); }