blob: 159fde18912176a76cda5f5f803c00213a8e57ea [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tv.tuner.exoplayer.buffer;
import android.os.ConditionVariable;
import android.support.annotation.NonNull;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.tuner.tvinput.PlaybackBufferListener;
import com.android.tv.tuner.exoplayer.SampleExtractor;
import java.io.IOException;
import java.util.List;
/**
* Handles I/O for {@link SampleExtractor} when
* physical storage based buffer is not used. Trickplay is disabled.
*/
public class SimpleSampleBuffer implements BufferManager.SampleBuffer {
private final SamplePool mSamplePool = new SamplePool();
private SampleQueue[] mPlayingSampleQueues;
private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US;
private volatile boolean mEos;
public SimpleSampleBuffer(PlaybackBufferListener bufferListener) {
if (bufferListener != null) {
// Disables trickplay.
bufferListener.onBufferStateChanged(false);
}
}
@Override
public synchronized void init(@NonNull List<String> ids,
@NonNull List<MediaFormat> mediaFormats) {
int trackCount = ids.size();
mPlayingSampleQueues = new SampleQueue[trackCount];
for (int i = 0; i < trackCount; i++) {
mPlayingSampleQueues[i] = null;
}
}
@Override
public void setEos() {
mEos = true;
}
private boolean reachedEos() {
return mEos;
}
@Override
public void selectTrack(int index) {
synchronized (this) {
if (mPlayingSampleQueues[index] == null) {
mPlayingSampleQueues[index] = new SampleQueue(mSamplePool);
} else {
mPlayingSampleQueues[index].clear();
}
}
}
@Override
public void deselectTrack(int index) {
synchronized (this) {
if (mPlayingSampleQueues[index] != null) {
mPlayingSampleQueues[index].clear();
mPlayingSampleQueues[index] = null;
}
}
}
@Override
public synchronized long getBufferedPositionUs() {
Long result = null;
for (SampleQueue queue : mPlayingSampleQueues) {
if (queue == null) {
continue;
}
Long lastQueuedSamplePositionUs = queue.getLastQueuedPositionUs();
if (lastQueuedSamplePositionUs == null) {
// No sample has been queued.
result = mLastBufferedPositionUs;
continue;
}
if (result == null || result > lastQueuedSamplePositionUs) {
result = lastQueuedSamplePositionUs;
}
}
if (result == null) {
return mLastBufferedPositionUs;
}
return (mLastBufferedPositionUs = result);
}
@Override
public synchronized int readSample(int track, SampleHolder sampleHolder) {
SampleQueue queue = mPlayingSampleQueues[track];
SoftPreconditions.checkNotNull(queue);
int result = queue == null ? SampleSource.NOTHING_READ : queue.dequeueSample(sampleHolder);
if (result != SampleSource.SAMPLE_READ && reachedEos()) {
return SampleSource.END_OF_STREAM;
}
return result;
}
@Override
public void writeSample(int index, SampleHolder sample,
ConditionVariable conditionVariable) throws IOException {
sample.data.position(0).limit(sample.size);
SampleHolder sampleToQueue = mSamplePool.acquireSample(sample.size);
sampleToQueue.size = sample.size;
sampleToQueue.clearData();
sampleToQueue.data.put(sample.data);
sampleToQueue.timeUs = sample.timeUs;
sampleToQueue.flags = sample.flags;
synchronized (this) {
if (mPlayingSampleQueues[index] != null) {
mPlayingSampleQueues[index].queueSample(sampleToQueue);
}
}
}
@Override
public boolean isWriteSpeedSlow(int sampleSize, long durationNs) {
// Since SimpleSampleBuffer write samples only to memory (not to physical storage),
// write speed is always fine.
return false;
}
@Override
public void handleWriteSpeedSlow() {
// no-op
}
@Override
public synchronized boolean continueBuffering(long positionUs) {
for (SampleQueue queue : mPlayingSampleQueues) {
if (queue == null) {
continue;
}
if (queue.getLastQueuedPositionUs() == null
|| positionUs > queue.getLastQueuedPositionUs()) {
// No more buffered data.
return false;
}
}
return true;
}
@Override
public void seekTo(long positionUs) {
// Not used.
}
@Override
public void release() {
// Not used.
}
}