aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-02-19 22:43:01 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-02-19 22:43:01 +0000
commit9593ed39ed95b190f713cea06c59b9bd061e96a9 (patch)
tree7e8aaaf8b95723055d1b1665a69c40c80ee6614c
parent3825a515b609c4df29adf6673949272687518b3f (diff)
parentbf7b5892a4dcc95eae704aca5e089291fa96d481 (diff)
downloadTV-9593ed39ed95b190f713cea06c59b9bd061e96a9.tar.gz
Merge "Refactor buffer classes to use Exoplayer V2 classes" am: bf7b5892a4
Change-Id: Iac9cfa33d98e2b93ffa57925769981918f21be03
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java3
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/BufferManager.java104
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/DvrStorageManager.java100
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/InputBufferPool.java (renamed from tuner/src/com/android/tv/tuner/exoplayer2/buffer/SamplePool.java)32
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/MemorySampleBuffer.java85
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/PlaybackBufferListener.java2
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/RecordingSampleBuffer.java72
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunk.java116
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java198
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleQueue.java41
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/buffer/TrickplayStorageManager.java4
11 files changed, 400 insertions, 357 deletions
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java b/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java
index d27f4878..4fa44c95 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java
@@ -104,6 +104,9 @@ public class MpegTsPlayerV2
}
+ public static final int MIN_BUFFER_MS = 0;
+ public static final int MIN_REBUFFER_MS = 500;
+
@IntDef({TRACK_TYPE_VIDEO, TRACK_TYPE_AUDIO, TRACK_TYPE_TEXT})
@Retention(RetentionPolicy.SOURCE)
public @interface TrackType {}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/BufferManager.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/BufferManager.java
index 0b88ed7f..21b8d485 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/BufferManager.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/BufferManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -26,9 +26,9 @@ import android.util.Pair;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.tuner.exoplayer.SampleExtractor;
-
-import com.google.android.exoplayer.SampleHolder;
+import com.android.tv.tuner.exoplayer2.SampleExtractor;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import java.io.File;
import java.io.IOException;
@@ -43,11 +43,12 @@ import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
- * Manages {@link SampleChunk} objects.
+ * Reads and writes the {@link SampleChunk} objects during playback and DVR. I/O operations are
+ * handled by {@link StorageManager}.
*
- * <p>The buffer manager can be disabled, while running, if the write throughput to the associated
- * external storage is detected to be lower than a threshold {@code MINIMUM_DISK_WRITE_SPEED_MBPS}".
- * This leads to restarting playback flow.
+ * <p>The buffer manager is enabled for DVR and it can be disabled for playback, while running, if
+ * the write throughput to the associated external storage is detected to be lower than a threshold
+ * {@code MINIMUM_DISK_WRITE_SPEED_MBPS}". This leads to restarting playback flow.
*/
public class BufferManager {
private static final String TAG = "BufferManager";
@@ -89,7 +90,12 @@ public class BufferManager {
private final AtomicInteger mSpeedCheckCount = new AtomicInteger();
public interface ChunkEvictedListener {
- void onChunkEvicted(String id, long createdTimeMs);
+ /**
+ * Listener for when {@link SampleChunk} is removed from track.
+ *
+ * @param createdTimeMs creation time of the evicted chunk.
+ */
+ void onChunkEvicted(long createdTimeMs);
}
/** Handles I/O between BufferManager and {@link SampleExtractor}. */
public interface SampleBuffer {
@@ -97,13 +103,13 @@ public class BufferManager {
/**
* Initializes SampleBuffer.
*
- * @param Ids track identifiers for storage read/write.
- * @param mediaFormats meta-data for each track.
- * @throws IOException
+ * @param ids track identifiers for storage read/write.
+ * @param formats meta-data for each track.
+ * @throws IOException if an I/O error occurs.
*/
void init(
- @NonNull List<String> Ids,
- @NonNull List<com.google.android.exoplayer.MediaFormat> mediaFormats)
+ @NonNull List<String> ids,
+ @NonNull List<Format> formats)
throws IOException;
/** Selects the track {@code index} for reading sample data. */
@@ -121,9 +127,9 @@ public class BufferManager {
* @param index track index
* @param sample sample to write at storage
* @param conditionVariable notifies the completion of writing sample.
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
- void writeSample(int index, SampleHolder sample, ConditionVariable conditionVariable)
+ void writeSample(int index, DecoderInputBuffer sample, ConditionVariable conditionVariable)
throws IOException;
/** Checks whether storage write speed is slow. */
@@ -131,35 +137,30 @@ public class BufferManager {
/**
* Handles when write speed is slow.
- *
- * @throws IOException
*/
- void handleWriteSpeedSlow() throws IOException;
+ void handleWriteSpeedSlow();
/** Sets the flag when EoS was reached. */
void setEos();
/**
- * Reads the next sample in the track at index {@code track} into {@code sampleHolder},
+ * Reads the next sample in the track at index {@code track} into {@code DecoderInputBuffer}
* returning {@link com.google.android.exoplayer.SampleSource#SAMPLE_READ} if it is
* available. If the next sample is not available, returns {@link
* com.google.android.exoplayer.SampleSource#NOTHING_READ}.
*/
- int readSample(int index, SampleHolder outSample);
+ int readSample(int index, DecoderInputBuffer outSample);
/** Seeks to the specified time in microseconds. */
void seekTo(long positionUs);
- /** Returns an estimate of the position up to which data is buffered. */
- long getBufferedPositionUs();
-
/** Returns whether there is buffered data. */
- boolean continueBuffering(long positionUs);
+ boolean continueLoading(long positionUs);
/**
* Cleans up and releases everything.
*
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
void release() throws IOException;
}
@@ -174,17 +175,18 @@ public class BufferManager {
public final String trackId;
/** The {@link MediaFormat} for the specified track. */
- public final MediaFormat format;
+ // TODO: Refactor to Format.
+ public final MediaFormat mediaFormat;
/**
* Creates TrackFormat.
*
- * @param trackId
- * @param format
+ * @param trackId Track id
+ * @param mediaFormat Media mediaFormat of track
*/
- public TrackFormat(String trackId, MediaFormat format) {
+ public TrackFormat(String trackId, MediaFormat mediaFormat) {
this.trackId = trackId;
- this.format = format;
+ this.mediaFormat = mediaFormat;
}
}
@@ -206,8 +208,9 @@ public class BufferManager {
/**
* Creates a holder for a specific position in the recording.
*
- * @param positionUs
- * @param offset
+ * @param positionUs Position in the recording
+ * @param basePositionUs Position of base sample
+ * @param offset Offset in the recording
*/
public PositionHolder(long positionUs, long basePositionUs, int offset) {
this.positionUs = positionUs;
@@ -265,7 +268,7 @@ public class BufferManager {
*
* @param trackId track name
* @return indexes of the specified track
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
ArrayList<PositionHolder> readIndexFile(String trackId) throws IOException;
@@ -274,7 +277,7 @@ public class BufferManager {
*
* @param formatList {@list List} of TrackFormat
* @param isAudio {@code true} if it is for audio track
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
void writeTrackInfoFiles(List<TrackFormat> formatList, boolean isAudio) throws IOException;
@@ -283,7 +286,7 @@ public class BufferManager {
*
* @param trackName track name
* @param index {@link SampleChunk} container
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
void writeIndexFile(String trackName, SortedMap<Long, Pair<SampleChunk, Integer>> index)
throws IOException;
@@ -296,7 +299,7 @@ public class BufferManager {
* @param position position in micro seconds
* @param sampleChunk {@link SampleChunk} chunk to be added
* @param offset offset
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
void updateIndexFile(
String trackName, int size, long position, SampleChunk sampleChunk, int offset)
@@ -373,17 +376,17 @@ public class BufferManager {
*
* @param id the name of the track
* @param positionUs current position to write a sample in micro seconds.
- * @param samplePool {@link SamplePool} for the fast creation of samples.
+ * @param inputBufferPool {@link InputBufferPool} for the fast creation of samples.
* @param currentChunk the current {@link SampleChunk} to write, {@code null} when to create a
* new {@link SampleChunk}.
* @param currentOffset the current offset to write.
* @return returns the created {@link SampleChunk}.
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
public SampleChunk createNewWriteFileIfNeeded(
String id,
long positionUs,
- SamplePool samplePool,
+ InputBufferPool inputBufferPool,
SampleChunk currentChunk,
int currentOffset,
boolean updateIndexFile)
@@ -402,7 +405,7 @@ public class BufferManager {
File file = new File(mStorageManager.getBufferDir(), getFileName(id, positionUs));
SampleChunk sampleChunk =
mSampleChunkCreator.createSampleChunk(
- samplePool, file, positionUs, mChunkCallback);
+ inputBufferPool, file, positionUs, mChunkCallback);
map.put(positionUs, Pair.create(sampleChunk, 0));
if (updateIndexFile) {
mStorageManager.updateIndexFile(id, map.size(), positionUs, sampleChunk, 0);
@@ -422,10 +425,11 @@ public class BufferManager {
* Loads a track using {@link BufferManager.StorageManager}.
*
* @param trackId the name of the track.
- * @param samplePool {@link SamplePool} for the fast creation of samples.
- * @throws IOException
+ * @param inputBufferPool {@link InputBufferPool} for the fast creation of samples.
+ * @throws IOException if an I/O error occurs.
*/
- public void loadTrackFromStorage(String trackId, SamplePool samplePool) throws IOException {
+ public void loadTrackFromStorage(String trackId, InputBufferPool inputBufferPool)
+ throws IOException {
ArrayList<PositionHolder> keyPositions = mStorageManager.readIndexFile(trackId);
long startPositionUs = keyPositions.size() > 0 ? keyPositions.get(0).positionUs : 0;
@@ -442,7 +446,7 @@ public class BufferManager {
if (position.basePositionUs != basePositionUs) {
chunk =
mSampleChunkCreator.loadSampleChunkFromFile(
- samplePool,
+ inputBufferPool,
mStorageManager.getBufferDir(),
getFileName(trackId, position.positionUs),
position.positionUs,
@@ -484,7 +488,7 @@ public class BufferManager {
* than
*/
public void evictChunks(String id, long earlierThanPositionUs) {
- SampleChunk chunk = null;
+ SampleChunk chunk;
while ((chunk = mPendingDelete.poll(id, earlierThanPositionUs)) != null) {
SampleChunk.IoState.release(chunk, !mStorageManager.isPersistent());
}
@@ -545,7 +549,7 @@ public class BufferManager {
}
ChunkEvictedListener listener = mEvictListeners.get(earliestChunkId);
if (listener != null) {
- listener.onChunkEvicted(earliestChunkId, earliestChunk.getCreatedTimeMs());
+ listener.onChunkEvicted(earliestChunk.getCreatedTimeMs());
}
pendingDelete = mPendingDelete.getSize();
}
@@ -564,7 +568,7 @@ public class BufferManager {
* Reads track information which includes {@link MediaFormat}.
*
* @return returns all track information which is found by {@link BufferManager.StorageManager}.
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
public List<TrackFormat> readTrackInfoFiles() throws IOException {
List<TrackFormat> trackFormatList = new ArrayList<>();
@@ -581,7 +585,7 @@ public class BufferManager {
*
* @param audios list of audio track information
* @param videos list of audio track information
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
public void writeMetaFiles(List<TrackFormat> audios, List<TrackFormat> videos)
throws IOException {
@@ -617,7 +621,7 @@ public class BufferManager {
*
* @param audios list of audio track information
* @param videos list of audio track information
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
public void writeMetaFilesOnly(List<TrackFormat> audios, List<TrackFormat> videos)
throws IOException {
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/DvrStorageManager.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/DvrStorageManager.java
index 5549c7fd..0d8a4026 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/DvrStorageManager.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/DvrStorageManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -85,27 +85,27 @@ public class DvrStorageManager implements BufferManager.StorageManager {
return !mIsRecording || mBufferDir.getUsableSpace() >= MIN_BUFFER_BYTES;
}
- private void readFormatInt(DataInputStream in, MediaFormat format, String key)
+ private void readFormatInt(DataInputStream in, MediaFormat mediaFormat, String key)
throws IOException {
int val = in.readInt();
if (val != NO_VALUE) {
- format.setInteger(key, val);
+ mediaFormat.setInteger(key, val);
}
}
- private void readFormatLong(DataInputStream in, MediaFormat format, String key)
+ private void readFormatLong(DataInputStream in, MediaFormat mediaFormat, String key)
throws IOException {
long val = in.readLong();
if (val != NO_VALUE_LONG) {
- format.setLong(key, val);
+ mediaFormat.setLong(key, val);
}
}
- private void readFormatFloat(DataInputStream in, MediaFormat format, String key)
+ private void readFormatFloat(DataInputStream in, MediaFormat mediaFormat, String key)
throws IOException {
float val = in.readFloat();
if (val != NO_VALUE) {
- format.setFloat(key, val);
+ mediaFormat.setFloat(key, val);
}
}
@@ -119,19 +119,19 @@ public class DvrStorageManager implements BufferManager.StorageManager {
return new String(strBytes, StandardCharsets.UTF_8);
}
- private void readFormatString(DataInputStream in, MediaFormat format, String key)
+ private void readFormatString(DataInputStream in, MediaFormat mediaFormat, String key)
throws IOException {
String str = readString(in);
if (str != null) {
- format.setString(key, str);
+ mediaFormat.setString(key, str);
}
}
- private void readFormatStringOptional(DataInputStream in, MediaFormat format, String key) {
+ private void readFormatStringOptional(DataInputStream in, MediaFormat mediaFormat, String key) {
try {
String str = readString(in);
if (str != null) {
- format.setString(key, str);
+ mediaFormat.setString(key, str);
}
} catch (IOException e) {
// Since we are reading optional field, ignore the exception.
@@ -152,11 +152,11 @@ public class DvrStorageManager implements BufferManager.StorageManager {
return buffer;
}
- private void readFormatByteBuffer(DataInputStream in, MediaFormat format, String key)
+ private void readFormatByteBuffer(DataInputStream in, MediaFormat mediaFormat, String key)
throws IOException {
ByteBuffer buffer = readByteBuffer(in);
if (buffer != null) {
- format.setByteBuffer(key, buffer);
+ mediaFormat.setByteBuffer(key, buffer);
}
}
@@ -172,22 +172,22 @@ public class DvrStorageManager implements BufferManager.StorageManager {
File file = new File(getBufferDir(), fileName);
try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
String name = readString(in);
- MediaFormat format = new MediaFormat();
- readFormatString(in, format, MediaFormat.KEY_MIME);
- readFormatInt(in, format, MediaFormat.KEY_MAX_INPUT_SIZE);
- readFormatInt(in, format, MediaFormat.KEY_WIDTH);
- readFormatInt(in, format, MediaFormat.KEY_HEIGHT);
- readFormatInt(in, format, MediaFormat.KEY_CHANNEL_COUNT);
- readFormatInt(in, format, MediaFormat.KEY_SAMPLE_RATE);
- readFormatFloat(in, format, KEY_PIXEL_WIDTH_HEIGHT_RATIO);
+ MediaFormat mediaFormat = new MediaFormat();
+ readFormatString(in, mediaFormat, MediaFormat.KEY_MIME);
+ readFormatInt(in, mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE);
+ readFormatInt(in, mediaFormat, MediaFormat.KEY_WIDTH);
+ readFormatInt(in, mediaFormat, MediaFormat.KEY_HEIGHT);
+ readFormatInt(in, mediaFormat, MediaFormat.KEY_CHANNEL_COUNT);
+ readFormatInt(in, mediaFormat, MediaFormat.KEY_SAMPLE_RATE);
+ readFormatFloat(in, mediaFormat, KEY_PIXEL_WIDTH_HEIGHT_RATIO);
for (int i = 0; i < 3; ++i) {
- readFormatByteBuffer(in, format, "csd-" + i);
+ readFormatByteBuffer(in, mediaFormat, "csd-" + i);
}
- readFormatLong(in, format, MediaFormat.KEY_DURATION);
+ readFormatLong(in, mediaFormat, MediaFormat.KEY_DURATION);
// This is optional since language field is added later.
- readFormatStringOptional(in, format, MediaFormat.KEY_LANGUAGE);
- trackFormatList.add(new BufferManager.TrackFormat(name, format));
+ readFormatStringOptional(in, mediaFormat, MediaFormat.KEY_LANGUAGE);
+ trackFormatList.add(new BufferManager.TrackFormat(name, mediaFormat));
} catch (IOException e) {
trackNotFound = true;
}
@@ -261,28 +261,28 @@ public class DvrStorageManager implements BufferManager.StorageManager {
}
}
- private void writeFormatInt(DataOutputStream out, MediaFormat format, String key)
+ private void writeFormatInt(DataOutputStream out, MediaFormat mediaFormat, String key)
throws IOException {
- if (format.containsKey(key)) {
- out.writeInt(format.getInteger(key));
+ if (mediaFormat.containsKey(key)) {
+ out.writeInt(mediaFormat.getInteger(key));
} else {
out.writeInt(NO_VALUE);
}
}
- private void writeFormatLong(DataOutputStream out, MediaFormat format, String key)
+ private void writeFormatLong(DataOutputStream out, MediaFormat mediaFormat, String key)
throws IOException {
- if (format.containsKey(key)) {
- out.writeLong(format.getLong(key));
+ if (mediaFormat.containsKey(key)) {
+ out.writeLong(mediaFormat.getLong(key));
} else {
out.writeLong(NO_VALUE_LONG);
}
}
- private void writeFormatFloat(DataOutputStream out, MediaFormat format, String key)
+ private void writeFormatFloat(DataOutputStream out, MediaFormat mediaFormat, String key)
throws IOException {
- if (format.containsKey(key)) {
- out.writeFloat(format.getFloat(key));
+ if (mediaFormat.containsKey(key)) {
+ out.writeFloat(mediaFormat.getFloat(key));
} else {
out.writeFloat(NO_VALUE);
}
@@ -296,10 +296,10 @@ public class DvrStorageManager implements BufferManager.StorageManager {
}
}
- private void writeFormatString(DataOutputStream out, MediaFormat format, String key)
+ private void writeFormatString(DataOutputStream out, MediaFormat mediaFormat, String key)
throws IOException {
- if (format.containsKey(key)) {
- writeString(out, format.getString(key));
+ if (mediaFormat.containsKey(key)) {
+ writeString(out, mediaFormat.getString(key));
} else {
out.writeInt(0);
}
@@ -317,10 +317,10 @@ public class DvrStorageManager implements BufferManager.StorageManager {
}
}
- private void writeFormatByteBuffer(DataOutputStream out, MediaFormat format, String key)
+ private void writeFormatByteBuffer(DataOutputStream out, MediaFormat mediaFormat, String key)
throws IOException {
- if (format.containsKey(key)) {
- writeByteBuffer(out, format.getByteBuffer(key));
+ if (mediaFormat.containsKey(key)) {
+ writeByteBuffer(out, mediaFormat.getByteBuffer(key));
} else {
out.writeInt(0);
}
@@ -337,18 +337,18 @@ public class DvrStorageManager implements BufferManager.StorageManager {
File file = new File(getBufferDir(), fileName);
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) {
writeString(out, trackFormat.trackId);
- writeFormatString(out, trackFormat.format, MediaFormat.KEY_MIME);
- writeFormatInt(out, trackFormat.format, MediaFormat.KEY_MAX_INPUT_SIZE);
- writeFormatInt(out, trackFormat.format, MediaFormat.KEY_WIDTH);
- writeFormatInt(out, trackFormat.format, MediaFormat.KEY_HEIGHT);
- writeFormatInt(out, trackFormat.format, MediaFormat.KEY_CHANNEL_COUNT);
- writeFormatInt(out, trackFormat.format, MediaFormat.KEY_SAMPLE_RATE);
- writeFormatFloat(out, trackFormat.format, KEY_PIXEL_WIDTH_HEIGHT_RATIO);
+ writeFormatString(out, trackFormat.mediaFormat, MediaFormat.KEY_MIME);
+ writeFormatInt(out, trackFormat.mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE);
+ writeFormatInt(out, trackFormat.mediaFormat, MediaFormat.KEY_WIDTH);
+ writeFormatInt(out, trackFormat.mediaFormat, MediaFormat.KEY_HEIGHT);
+ writeFormatInt(out, trackFormat.mediaFormat, MediaFormat.KEY_CHANNEL_COUNT);
+ writeFormatInt(out, trackFormat.mediaFormat, MediaFormat.KEY_SAMPLE_RATE);
+ writeFormatFloat(out, trackFormat.mediaFormat, KEY_PIXEL_WIDTH_HEIGHT_RATIO);
for (int j = 0; j < 3; ++j) {
- writeFormatByteBuffer(out, trackFormat.format, "csd-" + j);
+ writeFormatByteBuffer(out, trackFormat.mediaFormat, "csd-" + j);
}
- writeFormatLong(out, trackFormat.format, MediaFormat.KEY_DURATION);
- writeFormatString(out, trackFormat.format, MediaFormat.KEY_LANGUAGE);
+ writeFormatLong(out, trackFormat.mediaFormat, MediaFormat.KEY_DURATION);
+ writeFormatString(out, trackFormat.mediaFormat, MediaFormat.KEY_LANGUAGE);
}
}
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SamplePool.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/InputBufferPool.java
index 8d4ee20d..b40f4a06 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SamplePool.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/InputBufferPool.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -16,26 +16,28 @@
package com.android.tv.tuner.exoplayer2.buffer;
-import com.google.android.exoplayer.SampleHolder;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+
import java.util.LinkedList;
/** Pool of samples to recycle ByteBuffers as much as possible. */
-public class SamplePool {
- private final LinkedList<SampleHolder> mSamplePool = new LinkedList<>();
+public class InputBufferPool {
+ private final LinkedList<DecoderInputBuffer> mInputBufferPool = new LinkedList<>();
/**
* Acquires a sample with a buffer larger than size from the pool. Allocate new one or resize an
* existing buffer if necessary.
*/
- public synchronized SampleHolder acquireSample(int size) {
- if (mSamplePool.isEmpty()) {
- SampleHolder sample = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
+ public synchronized DecoderInputBuffer acquireSample(int size) {
+ if (mInputBufferPool.isEmpty()) {
+ DecoderInputBuffer sample =
+ new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
sample.ensureSpaceForWrite(size);
return sample;
}
- SampleHolder smallestSufficientSample = null;
- SampleHolder maxSample = mSamplePool.getFirst();
- for (SampleHolder sample : mSamplePool) {
+ DecoderInputBuffer smallestSufficientSample = null;
+ DecoderInputBuffer maxSample = mInputBufferPool.getFirst();
+ for (DecoderInputBuffer sample : mInputBufferPool) {
// Grab the smallest sufficient sample.
if (sample.data.capacity() >= size
&& (smallestSufficientSample == null
@@ -48,20 +50,20 @@ public class SamplePool {
maxSample = sample;
}
}
- SampleHolder sampleFromPool = smallestSufficientSample;
+ DecoderInputBuffer sampleFromPool = smallestSufficientSample;
// If there's no sufficient sample, grab the maximum sample and resize it to size.
if (sampleFromPool == null) {
sampleFromPool = maxSample;
sampleFromPool.ensureSpaceForWrite(size);
}
- mSamplePool.remove(sampleFromPool);
+ mInputBufferPool.remove(sampleFromPool);
return sampleFromPool;
}
/** Releases the sample back to the pool. */
- public synchronized void releaseSample(SampleHolder sample) {
- sample.clearData();
- mSamplePool.offerLast(sample);
+ public synchronized void releaseSample(DecoderInputBuffer sample) {
+ sample.clear();
+ mInputBufferPool.offerLast(sample);
}
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/MemorySampleBuffer.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/MemorySampleBuffer.java
index 21c0919a..c9292535 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/MemorySampleBuffer.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/MemorySampleBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -19,22 +19,21 @@ package com.android.tv.tuner.exoplayer2.buffer;
import android.os.ConditionVariable;
import android.support.annotation.NonNull;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.tuner.exoplayer.SampleExtractor;
-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 java.io.IOException;
+import com.android.tv.tuner.exoplayer2.SampleExtractor;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+
import java.util.List;
/**
- * Handles I/O for {@link SampleExtractor} when physical storage based buffer is not used. Trickplay
- * is disabled.
+ * Handles I/O for {@link SampleExtractor} when Trickplay is disabled. Memory storage based buffer
+ * is used instead of physical storage based buffer.
*/
public class MemorySampleBuffer implements BufferManager.SampleBuffer {
- private final SamplePool mSamplePool = new SamplePool();
+ private final InputBufferPool mInputBufferPool = new InputBufferPool();
private SampleQueue[] mPlayingSampleQueues;
- private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US;
private volatile boolean mEos;
@@ -46,8 +45,7 @@ public class MemorySampleBuffer implements BufferManager.SampleBuffer {
}
@Override
- public synchronized void init(
- @NonNull List<String> ids, @NonNull List<MediaFormat> mediaFormats) {
+ public synchronized void init(@NonNull List<String> ids, @NonNull List<Format> formats) {
int trackCount = ids.size();
mPlayingSampleQueues = new SampleQueue[trackCount];
for (int i = 0; i < trackCount; i++) {
@@ -68,7 +66,7 @@ public class MemorySampleBuffer implements BufferManager.SampleBuffer {
public void selectTrack(int index) {
synchronized (this) {
if (mPlayingSampleQueues[index] == null) {
- mPlayingSampleQueues[index] = new SampleQueue(mSamplePool);
+ mPlayingSampleQueues[index] = new SampleQueue(mInputBufferPool);
} else {
mPlayingSampleQueues[index].clear();
}
@@ -76,59 +74,36 @@ public class MemorySampleBuffer implements BufferManager.SampleBuffer {
}
@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;
+ public synchronized void deselectTrack(int index) {
+ if (mPlayingSampleQueues[index] != null) {
+ mPlayingSampleQueues[index].clear();
+ mPlayingSampleQueues[index] = null;
}
- return (mLastBufferedPositionUs = result);
}
@Override
- public synchronized int readSample(int track, SampleHolder sampleHolder) {
+ public synchronized int readSample(int track, DecoderInputBuffer 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;
+ int result = queue == null ? C.RESULT_NOTHING_READ : queue.dequeueSample(sampleHolder);
+ if (result != C.RESULT_BUFFER_READ && reachedEos()) {
+ return C.RESULT_END_OF_INPUT;
}
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();
+ public void writeSample(
+ int index, DecoderInputBuffer sample, ConditionVariable conditionVariable) {
+ int size = sample.data.position();
+ sample.data.position(0).limit(size);
+ DecoderInputBuffer sampleToQueue = mInputBufferPool.acquireSample(size);
+ sampleToQueue.data.clear();
sampleToQueue.data.put(sample.data);
sampleToQueue.timeUs = sample.timeUs;
- sampleToQueue.flags = sample.flags;
+ sampleToQueue.setFlags((sample.isKeyFrame() ? C.BUFFER_FLAG_KEY_FRAME : 0)
+ | (sample.isDecodeOnly() ? C.BUFFER_FLAG_DECODE_ONLY : 0)
+ | (sample.isEncrypted() ? C.BUFFER_FLAG_ENCRYPTED : 0));
synchronized (this) {
if (mPlayingSampleQueues[index] != null) {
@@ -150,7 +125,7 @@ public class MemorySampleBuffer implements BufferManager.SampleBuffer {
}
@Override
- public synchronized boolean continueBuffering(long positionUs) {
+ public synchronized boolean continueLoading(long positionUs) {
for (SampleQueue queue : mPlayingSampleQueues) {
if (queue == null) {
continue;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/PlaybackBufferListener.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/PlaybackBufferListener.java
index 228ec911..efb5a988 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/PlaybackBufferListener.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/PlaybackBufferListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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.
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/RecordingSampleBuffer.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/RecordingSampleBuffer.java
index fe2bb464..b7c38654 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/RecordingSampleBuffer.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/RecordingSampleBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -21,14 +21,13 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.util.Log;
-import com.android.tv.tuner.exoplayer.MpegTsPlayer;
-import com.android.tv.tuner.exoplayer.SampleExtractor;
+import com.android.tv.tuner.exoplayer2.MpegTsPlayerV2;
+import com.android.tv.tuner.exoplayer2.SampleExtractor;
-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.google.android.exoplayer.util.Assertions;
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+import com.google.android.exoplayer2.util.Assertions;
import com.google.auto.factory.AutoFactory;
import com.google.auto.factory.Provided;
@@ -68,7 +67,7 @@ public class RecordingSampleBuffer
private static final long BUFFER_WRITE_TIMEOUT_MS = 10 * 1000; // 10 seconds
private static final long BUFFER_NEEDED_US =
- 1000L * Math.max(MpegTsPlayer.MIN_BUFFER_MS, MpegTsPlayer.MIN_REBUFFER_MS);
+ 1000L * Math.max(MpegTsPlayerV2.MIN_BUFFER_MS, MpegTsPlayerV2.MIN_REBUFFER_MS);
private final BufferManager mBufferManager;
private final PlaybackBufferListener mBufferListener;
@@ -78,8 +77,7 @@ public class RecordingSampleBuffer
private int mTrackCount;
private boolean[] mTrackSelected;
private List<SampleQueue> mReadSampleQueues;
- private final SamplePool mSamplePool = new SamplePool();
- private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US;
+ private final InputBufferPool mInputBufferPool = new InputBufferPool();
private long mCurrentPlaybackPositionUs = 0;
// An error in I/O thread of {@link SampleChunkIoHelper} will be notified.
@@ -108,7 +106,7 @@ public class RecordingSampleBuffer
* generated class.
*/
public interface Factory {
- public RecordingSampleBuffer create(
+ RecordingSampleBuffer create(
BufferManager bufferManager,
PlaybackBufferListener bufferListener,
boolean enableTrickplay,
@@ -141,7 +139,7 @@ public class RecordingSampleBuffer
}
@Override
- public void init(@NonNull List<String> ids, @NonNull List<MediaFormat> mediaFormats)
+ public void init(@NonNull List<String> ids, @NonNull List<Format> formats)
throws IOException {
mTrackCount = ids.size();
if (mTrackCount <= 0) {
@@ -151,9 +149,9 @@ public class RecordingSampleBuffer
mReadSampleQueues = new ArrayList<>();
mSampleChunkIoHelper =
mSampleChunkIoHelperFactory.create(
- ids, mediaFormats, mBufferReason, mBufferManager, mSamplePool, mIoCallback);
+ ids, formats, mBufferReason, mBufferManager, mInputBufferPool, mIoCallback);
for (int i = 0; i < mTrackCount; ++i) {
- mReadSampleQueues.add(i, new SampleQueue(mSamplePool));
+ mReadSampleQueues.add(i, new SampleQueue(mInputBufferPool));
}
mSampleChunkIoHelper.init();
for (int i = 0; i < mTrackCount; ++i) {
@@ -180,8 +178,10 @@ public class RecordingSampleBuffer
}
@Override
- public void writeSample(int index, SampleHolder sample, ConditionVariable conditionVariable)
- throws IOException {
+ public void writeSample(
+ int index,
+ DecoderInputBuffer sample,
+ ConditionVariable conditionVariable) throws IOException {
mSampleChunkIoHelper.writeSample(index, sample, conditionVariable);
if (!conditionVariable.block(BUFFER_WRITE_TIMEOUT_MS)) {
@@ -200,7 +200,7 @@ public class RecordingSampleBuffer
}
@Override
- public void handleWriteSpeedSlow() throws IOException {
+ public void handleWriteSpeedSlow() {
if (mBufferReason == BUFFER_REASON_RECORDING) {
// Recording does not need to stop because I/O speed is slow temporarily.
// If fixed size buffer of TsStreamer overflows, TsDataSource will reach EoS.
@@ -233,7 +233,7 @@ public class RecordingSampleBuffer
// finish the buffering state.
return false;
}
- SampleHolder sample = mSampleChunkIoHelper.readSample(index);
+ DecoderInputBuffer sample = mSampleChunkIoHelper.readSample(index);
if (sample != null) {
queue.queueSample(sample);
return true;
@@ -242,12 +242,12 @@ public class RecordingSampleBuffer
}
@Override
- public int readSample(int track, SampleHolder outSample) {
+ public int readSample(int track, DecoderInputBuffer outSample) {
Assertions.checkState(mTrackSelected[track]);
maybeReadSample(mReadSampleQueues.get(track), track);
int result = mReadSampleQueues.get(track).dequeueSample(outSample);
- if ((result != SampleSource.SAMPLE_READ && mEos) || mError) {
- return SampleSource.END_OF_STREAM;
+ if ((result != C.RESULT_BUFFER_READ && mEos) || mError) {
+ return C.RESULT_END_OF_INPUT;
}
return result;
}
@@ -260,34 +260,10 @@ public class RecordingSampleBuffer
mSampleChunkIoHelper.openRead(i, positionUs);
}
}
- mLastBufferedPositionUs = positionUs;
- }
-
- @Override
- public long getBufferedPositionUs() {
- Long result = null;
- for (int i = 0; i < mTrackCount; ++i) {
- if (!mTrackSelected[i]) {
- continue;
- }
- Long lastQueuedSamplePositionUs = mReadSampleQueues.get(i).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 boolean continueBuffering(long positionUs) {
+ public boolean continueLoading(long positionUs) {
mCurrentPlaybackPositionUs = positionUs;
for (int i = 0; i < mTrackCount; ++i) {
if (!mTrackSelected[i]) {
@@ -316,7 +292,7 @@ public class RecordingSampleBuffer
// onChunkEvictedListener
@Override
- public void onChunkEvicted(String id, long createdTimeMs) {
+ public void onChunkEvicted(long createdTimeMs) {
if (mBufferListener != null) {
mBufferListener.onBufferStartTimeChanged(
createdTimeMs + TimeUnit.MICROSECONDS.toMillis(MIN_SEEK_DURATION_US));
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunk.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunk.java
index 34090bc4..1a11f03b 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunk.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunk.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -19,7 +19,10 @@ package com.android.tv.tuner.exoplayer2.buffer;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import com.google.android.exoplayer.SampleHolder;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -34,6 +37,17 @@ public class SampleChunk {
private static final String TAG = "SampleChunk";
private static final boolean DEBUG = false;
+ // The flag values should not be changed.
+ /**
+ * This indicates that the (encoded) buffer marked as such contains
+ * the data for a key frame.
+ */
+ private static final int BUFFER_FLAG_KEY_FRAME = 1;
+ /** Indicates that a buffer should be decoded but not rendered. */
+ private static final int BUFFER_FLAG_DECODE_ONLY = 1 << 31; // 0x80000000
+ /** Indicates that a buffer is (at least partially) encrypted. */
+ private static final int BUFFER_FLAG_ENCRYPTED = 1 << 30; // 0x40000000
+
private final long mCreatedTimeMs;
private final long mStartPositionUs;
private SampleChunk mNextChunk;
@@ -43,7 +57,7 @@ public class SampleChunk {
private final File mFile;
private final ChunkCallback mChunkCallback;
- private final SamplePool mSamplePool;
+ private final InputBufferPool mInputBufferPool;
private RandomAccessFile mAccessFile;
private long mWriteOffset;
private boolean mWriteFinished;
@@ -74,43 +88,46 @@ public class SampleChunk {
/**
* Returns a newly created SampleChunk to read & write samples.
*
- * @param samplePool sample allocator
+ * @param inputBufferPool sample allocator
* @param file filename which will be created newly
* @param startPositionUs the start position of the earliest sample to be stored
* @param chunkCallback for total storage usage change notification
*/
@VisibleForTesting
- public SampleChunk createSampleChunk(
- SamplePool samplePool,
+ SampleChunk createSampleChunk(
+ InputBufferPool inputBufferPool,
File file,
long startPositionUs,
ChunkCallback chunkCallback) {
return new SampleChunk(
- samplePool, file, startPositionUs, System.currentTimeMillis(), chunkCallback);
+ inputBufferPool,
+ file,
+ startPositionUs,
+ System.currentTimeMillis(),
+ chunkCallback);
}
/**
* Returns a newly created SampleChunk which is backed by an existing file. Created
* SampleChunk is read-only.
*
- * @param samplePool sample allocator
+ * @param inputBufferPool sample allocator
* @param bufferDir the directory where the file to read is located
* @param filename the filename which will be read afterwards
* @param startPositionUs the start position of the earliest sample in the file
* @param chunkCallback for total storage usage change notification
* @param prev the previous SampleChunk just before the newly created SampleChunk
- * @throws IOException
*/
SampleChunk loadSampleChunkFromFile(
- SamplePool samplePool,
+ InputBufferPool inputBufferPool,
File bufferDir,
String filename,
long startPositionUs,
ChunkCallback chunkCallback,
- SampleChunk prev)
- throws IOException {
+ SampleChunk prev) {
File file = new File(bufferDir, filename);
- SampleChunk chunk = new SampleChunk(samplePool, file, startPositionUs, chunkCallback);
+ SampleChunk chunk =
+ new SampleChunk(inputBufferPool, file, startPositionUs, chunkCallback);
if (prev != null) {
prev.mNextChunk = chunk;
}
@@ -123,7 +140,7 @@ public class SampleChunk {
* I/O operation.
*/
@VisibleForTesting
- public static class IoState {
+ static class IoState {
private SampleChunk mChunk;
private long mCurrentOffset;
@@ -155,7 +172,7 @@ public class SampleChunk {
* Prepares for read I/O operation from a new SampleChunk.
*
* @param chunk the new SampleChunk to read from
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
void openRead(SampleChunk chunk, long offset) throws IOException {
if (mChunk != null) {
@@ -169,7 +186,7 @@ public class SampleChunk {
* Prepares for write I/O operation to a new SampleChunk.
*
* @param chunk the new SampleChunk to write samples afterwards
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
void openWrite(SampleChunk chunk) throws IOException {
if (mChunk != null) {
@@ -183,9 +200,9 @@ public class SampleChunk {
* Reads a sample if it is available.
*
* @return Returns a sample if it is available, null otherwise.
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
- SampleHolder read() throws IOException {
+ DecoderInputBuffer read() throws IOException {
if (mChunk != null && mChunk.isReadFinished(this)) {
SampleChunk next = mChunk.mNextChunk;
mChunk.closeRead();
@@ -213,9 +230,9 @@ public class SampleChunk {
* @param sample to write
* @param nextChunk if this is {@code null} writes at the current SampleChunk, otherwise
* close current SampleChunk and writes at this
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
- void write(SampleHolder sample, SampleChunk nextChunk) throws IOException {
+ void write(DecoderInputBuffer sample, SampleChunk nextChunk) throws IOException {
if (mChunk == null) {
throw new IOException("mChunk should not be null");
}
@@ -234,7 +251,7 @@ public class SampleChunk {
/**
* Finishes write I/O operation.
*
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
void closeWrite() throws IOException {
if (mChunk != null) {
@@ -265,26 +282,28 @@ public class SampleChunk {
}
@VisibleForTesting
- protected SampleChunk(
- SamplePool samplePool,
+ SampleChunk(
+ InputBufferPool inputBufferPool,
File file,
long startPositionUs,
long createdTimeMs,
ChunkCallback chunkCallback) {
mStartPositionUs = startPositionUs;
mCreatedTimeMs = createdTimeMs;
- mSamplePool = samplePool;
+ mInputBufferPool = inputBufferPool;
mFile = file;
mChunkCallback = chunkCallback;
}
// Constructor of SampleChunk which is backed by the given existing file.
private SampleChunk(
- SamplePool samplePool, File file, long startPositionUs, ChunkCallback chunkCallback)
- throws IOException {
+ InputBufferPool inputBufferPool,
+ File file,
+ long startPositionUs,
+ ChunkCallback chunkCallback) {
mStartPositionUs = startPositionUs;
mCreatedTimeMs = mStartPositionUs / 1000;
- mSamplePool = samplePool;
+ mInputBufferPool = inputBufferPool;
mFile = file;
mChunkCallback = chunkCallback;
mWriteFinished = true;
@@ -350,7 +369,7 @@ public class SampleChunk {
return mWriteFinished && state.equals(this, mWriteOffset);
}
- private SampleHolder read(IoState state) throws IOException {
+ private DecoderInputBuffer read(IoState state) throws IOException {
if (mAccessFile == null || state.mChunk != this) {
throw new IllegalStateException("Requested read for wrong SampleChunk");
}
@@ -367,36 +386,55 @@ public class SampleChunk {
}
mAccessFile.seek(offset);
int size = mAccessFile.readInt();
- SampleHolder sample = mSamplePool.acquireSample(size);
- sample.size = size;
- sample.flags = mAccessFile.readInt();
+ DecoderInputBuffer sample = mInputBufferPool.acquireSample(size);
+ int flags = mAccessFile.readInt();
+ flags = (isKeyFrame(flags) ? C.BUFFER_FLAG_KEY_FRAME : 0)
+ | (isDecodeOnly(flags) ? C.BUFFER_FLAG_DECODE_ONLY : 0)
+ | (isEncrypted(flags) ? C.BUFFER_FLAG_ENCRYPTED : 0);
+ sample.setFlags(flags);
sample.timeUs = mAccessFile.readLong();
- sample.clearData();
+ sample.data.clear();
sample.data.put(
mAccessFile
.getChannel()
.map(
FileChannel.MapMode.READ_ONLY,
offset + SAMPLE_HEADER_LENGTH,
- sample.size));
- offset += sample.size + SAMPLE_HEADER_LENGTH;
+ size));
+ offset += size + SAMPLE_HEADER_LENGTH;
state.mCurrentOffset = offset;
return sample;
}
+ private boolean isKeyFrame(int flag) {
+ return (flag & BUFFER_FLAG_KEY_FRAME) == BUFFER_FLAG_KEY_FRAME;
+ }
+
+ private boolean isDecodeOnly(int flag) {
+ return (flag & BUFFER_FLAG_DECODE_ONLY) == BUFFER_FLAG_DECODE_ONLY;
+ }
+
+ private boolean isEncrypted(int flag) {
+ return (flag & BUFFER_FLAG_ENCRYPTED) == BUFFER_FLAG_ENCRYPTED;
+ }
+
@VisibleForTesting
- protected void write(SampleHolder sample, IoState state) throws IOException {
+ void write(DecoderInputBuffer sample, IoState state) throws IOException {
if (mAccessFile == null || mNextChunk != null || !state.equals(this, mWriteOffset)) {
throw new IllegalStateException("Requested write for wrong SampleChunk");
}
mAccessFile.seek(mWriteOffset);
- mAccessFile.writeInt(sample.size);
- mAccessFile.writeInt(sample.flags);
+ int size = sample.data.position();
+ mAccessFile.writeInt(size);
+ int flags = (sample.isKeyFrame() ? BUFFER_FLAG_KEY_FRAME : 0)
+ | (sample.isDecodeOnly() ? BUFFER_FLAG_DECODE_ONLY : 0)
+ | (sample.isEncrypted() ? BUFFER_FLAG_ENCRYPTED : 0);
+ mAccessFile.writeInt(flags);
mAccessFile.writeLong(sample.timeUs);
- sample.data.position(0).limit(sample.size);
+ sample.data.position(0).limit(size);
mAccessFile.getChannel().position(mWriteOffset + SAMPLE_HEADER_LENGTH).write(sample.data);
- mWriteOffset += sample.size + SAMPLE_HEADER_LENGTH;
+ mWriteOffset += size + SAMPLE_HEADER_LENGTH;
state.mCurrentOffset = mWriteOffset;
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java
index da3dd725..5a3f6682 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleChunkIoHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -16,7 +16,7 @@
package com.android.tv.tuner.exoplayer2.buffer;
-import android.media.MediaCodec;
+import android.media.MediaFormat;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
@@ -26,11 +26,13 @@ import android.util.Log;
import android.util.Pair;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer.BufferReason;
+import com.android.tv.tuner.exoplayer2.buffer.RecordingSampleBuffer.BufferReason;
-import com.google.android.exoplayer.MediaFormat;
-import com.google.android.exoplayer.SampleHolder;
-import com.google.android.exoplayer.util.MimeTypes;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+import com.google.android.exoplayer2.mediacodec.MediaFormatUtil;
+import com.google.android.exoplayer2.util.MimeTypes;
+import com.google.android.exoplayer2.util.Util;
import com.google.auto.factory.AutoFactory;
import java.io.IOException;
@@ -62,15 +64,15 @@ public class SampleChunkIoHelper implements Handler.Callback {
private final long mSampleChunkDurationUs;
private final int mTrackCount;
private final List<String> mIds;
- private final List<MediaFormat> mMediaFormats;
+ private final List<Format> mFormats;
private final @BufferReason int mBufferReason;
private final BufferManager mBufferManager;
- private final SamplePool mSamplePool;
+ private final InputBufferPool mInputBufferPool;
private final IoCallback mIoCallback;
private Handler mIoHandler;
- private final ConcurrentLinkedQueue<SampleHolder> mReadSampleBuffers[];
- private final ConcurrentLinkedQueue<SampleHolder> mHandlerReadSampleBuffers[];
+ private final ConcurrentLinkedQueue<DecoderInputBuffer>[] mReadSampleBuffers;
+ private final ConcurrentLinkedQueue<DecoderInputBuffer>[] mHandlerReadSampleBuffers;
private final long[] mWriteIndexEndPositionUs;
private final long[] mWriteChunkEndPositionUs;
private final SampleChunk.IoState[] mReadIoStates;
@@ -96,16 +98,16 @@ public class SampleChunkIoHelper implements Handler.Callback {
private static class IoParams {
private final int index;
private final long positionUs;
- private final SampleHolder sample;
+ private final DecoderInputBuffer sample;
private final ConditionVariable conditionVariable;
- private final ConcurrentLinkedQueue<SampleHolder> readSampleBuffer;
+ private final ConcurrentLinkedQueue<DecoderInputBuffer> readSampleBuffer;
private IoParams(
int index,
long positionUs,
- SampleHolder sample,
+ DecoderInputBuffer sample,
ConditionVariable conditionVariable,
- ConcurrentLinkedQueue<SampleHolder> readSampleBuffer) {
+ ConcurrentLinkedQueue<DecoderInputBuffer> readSampleBuffer) {
this.index = index;
this.positionUs = positionUs;
this.sample = sample;
@@ -121,12 +123,12 @@ public class SampleChunkIoHelper implements Handler.Callback {
* generated class.
*/
public interface Factory {
- public SampleChunkIoHelper create(
+ SampleChunkIoHelper create(
List<String> ids,
- List<MediaFormat> mediaFormats,
+ List<Format> formats,
@BufferReason int bufferReason,
BufferManager bufferManager,
- SamplePool samplePool,
+ InputBufferPool inputBufferPool,
IoCallback ioCallback);
}
@@ -134,26 +136,26 @@ public class SampleChunkIoHelper implements Handler.Callback {
* Creates {@link SampleChunk} I/O handler.
*
* @param ids track names
- * @param mediaFormats {@link android.media.MediaFormat} for each track
+ * @param formats {@link Format} for each track
* @param bufferReason reason to be buffered
* @param bufferManager manager of {@link SampleChunk} collections
- * @param samplePool allocator for a sample
+ * @param inputBufferPool allocator for a sample
* @param ioCallback listeners for I/O events
*/
@AutoFactory(implementing = Factory.class)
public SampleChunkIoHelper(
List<String> ids,
- List<MediaFormat> mediaFormats,
+ List<Format> formats,
@BufferReason int bufferReason,
BufferManager bufferManager,
- SamplePool samplePool,
+ InputBufferPool inputBufferPool,
IoCallback ioCallback) {
mTrackCount = ids.size();
mIds = ids;
- mMediaFormats = mediaFormats;
+ mFormats = formats;
mBufferReason = bufferReason;
mBufferManager = bufferManager;
- mSamplePool = samplePool;
+ mInputBufferPool = inputBufferPool;
mIoCallback = ioCallback;
mReadSampleBuffers = new ConcurrentLinkedQueue[mTrackCount];
@@ -182,7 +184,7 @@ public class SampleChunkIoHelper implements Handler.Callback {
/**
* Prepares and initializes for I/O operations.
*
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
public void init() throws IOException {
HandlerThread handlerThread = new HandlerThread(TAG);
@@ -190,7 +192,7 @@ public class SampleChunkIoHelper implements Handler.Callback {
mIoHandler = new Handler(handlerThread.getLooper(), this);
if (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK) {
for (int i = 0; i < mTrackCount; ++i) {
- mBufferManager.loadTrackFromStorage(mIds.get(i), mSamplePool);
+ mBufferManager.loadTrackFromStorage(mIds.get(i), mInputBufferPool);
}
mWriteEnded = true;
} else {
@@ -205,22 +207,23 @@ public class SampleChunkIoHelper implements Handler.Callback {
List<BufferManager.TrackFormat> audios = new ArrayList<>(mTrackCount);
List<BufferManager.TrackFormat> videos = new ArrayList<>(mTrackCount);
for (int i = 0; i < mTrackCount; ++i) {
- android.media.MediaFormat format =
- mMediaFormats.get(i).getFrameworkMediaFormatV16();
- format.setLong(android.media.MediaFormat.KEY_DURATION, mBufferDurationUs);
- if (mMediaFormats.get(i).pixelWidthHeightRatio > 0) {
- // MediaFormats doesn't store aspect ratio so updating the width
- // to maintain aspect ratio.
- format.setInteger(
- android.media.MediaFormat.KEY_WIDTH,
- (int)
- (mMediaFormats.get(i).width
- * mMediaFormats.get(i).pixelWidthHeightRatio));
- }
- if (MimeTypes.isAudio(mMediaFormats.get(i).mimeType)) {
- audios.add(new BufferManager.TrackFormat(mIds.get(i), format));
- } else if (MimeTypes.isVideo(mMediaFormats.get(i).mimeType)) {
- videos.add(new BufferManager.TrackFormat(mIds.get(i), format));
+ if (MimeTypes.isAudio(mFormats.get(i).sampleMimeType)) {
+ MediaFormat mediaFormat = getAudioMediaFormat(mFormats.get(i));
+ mediaFormat.setLong(MediaFormat.KEY_DURATION, mBufferDurationUs);
+ audios.add(new BufferManager.TrackFormat(mIds.get(i), mediaFormat));
+ } else if (MimeTypes.isVideo(mFormats.get(i).sampleMimeType)) {
+ MediaFormat mediaFormat = getVideoMediaFormat(mFormats.get(i));
+ mediaFormat.setLong(MediaFormat.KEY_DURATION, mBufferDurationUs);
+ if (mFormats.get(i).pixelWidthHeightRatio != Format.NO_VALUE) {
+ // MediaFormats doesn't store aspect ratio so updating the width
+ // to maintain aspect ratio.
+ mediaFormat.setInteger(
+ MediaFormat.KEY_WIDTH,
+ (int)
+ (mFormats.get(i).width
+ * mFormats.get(i).pixelWidthHeightRatio));
+ }
+ videos.add(new BufferManager.TrackFormat(mIds.get(i), mediaFormat));
}
}
mBufferManager.writeMetaFilesOnly(audios, videos);
@@ -230,14 +233,50 @@ public class SampleChunkIoHelper implements Handler.Callback {
}
}
+ private MediaFormat getVideoMediaFormat(Format format) {
+ MediaFormat mediaFormat = new MediaFormat();
+ // Set mediaFormat parameters that should always be set.
+ mediaFormat.setString(MediaFormat.KEY_MIME, format.sampleMimeType);
+ mediaFormat.setInteger(MediaFormat.KEY_WIDTH, format.width);
+ mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, format.height);
+ MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
+ // Set mediaFormat parameters that may be unset.
+ MediaFormatUtil.maybeSetFloat(mediaFormat, MediaFormat.KEY_FRAME_RATE, format.frameRate);
+ MediaFormatUtil.maybeSetInteger(
+ mediaFormat, MediaFormat.KEY_ROTATION, format.rotationDegrees);
+ MediaFormatUtil.maybeSetColorInfo(mediaFormat, format.colorInfo);
+ MediaFormatUtil.maybeSetInteger(
+ mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
+ if (Util.SDK_INT >= 23) {
+ mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */);
+ }
+ return mediaFormat;
+ }
+
+ private MediaFormat getAudioMediaFormat(Format format) {
+ MediaFormat mediaFormat = new MediaFormat();
+ // Set mediaFormat parameters that should always be set.
+ mediaFormat.setString(MediaFormat.KEY_MIME, format.sampleMimeType);
+ mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, format.channelCount);
+ mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, format.sampleRate);
+ // Set mediaFormat parameters that may be unset.
+ MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
+ MediaFormatUtil.maybeSetInteger(
+ mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
+ if (Util.SDK_INT >= 23) {
+ mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */);
+ }
+ return mediaFormat;
+ }
+
/**
* Reads a sample if it is available.
*
* @param index track index
* @return {@code null} if a sample is not available, otherwise returns a sample
*/
- public SampleHolder readSample(int index) {
- SampleHolder sample = mReadSampleBuffers[index].poll();
+ public DecoderInputBuffer readSample(int index) {
+ DecoderInputBuffer sample = mReadSampleBuffers[index].poll();
mIoHandler.sendMessage(mIoHandler.obtainMessage(MSG_READ, index));
return sample;
}
@@ -248,10 +287,12 @@ public class SampleChunkIoHelper implements Handler.Callback {
* @param index track index
* @param sample to write
* @param conditionVariable which will be wait until the write is finished
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
- public void writeSample(int index, SampleHolder sample, ConditionVariable conditionVariable)
- throws IOException {
+ public void writeSample(
+ int index,
+ DecoderInputBuffer sample,
+ ConditionVariable conditionVariable) throws IOException {
if (mErrorNotified) {
throw new IOException("Storage I/O error happened");
}
@@ -302,7 +343,7 @@ public class SampleChunkIoHelper implements Handler.Callback {
/**
* Finishes I/O operations and releases all the resources.
*
- * @throws IOException
+ * @throws IOException if an I/O error occurs.
*/
public void release() throws IOException {
if (mIoHandler == null) {
@@ -322,22 +363,23 @@ public class SampleChunkIoHelper implements Handler.Callback {
List<BufferManager.TrackFormat> audios = new LinkedList<>();
List<BufferManager.TrackFormat> videos = new LinkedList<>();
for (int i = 0; i < mTrackCount; ++i) {
- android.media.MediaFormat format =
- mMediaFormats.get(i).getFrameworkMediaFormatV16();
- format.setLong(android.media.MediaFormat.KEY_DURATION, mBufferDurationUs);
- if (mMediaFormats.get(i).pixelWidthHeightRatio > 0) {
- // MediaFormats doesn't store aspect ratio so updating the width
- // to maintain aspect ratio.
- format.setInteger(
- android.media.MediaFormat.KEY_WIDTH,
- (int)
- (mMediaFormats.get(i).width
- * mMediaFormats.get(i).pixelWidthHeightRatio));
- }
- if (MimeTypes.isAudio(mMediaFormats.get(i).mimeType)) {
- audios.add(new BufferManager.TrackFormat(mIds.get(i), format));
- } else if (MimeTypes.isVideo(mMediaFormats.get(i).mimeType)) {
- videos.add(new BufferManager.TrackFormat(mIds.get(i), format));
+ if (MimeTypes.isAudio(mFormats.get(i).sampleMimeType)) {
+ MediaFormat mediaFormat = getAudioMediaFormat(mFormats.get(i));
+ mediaFormat.setLong(MediaFormat.KEY_DURATION, mBufferDurationUs);
+ audios.add(new BufferManager.TrackFormat(mIds.get(i), mediaFormat));
+ } else if (MimeTypes.isVideo(mFormats.get(i).sampleMimeType)) {
+ MediaFormat mediaFormat = getVideoMediaFormat(mFormats.get(i));
+ mediaFormat.setLong(MediaFormat.KEY_DURATION, mBufferDurationUs);
+ if (mFormats.get(i).pixelWidthHeightRatio != Format.NO_VALUE) {
+ // MediaFormats doesn't store aspect ratio so updating the width
+ // to maintain aspect ratio.
+ mediaFormat.setInteger(
+ MediaFormat.KEY_WIDTH,
+ (int)
+ (mFormats.get(i).width
+ * mFormats.get(i).pixelWidthHeightRatio));
+ }
+ videos.add(new BufferManager.TrackFormat(mIds.get(i), mediaFormat));
}
}
mBufferManager.writeMetaFiles(audios, videos);
@@ -405,9 +447,9 @@ public class SampleChunkIoHelper implements Handler.Callback {
mSelectedTracks.add(index);
mReadIoStates[index].openRead(readPosition.first, (long) readPosition.second);
if (mHandlerReadSampleBuffers[index] != null) {
- SampleHolder sample;
+ DecoderInputBuffer sample;
while ((sample = mHandlerReadSampleBuffers[index].poll()) != null) {
- mSamplePool.releaseSample(sample);
+ mInputBufferPool.releaseSample(sample);
}
}
mHandlerReadSampleBuffers[index] = params.readSampleBuffer;
@@ -417,21 +459,21 @@ public class SampleChunkIoHelper implements Handler.Callback {
private void doOpenWrite(int index) throws IOException {
boolean updateIndexFile =
(mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING)
- && (MimeTypes.isVideo(mMediaFormats.get(index).mimeType)
- || MimeTypes.isAudio(mMediaFormats.get(index).mimeType));
+ && (MimeTypes.isVideo(mFormats.get(index).sampleMimeType)
+ || MimeTypes.isAudio(mFormats.get(index).sampleMimeType));
SampleChunk chunk =
mBufferManager.createNewWriteFileIfNeeded(
- mIds.get(index), 0, mSamplePool, null, 0, updateIndexFile);
+ mIds.get(index), 0, mInputBufferPool, null, 0, updateIndexFile);
mWriteIoStates[index].openWrite(chunk);
}
private void doCloseRead(int index) {
mSelectedTracks.remove(index);
if (mHandlerReadSampleBuffers[index] != null) {
- SampleHolder sample;
+ DecoderInputBuffer sample;
while ((sample = mHandlerReadSampleBuffers[index].poll()) != null) {
- mSamplePool.releaseSample(sample);
+ mInputBufferPool.releaseSample(sample);
}
}
mIoHandler.removeMessages(MSG_READ, index);
@@ -454,7 +496,7 @@ public class SampleChunkIoHelper implements Handler.Callback {
mIoCallback.onIoReachedEos();
return;
}
- SampleHolder sample = mReadIoStates[index].read();
+ DecoderInputBuffer sample = mReadIoStates[index].read();
if (sample != null) {
mHandlerReadSampleBuffers[index].offer(sample);
mReadChunkOffset[index] = mReadIoStates[index].getOffset();
@@ -472,11 +514,11 @@ public class SampleChunkIoHelper implements Handler.Callback {
}
}
- public void doUpdateIndex(IoParams params) throws IOException {
+ private void doUpdateIndex(IoParams params) throws IOException {
int index = params.index;
mIoHandler.removeMessages(MSG_READ, index);
// Update Track from Storage to load new Samples
- mBufferManager.loadTrackFromStorage(mIds.get(index), mSamplePool);
+ mBufferManager.loadTrackFromStorage(mIds.get(index), mInputBufferPool);
Pair<SampleChunk, Integer> readPosition =
mBufferManager.getReadFile(mIds.get(index), mReadChunkPositionUs[index]);
if (readPosition == null) {
@@ -500,9 +542,9 @@ public class SampleChunkIoHelper implements Handler.Callback {
return;
}
int index = params.index;
- SampleHolder sample = params.sample;
+ DecoderInputBuffer sample = params.sample;
SampleChunk nextChunk = null;
- if ((sample.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
+ if (sample.isKeyFrame()) {
if (sample.timeUs > mBufferDurationUs) {
mBufferDurationUs = sample.timeUs;
}
@@ -514,15 +556,15 @@ public class SampleChunkIoHelper implements Handler.Callback {
int currentOffset = (int) mWriteIoStates[params.index].getOffset();
boolean updateIndexFile =
(mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING)
- && (MimeTypes.isVideo(mMediaFormats.get(index).mimeType)
+ && (MimeTypes.isVideo(mFormats.get(index).sampleMimeType)
|| MimeTypes.isAudio(
- mMediaFormats.get(index).mimeType));
+ mFormats.get(index).sampleMimeType));
nextChunk =
mBufferManager.createNewWriteFileIfNeeded(
mIds.get(index),
mWriteIndexEndPositionUs[index],
- mSamplePool,
+ mInputBufferPool,
currentChunk,
currentOffset,
updateIndexFile);
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleQueue.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleQueue.java
index 30c0f532..e001849a 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleQueue.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/SampleQueue.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -16,44 +16,47 @@
package com.android.tv.tuner.exoplayer2.buffer;
-import com.google.android.exoplayer.SampleHolder;
-import com.google.android.exoplayer.SampleSource;
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+
import java.util.LinkedList;
/** A sample queue which reads from the buffer and passes to player pipeline. */
public class SampleQueue {
- private final LinkedList<SampleHolder> mQueue = new LinkedList<>();
- private final SamplePool mSamplePool;
+ private final LinkedList<DecoderInputBuffer> mQueue = new LinkedList<>();
+ private final InputBufferPool mInputBufferPool;
private Long mLastQueuedPositionUs = null;
- public SampleQueue(SamplePool samplePool) {
- mSamplePool = samplePool;
+ public SampleQueue(InputBufferPool inputBufferPool) {
+ mInputBufferPool = inputBufferPool;
}
- public void queueSample(SampleHolder sample) {
+ public void queueSample(DecoderInputBuffer sample) {
mQueue.offer(sample);
mLastQueuedPositionUs = sample.timeUs;
}
- public int dequeueSample(SampleHolder sample) {
- SampleHolder sampleFromQueue = mQueue.poll();
+ public int dequeueSample(DecoderInputBuffer sample) {
+ DecoderInputBuffer sampleFromQueue = mQueue.poll();
if (sampleFromQueue == null) {
- return SampleSource.NOTHING_READ;
+ return C.RESULT_NOTHING_READ;
}
- sample.ensureSpaceForWrite(sampleFromQueue.size);
- sample.size = sampleFromQueue.size;
- sample.flags = sampleFromQueue.flags;
+ int size = sampleFromQueue.data.position();
+ sample.ensureSpaceForWrite(size);
+ sample.setFlags((sampleFromQueue.isKeyFrame() ? C.BUFFER_FLAG_KEY_FRAME : 0)
+ | (sampleFromQueue.isDecodeOnly() ? C.BUFFER_FLAG_DECODE_ONLY : 0)
+ | (sampleFromQueue.isEncrypted() ? C.BUFFER_FLAG_ENCRYPTED : 0));
sample.timeUs = sampleFromQueue.timeUs;
- sample.clearData();
- sampleFromQueue.data.position(0).limit(sample.size);
+ sample.data.clear();
+ sampleFromQueue.flip();
sample.data.put(sampleFromQueue.data);
- mSamplePool.releaseSample(sampleFromQueue);
- return SampleSource.SAMPLE_READ;
+ mInputBufferPool.releaseSample(sampleFromQueue);
+ return C.RESULT_BUFFER_READ;
}
public void clear() {
while (!mQueue.isEmpty()) {
- mSamplePool.releaseSample(mQueue.poll());
+ mInputBufferPool.releaseSample(mQueue.poll());
}
mLastQueuedPositionUs = null;
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/TrickplayStorageManager.java b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/TrickplayStorageManager.java
index ab5d0ddf..b511c6ab 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/buffer/TrickplayStorageManager.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/buffer/TrickplayStorageManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -87,7 +87,7 @@ public class TrickplayStorageManager implements BufferManager.StorageManager {
if (isCancelled()) {
return null;
}
- File files[] = sBufferDir.listFiles();
+ File[] files = sBufferDir.listFiles();
if (files == null || files.length == 0) {
return null;
}