diff options
Diffstat (limited to 'usbtuner/src/com/android/usbtuner/exoplayer/CachedSampleSourceExtractor.java')
-rw-r--r-- | usbtuner/src/com/android/usbtuner/exoplayer/CachedSampleSourceExtractor.java | 331 |
1 files changed, 0 insertions, 331 deletions
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/CachedSampleSourceExtractor.java b/usbtuner/src/com/android/usbtuner/exoplayer/CachedSampleSourceExtractor.java deleted file mode 100644 index 654a9f92..00000000 --- a/usbtuner/src/com/android/usbtuner/exoplayer/CachedSampleSourceExtractor.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * 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.usbtuner.exoplayer; - -import android.media.MediaCodec; -import android.media.MediaDataSource; -import android.os.ConditionVariable; -import android.os.SystemClock; -import android.util.Log; - -import com.google.android.exoplayer.C; -import com.google.android.exoplayer.SampleHolder; -import com.google.android.exoplayer.SampleSource; -import com.android.usbtuner.tvinput.PlaybackCacheListener; - -import junit.framework.Assert; - -import java.io.IOException; -import java.util.Locale; -import java.util.Random; -import java.util.concurrent.TimeUnit; - -/** - * Extracts samples from {@link MediaDataSource} and stores them on the disk, which enables - * trickplay. - */ -public class CachedSampleSourceExtractor extends BaseSampleSourceExtractor implements - CacheManager.EvictListener { - private static final String TAG = "CachedSampleSourceExt"; - private static final boolean DEBUG = false; - - public static final long CHUNK_DURATION_US = TimeUnit.MILLISECONDS.toMicros(500); - - private static final long LIVE_THRESHOLD_US = TimeUnit.SECONDS.toMicros(1); - private static final long CACHE_WRITE_TIMEOUT_MS = 10 * 1000; // 10 seconds - - private final CacheManager mCacheManager; - private final String mId; - - private final PlaybackCacheListener mCacheListener; - private long[] mCacheEndPositionUs; - private SampleCache[] mSampleCaches; - private CachedSampleQueue[] mPlayingSampleQueues; - private final SamplePool mSamplePool = new SamplePool(); - private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US; - private long mCurrentPlaybackPositionUs = 0; - - private class CachedSampleQueue extends SampleQueue { - private SampleCache mCache = null; - - public CachedSampleQueue(SamplePool samplePool) { - super(samplePool); - } - - public void setSource(SampleCache newCache) { - for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) { - cache.clear(); - cache.close(); - } - mCache = newCache; - for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) { - cache.resetRead(); - } - } - - public boolean maybeReadSample() { - if (isDurationGreaterThan(CHUNK_DURATION_US)) { - return false; - } - SampleHolder sample = mCache.maybeReadSample(); - if (sample == null) { - if (!mCache.canReadMore() && mCache.getNext() != null) { - mCache.clear(); - mCache.close(); - mCache = mCache.getNext(); - mCache.resetRead(); - return maybeReadSample(); - } else { - return false; - } - } else { - queueSample(sample); - return true; - } - } - - public int dequeueSample(SampleHolder sample) { - maybeReadSample(); - return super.dequeueSample(sample); - } - - @Override - public void clear() { - super.clear(); - for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) { - cache.clear(); - cache.close(); - } - mCache = null; - } - - public long getSourceStartPositionUs() { - return mCache == null ? -1 : mCache.getStartPositionUs(); - } - } - - public CachedSampleSourceExtractor(MediaDataSource source, CacheManager cacheManager, - PlaybackCacheListener cacheListener) { - super(source); - mCacheManager = cacheManager; - mCacheListener = cacheListener; - mId = Long.toHexString(new Random().nextLong()); - cacheListener.onCacheStateChanged(true); // Enable trickplay - } - - @Override - public void queueSample(int index, SampleHolder sample, ConditionVariable conditionVariable) - throws IOException { - long writeStartTimeNs = SystemClock.elapsedRealtimeNanos(); - synchronized (this) { - SampleCache cache = mSampleCaches[index]; - if ((sample.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) { - if (sample.timeUs >= mCacheEndPositionUs[index]) { - try { - SampleCache nextCache = mCacheManager.createNewWriteFile( - getTrackId(index), mCacheEndPositionUs[index], mSamplePool); - cache.finishWrite(nextCache); - mSampleCaches[index] = cache = nextCache; - mCacheEndPositionUs[index] = - ((sample.timeUs / CHUNK_DURATION_US) + 1) * CHUNK_DURATION_US; - } catch (IOException e) { - cache.finishWrite(null); - throw e; - } - } - } - cache.writeSample(sample, conditionVariable); - } - if (!conditionVariable.block(CACHE_WRITE_TIMEOUT_MS)) { - Log.e(TAG, "Error: Serious delay on writing cache"); - conditionVariable.block(); - } - - // Check if the storage has enough bandwidth for trickplay. Otherwise we disable it - // and notify the slowness through the playback cache listener. - mCacheManager.addWriteStat(sample.size, - SystemClock.elapsedRealtimeNanos() - writeStartTimeNs); - if (mCacheManager.isWriteSlow()) { - Log.w(TAG, "Disk is too slow for trickplay. Disable trickplay."); - mCacheManager.disable(); - mCacheListener.onDiskTooSlow(); - } - } - - private String getTrackId(int index) { - return String.format(Locale.ENGLISH, "%s_%x", mId, index); - } - - @Override - public void initOnPrepareLocked(int trackCount) throws IOException { - mSampleCaches = new SampleCache[trackCount]; - mPlayingSampleQueues = new CachedSampleQueue[trackCount]; - mCacheEndPositionUs = new long[trackCount]; - for (int i = 0; i < trackCount; i++) { - mSampleCaches[i] = mCacheManager.createNewWriteFile(getTrackId(i), 0, mSamplePool); - mPlayingSampleQueues[i] = null; - mCacheEndPositionUs[i] = CHUNK_DURATION_US; - } - } - - @Override - public void selectTrack(int index) { - synchronized (this) { - if (mPlayingSampleQueues[index] == null) { - String trackId = getTrackId(index); - mPlayingSampleQueues[index] = new CachedSampleQueue(mSamplePool); - mCacheManager.registerEvictListener(trackId, this); - seekIndividualTrackLocked(index, mCurrentPlaybackPositionUs, - isLiveLocked(mCurrentPlaybackPositionUs)); - mPlayingSampleQueues[index].maybeReadSample(); - } - } - } - - @Override - public void deselectTrack(int index) { - synchronized (this) { - if (mPlayingSampleQueues[index] != null) { - mPlayingSampleQueues[index].clear(); - mPlayingSampleQueues[index] = null; - mCacheManager.unregisterEvictListener(getTrackId(index)); - } - } - } - - @Override - public long getBufferedPositionUs() { - synchronized (this) { - Long result = null; - for (CachedSampleQueue queue : mPlayingSampleQueues) { - if (queue == null) { - continue; - } - Long bufferedPositionUs = queue.getEndPositionUs(); - if (bufferedPositionUs == null) { - continue; - } - if (result == null || result > bufferedPositionUs) { - result = bufferedPositionUs; - } - } - if (result == null) { - return mLastBufferedPositionUs; - } else { - return (mLastBufferedPositionUs = result); - } - } - } - - @Override - public void seekTo(long positionUs) { - synchronized (this) { - boolean isLive = isLiveLocked(positionUs); - - // Seek video track first - for (int i = 0; i < mPlayingSampleQueues.length; ++i) { - CachedSampleQueue queue = mPlayingSampleQueues[i]; - if (queue == null) { - continue; - } - seekIndividualTrackLocked(i, positionUs, isLive); - if (DEBUG) { - Log.d(TAG, "start time = " + queue.getSourceStartPositionUs()); - } - } - mLastBufferedPositionUs = positionUs; - } - } - - private boolean isLiveLocked(long positionUs) { - Long livePositionUs = null; - for (SampleCache cache : mSampleCaches) { - if (livePositionUs == null || livePositionUs < cache.getEndPositionUs()) { - livePositionUs = cache.getEndPositionUs(); - } - } - return (livePositionUs == null - || Math.abs(livePositionUs - positionUs) < LIVE_THRESHOLD_US); - } - - private void seekIndividualTrackLocked(int index, long positionUs, boolean isLive) { - CachedSampleQueue queue = mPlayingSampleQueues[index]; - if (queue == null) { - return; - } - queue.clear(); - if (isLive) { - queue.setSource(mSampleCaches[index]); - } else { - queue.setSource(mCacheManager.getReadFile(getTrackId(index), positionUs)); - } - queue.maybeReadSample(); - } - - @Override - public int readSample(int track, SampleHolder sampleHolder) { - synchronized (this) { - CachedSampleQueue queue = mPlayingSampleQueues[track]; - Assert.assertNotNull(queue); - queue.maybeReadSample(); - int result = queue.dequeueSample(sampleHolder); - if (result != SampleSource.SAMPLE_READ && getEos()) { - return SampleSource.END_OF_STREAM; - } - return result; - } - } - - @Override - public void cleanUpImpl() { - if (mSampleCaches == null) { - return; - } - for (int i = 0; i < mSampleCaches.length; ++i) { - mSampleCaches[i].finishWrite(null); - mCacheManager.unregisterEvictListener(getTrackId(i)); - } - for (int i = 0; i < mSampleCaches.length; ++i) { - mCacheManager.clearTrack(getTrackId(i)); - } - } - - @Override - public boolean continueBuffering(long positionUs) { - synchronized (this) { - boolean hasSamples = true; - mCurrentPlaybackPositionUs = positionUs; - for (CachedSampleQueue queue : mPlayingSampleQueues) { - if (queue == null) { - continue; - } - queue.maybeReadSample(); - if (queue.isEmpty()) { - hasSamples = false; - } - } - return hasSamples; - } - } - - // CacheEvictListener - @Override - public void onCacheEvicted(String id, long createdTimeMs) { - mCacheListener.onCacheStartTimeChanged( - createdTimeMs + TimeUnit.MICROSECONDS.toMillis(CHUNK_DURATION_US)); - } -} |