private boolean openSeekable() { final Info initialInfo = new Info(); final Comment initialComment = new Comment(); this.m_chunkSize = Math.min(8500, (int) length(this.m_vorbisStream)); final Page page = new Page(); final int[] testSerialno = {0}; final int ret = this.fetchHeaders(initialInfo, initialComment, testSerialno, null); final int serialno = testSerialno[0]; final int dataOffset = (int) this.m_offset; this.m_oggStreamState.clear(); if (ret < 0) { return false; } seek(this.m_vorbisStream, 0L, 1); this.m_offset = tell(this.m_vorbisStream); final long end = this.getPreviousPage(page); if (page.serialno() != serialno) { if (this.bisectForwardSerialno(0L, 0L, end + 1L, serialno, 0) < 0) { return false; } } else if (this.bisectForwardSerialno(0L, end, end + 1L, serialno, 0) < 0) { return false; } this.prefetchAllHeaders(initialInfo, initialComment, dataOffset); this.rawSeek(this.m_dataOffsets[0]); return true; }
public int fetchHeaders(final Info info, final Comment comment, final int[] serialno, Page page) { if (page == null) { page = new Page(); final int retValue = this.getNextPage(page, this.m_chunkSize); if (retValue == -128) { return -128; } if (retValue < 0) { return -130; } } if (serialno != null) { serialno[0] = page.serialno(); } this.m_oggStreamState.init(page.serialno()); info.init(); comment.init(); final Packet packet = new Packet(); int i = 0; while (i < 3) { this.m_oggStreamState.pagein(page); while (i < 3) { final int result = this.m_oggStreamState.packetout(packet); if (result == 0) { break; } if (result == -1) { info.clear(); this.m_oggStreamState.clear(); return -1; } if (info.synthesis_headerin(comment, packet) != 0) { info.clear(); this.m_oggStreamState.clear(); return -1; } ++i; } if (i < 3 && this.getNextPage(page, 1L) < 0) { info.clear(); this.m_oggStreamState.clear(); return -1; } } return 0; }
private int bisectForwardSerialno( final long begin, long searched, final long end, final int currentno, final int m) { long endsearched = end; long next = end; final Page page = new Page(); while (searched < endsearched) { long bisect; if (endsearched - searched < this.m_chunkSize) { bisect = searched; } else { bisect = (searched + endsearched) / 2L; } this.seekHelper(bisect); final int ret = this.getNextPage(page, -1L); if (ret == -128) { return -128; } if (ret < 0 || page.serialno() != currentno) { endsearched = bisect; if (ret < 0) { continue; } next = ret; } else { searched = ret + page.header_len + page.body_len; } } this.seekHelper(next); int ret = this.getNextPage(page, -1L); if (ret == -128) { return -128; } if (searched >= end || ret == -1) { this.m_links = m + 1; (this.m_offsets = new long[m + 2])[m + 1] = searched; } else { ret = this.bisectForwardSerialno(next, this.m_offset, end, page.serialno(), m + 1); if (ret == -128) { return -128; } } this.m_offsets[m] = begin; return 0; }
private void prefetchAllHeaders( final Info firstInfo, final Comment firstComment, final int dataoffset) { final Page page = new Page(); this.m_info = new Info[this.m_links]; this.m_comments = new Comment[this.m_links]; this.m_dataOffsets = new long[this.m_links]; this.m_pcmLengths = new long[this.m_links]; this.m_serialnos = new int[this.m_links]; for (int i = 0; i < this.m_links; ++i) { if (firstInfo != null && firstComment != null && i == 0) { this.m_info[i] = firstInfo; this.m_comments[i] = firstComment; this.m_dataOffsets[i] = dataoffset; } else { this.seekHelper(this.m_offsets[i]); this.m_info[i] = new Info(); this.m_comments[i] = new Comment(); if (this.fetchHeaders(this.m_info[i], this.m_comments[i], null, null) == -1) { this.m_dataOffsets[i] = -1L; } else { this.m_dataOffsets[i] = this.m_offset; this.m_oggStreamState.clear(); } } final long end = this.m_offsets[i + 1]; this.seekHelper(end); while (true) { final int ret = this.getPreviousPage(page); if (ret == -1) { this.m_info[i].clear(); break; } if (page.granulepos() != -1L) { this.m_serialnos[i] = page.serialno(); this.m_pcmLengths[i] = page.granulepos(); break; } } } }
@Override public int pcmSeek(final long pos) { if (!this.m_vorbisStream.isSeekable()) { return -1; } long total = this.pcmTotal(-1); if (pos < 0L || pos > total) { this.m_pcmOffset = -1L; this.decodeClear(); return -1; } int link; for (link = this.m_links - 1; link >= 0; --link) { total -= this.m_pcmLengths[link]; if (pos >= total) { break; } } final long target = pos - total; long end = this.m_offsets[link + 1]; long begin = this.m_offsets[link]; int best = (int) begin; final Page page = new Page(); while (begin < end) { long bisect; if (end - begin < this.m_chunkSize) { bisect = begin; } else { bisect = (end + begin) / 2L; } this.seekHelper(bisect); final int ret = this.getNextPage(page, end - bisect); if (ret == -1) { end = bisect; } else { final long granulepos = page.granulepos(); if (granulepos < target) { best = ret; begin = this.m_offset; } else { end = bisect; } } } if (this.rawSeek(best) != 0) { this.m_pcmOffset = -1L; this.decodeClear(); return -1; } if (this.m_pcmOffset >= pos) { this.m_pcmOffset = -1L; this.decodeClear(); return -1; } if (pos > this.pcmTotal(-1)) { this.m_pcmOffset = -1L; this.decodeClear(); return -1; } while (this.m_pcmOffset < pos) { final int target2 = (int) (pos - this.m_pcmOffset); final int[] _index = new int[this.m_info[this.m_currentLink].channelsCount]; int samples = this.m_dspState.synthesis_pcmout(this.m_pcmf_buffer, _index); if (samples > target2) { samples = target2; } this.m_dspState.synthesis_read(samples); this.m_pcmOffset += samples; if (samples < target2 && this.processPacket(true) == 0) { this.m_pcmOffset = this.pcmTotal(-1); } } return 0; }