Snap for 6224475 from f812050941b9068ffcb21b3c99923d3a6f4be94e to rvc-release

Change-Id: I7f38912063c5c504c0ad9d52c1c23520c4bcf0e3
diff --git a/build.gradle b/build.gradle
index d7f2ae2..3aceb05 100644
--- a/build.gradle
+++ b/build.gradle
@@ -63,7 +63,7 @@
 
     sourceSets {
         main {
-            res.srcDirs = ['res', 'material_res']
+            res.srcDirs = ['res', 'material_res', 'ratings/res']
             java.srcDirs = ['src', 'partner_support/src']
             manifest.srcFile 'AndroidManifest.xml'
         }
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java b/tuner/src/com/android/tv/tuner/exoplayer2/MpegTsPlayerV2.java
index d27f487..4fa44c9 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 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 0b88ed7..21b8d48 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 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.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 @@
     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 @@
         /**
          * 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 @@
          * @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 @@
 
         /**
          * 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 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 @@
         /**
          * 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 @@
          *
          * @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 @@
          *
          * @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 @@
          *
          * @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 @@
          * @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 @@
      *
      * @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 @@
             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 @@
      * 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 @@
             if (position.basePositionUs != basePositionUs) {
                 chunk =
                         mSampleChunkCreator.loadSampleChunkFromFile(
-                                samplePool,
+                                inputBufferPool,
                                 mStorageManager.getBufferDir(),
                                 getFileName(trackId, position.positionUs),
                                 position.positionUs,
@@ -484,7 +488,7 @@
      *     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 @@
             }
             ChunkEvictedListener listener = mEvictListeners.get(earliestChunkId);
             if (listener != null) {
-                listener.onChunkEvicted(earliestChunkId, earliestChunk.getCreatedTimeMs());
+                listener.onChunkEvicted(earliestChunk.getCreatedTimeMs());
             }
             pendingDelete = mPendingDelete.getSize();
         }
@@ -564,7 +568,7 @@
      * 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 @@
      *
      * @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 @@
      *
      * @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 5549c7f..0d8a402 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 @@
         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 @@
         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 @@
         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 @@
             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 @@
         }
     }
 
-    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 @@
         }
     }
 
-    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 @@
         }
     }
 
-    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 @@
             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
similarity index 65%
rename from tuner/src/com/android/tv/tuner/exoplayer2/buffer/SamplePool.java
rename to tuner/src/com/android/tv/tuner/exoplayer2/buffer/InputBufferPool.java
index 8d4ee20..b40f4a0 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 @@
                 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 21c0919..c929253 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 @@
 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 @@
     }
 
     @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 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 @@
     }
 
     @Override
-    public void deselectTrack(int index) {
-        synchronized (this) {
-            if (mPlayingSampleQueues[index] != null) {
-                mPlayingSampleQueues[index].clear();
-                mPlayingSampleQueues[index] = null;
-            }
+    public synchronized void deselectTrack(int index) {
+        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) {
+    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 @@
     }
 
     @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 228ec91..efb5a98 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 fe2bb46..b7c3865 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.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 @@
 
     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 @@
     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 @@
      * generated class.
      */
     public interface Factory {
-        public RecordingSampleBuffer create(
+        RecordingSampleBuffer create(
                 BufferManager bufferManager,
                 PlaybackBufferListener bufferListener,
                 boolean enableTrickplay,
@@ -141,7 +139,7 @@
     }
 
     @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 @@
         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 @@
     }
 
     @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 @@
     }
 
     @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 @@
             // 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 @@
     }
 
     @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 @@
                 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 @@
 
     // 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 34090bc..1a11f03 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 @@
 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 @@
     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 @@
 
     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 @@
         /**
          * 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 @@
      * I/O operation.
      */
     @VisibleForTesting
-    public static class IoState {
+    static class IoState {
         private SampleChunk mChunk;
         private long mCurrentOffset;
 
@@ -155,7 +172,7 @@
          * 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 @@
          * 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 @@
          * 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 @@
          * @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 @@
         /**
          * 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 @@
     }
 
     @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 @@
         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 @@
         }
         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 da3dd72..5a3f668 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.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 @@
     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 @@
     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 @@
      * 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 @@
      * 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 @@
     /**
      * 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 @@
         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 @@
                 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 @@
         }
     }
 
+    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 @@
      * @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 @@
     /**
      * 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 @@
                 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 @@
         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 @@
     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 @@
                 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 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 @@
                 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 @@
                     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 30c0f53..e001849 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 ab5d0dd..b511c6a 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 @@
                         if (isCancelled()) {
                             return null;
                         }
-                        File files[] = sBufferDir.listFiles();
+                        File[] files = sBufferDir.listFiles();
                         if (files == null || files.length == 0) {
                             return null;
                         }