1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.decoder; 17 18 import androidx.annotation.IntDef; 19 import androidx.annotation.Nullable; 20 import com.google.android.exoplayer2.C; 21 import java.lang.annotation.Documented; 22 import java.lang.annotation.Retention; 23 import java.lang.annotation.RetentionPolicy; 24 import java.nio.ByteBuffer; 25 import org.checkerframework.checker.nullness.qual.EnsuresNonNull; 26 27 /** 28 * Holds input for a decoder. 29 */ 30 public class DecoderInputBuffer extends Buffer { 31 32 /** 33 * The buffer replacement mode, which may disable replacement. One of {@link 34 * #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} or {@link 35 * #BUFFER_REPLACEMENT_MODE_DIRECT}. 36 */ 37 @Documented 38 @Retention(RetentionPolicy.SOURCE) 39 @IntDef({ 40 BUFFER_REPLACEMENT_MODE_DISABLED, 41 BUFFER_REPLACEMENT_MODE_NORMAL, 42 BUFFER_REPLACEMENT_MODE_DIRECT 43 }) 44 public @interface BufferReplacementMode {} 45 /** 46 * Disallows buffer replacement. 47 */ 48 public static final int BUFFER_REPLACEMENT_MODE_DISABLED = 0; 49 /** 50 * Allows buffer replacement using {@link ByteBuffer#allocate(int)}. 51 */ 52 public static final int BUFFER_REPLACEMENT_MODE_NORMAL = 1; 53 /** 54 * Allows buffer replacement using {@link ByteBuffer#allocateDirect(int)}. 55 */ 56 public static final int BUFFER_REPLACEMENT_MODE_DIRECT = 2; 57 58 /** 59 * {@link CryptoInfo} for encrypted data. 60 */ 61 public final CryptoInfo cryptoInfo; 62 63 /** The buffer's data, or {@code null} if no data has been set. */ 64 @Nullable public ByteBuffer data; 65 66 // TODO: Remove this temporary signaling once end-of-stream propagation for clips using content 67 // protection is fixed. See [Internal: b/153326944] for details. 68 /** 69 * Whether the last attempt to read a sample into this buffer failed due to not yet having the DRM 70 * keys associated with the next sample. 71 */ 72 public boolean waitingForKeys; 73 74 /** 75 * The time at which the sample should be presented. 76 */ 77 public long timeUs; 78 79 /** 80 * Supplemental data related to the buffer, if {@link #hasSupplementalData()} returns true. If 81 * present, the buffer is populated with supplemental data from position 0 to its limit. 82 */ 83 @Nullable public ByteBuffer supplementalData; 84 85 @BufferReplacementMode private final int bufferReplacementMode; 86 87 /** 88 * Creates a new instance for which {@link #isFlagsOnly()} will return true. 89 * 90 * @return A new flags only input buffer. 91 */ newFlagsOnlyInstance()92 public static DecoderInputBuffer newFlagsOnlyInstance() { 93 return new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED); 94 } 95 96 /** 97 * @param bufferReplacementMode Determines the behavior of {@link #ensureSpaceForWrite(int)}. One 98 * of {@link #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} and 99 * {@link #BUFFER_REPLACEMENT_MODE_DIRECT}. 100 */ DecoderInputBuffer(@ufferReplacementMode int bufferReplacementMode)101 public DecoderInputBuffer(@BufferReplacementMode int bufferReplacementMode) { 102 this.cryptoInfo = new CryptoInfo(); 103 this.bufferReplacementMode = bufferReplacementMode; 104 } 105 106 /** 107 * Clears {@link #supplementalData} and ensures that it's large enough to accommodate {@code 108 * length} bytes. 109 * 110 * @param length The length of the supplemental data that must be accommodated, in bytes. 111 */ 112 @EnsuresNonNull("supplementalData") resetSupplementalData(int length)113 public void resetSupplementalData(int length) { 114 if (supplementalData == null || supplementalData.capacity() < length) { 115 supplementalData = ByteBuffer.allocate(length); 116 } else { 117 supplementalData.clear(); 118 } 119 } 120 121 /** 122 * Ensures that {@link #data} is large enough to accommodate a write of a given length at its 123 * current position. 124 * 125 * <p>If the capacity of {@link #data} is sufficient this method does nothing. If the capacity is 126 * insufficient then an attempt is made to replace {@link #data} with a new {@link ByteBuffer} 127 * whose capacity is sufficient. Data up to the current position is copied to the new buffer. 128 * 129 * @param length The length of the write that must be accommodated, in bytes. 130 * @throws IllegalStateException If there is insufficient capacity to accommodate the write and 131 * the buffer replacement mode of the holder is {@link #BUFFER_REPLACEMENT_MODE_DISABLED}. 132 */ 133 @EnsuresNonNull("data") ensureSpaceForWrite(int length)134 public void ensureSpaceForWrite(int length) { 135 if (data == null) { 136 data = createReplacementByteBuffer(length); 137 return; 138 } 139 // Check whether the current buffer is sufficient. 140 int capacity = data.capacity(); 141 int position = data.position(); 142 int requiredCapacity = position + length; 143 if (capacity >= requiredCapacity) { 144 return; 145 } 146 // Instantiate a new buffer if possible. 147 ByteBuffer newData = createReplacementByteBuffer(requiredCapacity); 148 newData.order(data.order()); 149 // Copy data up to the current position from the old buffer to the new one. 150 if (position > 0) { 151 data.flip(); 152 newData.put(data); 153 } 154 // Set the new buffer. 155 data = newData; 156 } 157 158 /** 159 * Returns whether the buffer is only able to hold flags, meaning {@link #data} is null and 160 * its replacement mode is {@link #BUFFER_REPLACEMENT_MODE_DISABLED}. 161 */ isFlagsOnly()162 public final boolean isFlagsOnly() { 163 return data == null && bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DISABLED; 164 } 165 166 /** 167 * Returns whether the {@link C#BUFFER_FLAG_ENCRYPTED} flag is set. 168 */ isEncrypted()169 public final boolean isEncrypted() { 170 return getFlag(C.BUFFER_FLAG_ENCRYPTED); 171 } 172 173 /** 174 * Flips {@link #data} and {@link #supplementalData} in preparation for being queued to a decoder. 175 * 176 * @see java.nio.Buffer#flip() 177 */ flip()178 public final void flip() { 179 data.flip(); 180 if (supplementalData != null) { 181 supplementalData.flip(); 182 } 183 } 184 185 @Override clear()186 public void clear() { 187 super.clear(); 188 if (data != null) { 189 data.clear(); 190 } 191 if (supplementalData != null) { 192 supplementalData.clear(); 193 } 194 waitingForKeys = false; 195 } 196 createReplacementByteBuffer(int requiredCapacity)197 private ByteBuffer createReplacementByteBuffer(int requiredCapacity) { 198 if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_NORMAL) { 199 return ByteBuffer.allocate(requiredCapacity); 200 } else if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DIRECT) { 201 return ByteBuffer.allocateDirect(requiredCapacity); 202 } else { 203 int currentCapacity = data == null ? 0 : data.capacity(); 204 throw new IllegalStateException("Buffer too small (" + currentCapacity + " < " 205 + requiredCapacity + ")"); 206 } 207 } 208 209 } 210