/** * @param allocator An {@link Allocator} from which allocations for sample data can be obtained. */ public RollingSampleBuffer(Allocator allocator) { this.allocator = allocator; allocationLength = allocator.getIndividualAllocationLength(); infoQueue = new InfoQueue(); dataQueue = new LinkedBlockingDeque<>(); extrasHolder = new SampleExtrasHolder(); scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE); lastAllocationOffset = allocationLength; }
/** * Reads the current sample, advancing the read index to the next sample. * * @param sampleHolder The holder into which the current sample should be written. * @return True if a sample was read. False if there is no current sample. */ public boolean readSample(SampleHolder sampleHolder) { // Write the sample information into the holder and extrasHolder. boolean haveSample = infoQueue.peekSample(sampleHolder, extrasHolder); if (!haveSample) { return false; } // Read encryption data if the sample is encrypted. if (sampleHolder.isEncrypted()) { readEncryptionData(sampleHolder, extrasHolder); } // Write the sample data into the holder. if (sampleHolder.data == null || sampleHolder.data.capacity() < sampleHolder.size) { sampleHolder.replaceBuffer(sampleHolder.size); } if (sampleHolder.data != null) { readData(extrasHolder.offset, sampleHolder.data, sampleHolder.size); } // Advance the read head. long nextOffset = infoQueue.moveToNextSample(); dropDownstreamTo(nextOffset); return true; }
/** * Discards samples from the write side of the buffer. * * @param discardFromIndex The absolute index of the first sample to be discarded. * @return The reduced total number of bytes written, after the samples have been discarded. */ public long discardUpstreamSamples(int discardFromIndex) { int discardCount = getWriteIndex() - discardFromIndex; Assertions.checkArgument(0 <= discardCount && discardCount <= queueSize); if (discardCount == 0) { if (absoluteReadIndex == 0) { // queueSize == absoluteReadIndex == 0, so nothing has been written to the queue. return 0; } int lastWriteIndex = (relativeWriteIndex == 0 ? capacity : relativeWriteIndex) - 1; return offsets[lastWriteIndex] + sizes[lastWriteIndex]; } queueSize -= discardCount; relativeWriteIndex = (relativeWriteIndex + capacity - discardCount) % capacity; return offsets[relativeWriteIndex]; }
/** * Attempts to skip to the keyframe before the specified time, if it's present in the buffer. * * @param timeUs The seek time. * @return True if the skip was successful. False otherwise. */ public boolean skipToKeyframeBefore(long timeUs) { long nextOffset = infoQueue.skipToKeyframeBefore(timeUs); if (nextOffset == -1) { return false; } dropDownstreamTo(nextOffset); return true; }
/** * Clears the buffer, returning all allocations to the allocator. */ public void clear() { infoQueue.clear(); while (!dataQueue.isEmpty()) { allocator.release(dataQueue.remove()); } totalBytesDropped = 0; totalBytesWritten = 0; lastAllocation = null; lastAllocationOffset = allocationLength; }
/** * Skips the current sample. */ public void skipSample() { long nextOffset = infoQueue.moveToNextSample(); dropDownstreamTo(nextOffset); }
/** * Discards samples from the write side of the buffer. * * @param discardFromIndex The absolute index of the first sample to be discarded. */ public void discardUpstreamSamples(int discardFromIndex) { totalBytesWritten = infoQueue.discardUpstreamSamples(discardFromIndex); dropUpstreamFrom(totalBytesWritten); }
/** * Returns the current absolute read index. */ public int getReadIndex() { return infoQueue.getReadIndex(); }
/** * Indicates the end point for the current sample, making it available for consumption. * * @param sampleTimeUs The sample timestamp. * @param flags Flags that accompany the sample. See {@link SampleHolder#flags}. * @param position The position of the sample data in the rolling buffer. * @param size The size of the sample, in bytes. * @param encryptionKey The encryption key associated with the sample, or null. */ public void commitSample(long sampleTimeUs, int flags, long position, int size, byte[] encryptionKey) { infoQueue.commitSample(sampleTimeUs, flags, position, size, encryptionKey); }
/** * Returns the current absolute write index. */ public int getWriteIndex() { return infoQueue.getWriteIndex(); }
/** * Fills {@code holder} with information about the current sample, but does not write its data. * <p> * The fields set are {@link SampleHolder#size}, {@link SampleHolder#timeUs} and * {@link SampleHolder#flags}. * * @param holder The holder into which the current sample information should be written. * @return True if the holder was filled. False if there is no current sample. */ public boolean peekSample(SampleHolder holder) { return infoQueue.peekSample(holder, extrasHolder); }