1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tv.tuner.exoplayer.buffer; 18 19 import android.os.ConditionVariable; 20 21 import android.support.annotation.NonNull; 22 import com.google.android.exoplayer.C; 23 import com.google.android.exoplayer.MediaFormat; 24 import com.google.android.exoplayer.SampleHolder; 25 import com.google.android.exoplayer.SampleSource; 26 import com.android.tv.tuner.tvinput.PlaybackBufferListener; 27 import com.android.tv.tuner.exoplayer.SampleExtractor; 28 29 import java.io.IOException; 30 import java.util.List; 31 32 import junit.framework.Assert; 33 34 /** 35 * Handles I/O for {@link SampleExtractor} when 36 * physical storage based buffer is not used. Trickplay is disabled. 37 */ 38 public class SimpleSampleBuffer implements BufferManager.SampleBuffer { 39 private final SamplePool mSamplePool = new SamplePool(); 40 private SampleQueue[] mPlayingSampleQueues; 41 private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US; 42 43 private volatile boolean mEos; 44 45 public SimpleSampleBuffer(PlaybackBufferListener bufferListener) { 46 if (bufferListener != null) { 47 // Disables trickplay. 48 bufferListener.onBufferStateChanged(false); 49 } 50 } 51 52 @Override 53 public synchronized void init(@NonNull List<String> ids, 54 @NonNull List<MediaFormat> mediaFormats) { 55 int trackCount = ids.size(); 56 mPlayingSampleQueues = new SampleQueue[trackCount]; 57 for (int i = 0; i < trackCount; i++) { 58 mPlayingSampleQueues[i] = null; 59 } 60 } 61 62 @Override 63 public void setEos() { 64 mEos = true; 65 } 66 67 private boolean reachedEos() { 68 return mEos; 69 } 70 71 @Override 72 public void selectTrack(int index) { 73 synchronized (this) { 74 if (mPlayingSampleQueues[index] == null) { 75 mPlayingSampleQueues[index] = new SampleQueue(mSamplePool); 76 } else { 77 mPlayingSampleQueues[index].clear(); 78 } 79 } 80 } 81 82 @Override 83 public void deselectTrack(int index) { 84 synchronized (this) { 85 if (mPlayingSampleQueues[index] != null) { 86 mPlayingSampleQueues[index].clear(); 87 mPlayingSampleQueues[index] = null; 88 } 89 } 90 } 91 92 @Override 93 public synchronized long getBufferedPositionUs() { 94 Long result = null; 95 for (SampleQueue queue : mPlayingSampleQueues) { 96 if (queue == null) { 97 continue; 98 } 99 Long lastQueuedSamplePositionUs = queue.getLastQueuedPositionUs(); 100 if (lastQueuedSamplePositionUs == null) { 101 // No sample has been queued. 102 result = mLastBufferedPositionUs; 103 continue; 104 } 105 if (result == null || result > lastQueuedSamplePositionUs) { 106 result = lastQueuedSamplePositionUs; 107 } 108 } 109 if (result == null) { 110 return mLastBufferedPositionUs; 111 } 112 return (mLastBufferedPositionUs = result); 113 } 114 115 @Override 116 public synchronized int readSample(int track, SampleHolder sampleHolder) { 117 SampleQueue queue = mPlayingSampleQueues[track]; 118 Assert.assertNotNull(queue); 119 int result = queue.dequeueSample(sampleHolder); 120 if (result != SampleSource.SAMPLE_READ && reachedEos()) { 121 return SampleSource.END_OF_STREAM; 122 } 123 return result; 124 } 125 126 @Override 127 public void writeSample(int index, SampleHolder sample, 128 ConditionVariable conditionVariable) throws IOException { 129 sample.data.position(0).limit(sample.size); 130 SampleHolder sampleToQueue = mSamplePool.acquireSample(sample.size); 131 sampleToQueue.size = sample.size; 132 sampleToQueue.clearData(); 133 sampleToQueue.data.put(sample.data); 134 sampleToQueue.timeUs = sample.timeUs; 135 sampleToQueue.flags = sample.flags; 136 137 synchronized (this) { 138 if (mPlayingSampleQueues[index] != null) { 139 mPlayingSampleQueues[index].queueSample(sampleToQueue); 140 } 141 } 142 } 143 144 @Override 145 public boolean isWriteSpeedSlow(int sampleSize, long durationNs) { 146 // Since SimpleSampleBuffer write samples only to memory (not to physical storage), 147 // write speed is always fine. 148 return false; 149 } 150 151 @Override 152 public void handleWriteSpeedSlow() { 153 // no-op 154 } 155 156 @Override 157 public synchronized boolean continueBuffering(long positionUs) { 158 for (SampleQueue queue : mPlayingSampleQueues) { 159 if (queue == null) { 160 continue; 161 } 162 if (queue.getLastQueuedPositionUs() == null 163 || positionUs > queue.getLastQueuedPositionUs()) { 164 // No more buffered data. 165 return false; 166 } 167 } 168 return true; 169 } 170 171 @Override 172 public void seekTo(long positionUs) { 173 // Not used. 174 } 175 176 @Override 177 public void release() { 178 // Not used. 179 } 180 } 181