public class

DecoderInputBuffer

extends Buffer

 java.lang.Object

androidx.media3.decoder.Buffer

↳androidx.media3.decoder.DecoderInputBuffer

Subclasses:

MetadataInputBuffer, SubtitleInputBuffer

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-decoder', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-decoder
  • version: 1.5.0-alpha01

Artifact androidx.media3:media3-decoder:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

Holds input for a decoder.

Summary

Fields
public static final intBUFFER_REPLACEMENT_MODE_DIRECT

Allows buffer replacement using allocateDirect.

public static final intBUFFER_REPLACEMENT_MODE_DISABLED

Disallows buffer replacement.

public static final intBUFFER_REPLACEMENT_MODE_NORMAL

Allows buffer replacement using allocate.

public final CryptoInfocryptoInfo

CryptoInfo for encrypted data.

public java.nio.ByteBufferdata

The buffer's data, or null if no data has been set.

public Formatformat

The Format.

public java.nio.ByteBuffersupplementalData

Supplemental data related to the buffer, if Buffer.hasSupplementalData() returns true.

public longtimeUs

The time at which the sample should be presented.

public booleanwaitingForKeys

Whether the last attempt to read a sample into this buffer failed due to not yet having the DRM keys associated with the next sample.

Constructors
publicDecoderInputBuffer(int bufferReplacementMode)

Creates a new instance.

publicDecoderInputBuffer(int bufferReplacementMode, int paddingSize)

Creates a new instance.

Methods
public voidclear()

Clears the buffer.

public voidensureSpaceForWrite(int length)

Ensures that DecoderInputBuffer.data is large enough to accommodate a write of a given length at its current position.

public final voidflip()

Flips DecoderInputBuffer.data and DecoderInputBuffer.supplementalData in preparation for being queued to a decoder.

public final booleanisEncrypted()

Returns whether the C.BUFFER_FLAG_ENCRYPTED flag is set.

public static DecoderInputBuffernewNoDataInstance()

Returns a new instance that's not able to hold any data.

public voidresetSupplementalData(int length)

Clears DecoderInputBuffer.supplementalData and ensures that it's large enough to accommodate length bytes.

from BufferaddFlag, clearFlag, getFlag, hasSupplementalData, isEndOfStream, isFirstSample, isKeyFrame, isLastSample, notDependedOn, setFlags
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final int BUFFER_REPLACEMENT_MODE_DISABLED

Disallows buffer replacement.

public static final int BUFFER_REPLACEMENT_MODE_NORMAL

Allows buffer replacement using allocate.

public static final int BUFFER_REPLACEMENT_MODE_DIRECT

Allows buffer replacement using allocateDirect.

public Format format

The Format.

public final CryptoInfo cryptoInfo

CryptoInfo for encrypted data.

public java.nio.ByteBuffer data

The buffer's data, or null if no data has been set.

public boolean waitingForKeys

Whether the last attempt to read a sample into this buffer failed due to not yet having the DRM keys associated with the next sample.

public long timeUs

The time at which the sample should be presented.

public java.nio.ByteBuffer supplementalData

Supplemental data related to the buffer, if Buffer.hasSupplementalData() returns true. If present, the buffer is populated with supplemental data from position 0 to its limit.

Constructors

public DecoderInputBuffer(int bufferReplacementMode)

Creates a new instance.

Parameters:

bufferReplacementMode: The DecoderInputBuffer.BufferReplacementMode replacement mode.

public DecoderInputBuffer(int bufferReplacementMode, int paddingSize)

Creates a new instance.

Parameters:

bufferReplacementMode: The DecoderInputBuffer.BufferReplacementMode replacement mode.
paddingSize: If non-zero, DecoderInputBuffer.ensureSpaceForWrite(int) will ensure that the buffer is this number of bytes larger than the requested length. This can be useful for decoders that consume data in fixed size blocks, for efficiency. Setting the padding size to the decoder's fixed read size is necessary to prevent such a decoder from trying to read beyond the end of the buffer.

Methods

public static DecoderInputBuffer newNoDataInstance()

Returns a new instance that's not able to hold any data.

public void resetSupplementalData(int length)

Clears DecoderInputBuffer.supplementalData and ensures that it's large enough to accommodate length bytes.

Parameters:

length: The length of the supplemental data that must be accommodated, in bytes.

public void ensureSpaceForWrite(int length)

Ensures that DecoderInputBuffer.data is large enough to accommodate a write of a given length at its current position.

If the capacity of DecoderInputBuffer.data is sufficient this method does nothing. If the capacity is insufficient then an attempt is made to replace DecoderInputBuffer.data with a new java.nio.ByteBuffer whose capacity is sufficient. Data up to the current position is copied to the new buffer.

Parameters:

length: The length of the write that must be accommodated, in bytes.

public final boolean isEncrypted()

Returns whether the C.BUFFER_FLAG_ENCRYPTED flag is set.

public final void flip()

Flips DecoderInputBuffer.data and DecoderInputBuffer.supplementalData in preparation for being queued to a decoder.

See also: flip

public void clear()

Clears the buffer.

Source

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package androidx.media3.decoder;

import static java.lang.annotation.ElementType.TYPE_USE;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Format;
import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.nio.ByteBuffer;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;

/** Holds input for a decoder. */
@UnstableApi
public class DecoderInputBuffer extends Buffer {

  static {
    MediaLibraryInfo.registerModule("media3.decoder");
  }

  /**
   * Thrown when an attempt is made to write into a {@link DecoderInputBuffer} whose {@link
   * #bufferReplacementMode} is {@link #BUFFER_REPLACEMENT_MODE_DISABLED} and who {@link #data}
   * capacity is smaller than required.
   */
  public static final class InsufficientCapacityException extends IllegalStateException {

    /** The current capacity of the buffer. */
    public final int currentCapacity;

    /** The required capacity of the buffer. */
    public final int requiredCapacity;

    /**
     * Creates an instance.
     *
     * @param currentCapacity The current capacity of the buffer.
     * @param requiredCapacity The required capacity of the buffer.
     */
    public InsufficientCapacityException(int currentCapacity, int requiredCapacity) {
      super("Buffer too small (" + currentCapacity + " < " + requiredCapacity + ")");
      this.currentCapacity = currentCapacity;
      this.requiredCapacity = requiredCapacity;
    }
  }

  /**
   * The buffer replacement mode. This controls how {@link #ensureSpaceForWrite} generates
   * replacement buffers when the capacity of the existing buffer is insufficient. One of {@link
   * #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} or {@link
   * #BUFFER_REPLACEMENT_MODE_DIRECT}.
   */
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target(TYPE_USE)
  @IntDef({
    BUFFER_REPLACEMENT_MODE_DISABLED,
    BUFFER_REPLACEMENT_MODE_NORMAL,
    BUFFER_REPLACEMENT_MODE_DIRECT
  })
  public @interface BufferReplacementMode {}

  /** Disallows buffer replacement. */
  public static final int BUFFER_REPLACEMENT_MODE_DISABLED = 0;

  /** Allows buffer replacement using {@link ByteBuffer#allocate(int)}. */
  public static final int BUFFER_REPLACEMENT_MODE_NORMAL = 1;

  /** Allows buffer replacement using {@link ByteBuffer#allocateDirect(int)}. */
  public static final int BUFFER_REPLACEMENT_MODE_DIRECT = 2;

  /** The {@link Format}. */
  @Nullable public Format format;

  /** {@link CryptoInfo} for encrypted data. */
  public final CryptoInfo cryptoInfo;

  /** The buffer's data, or {@code null} if no data has been set. */
  @Nullable public ByteBuffer data;

  // TODO: Remove this temporary signaling once end-of-stream propagation for clips using content
  // protection is fixed. See [Internal: b/153326944] for details.
  /**
   * Whether the last attempt to read a sample into this buffer failed due to not yet having the DRM
   * keys associated with the next sample.
   */
  public boolean waitingForKeys;

  /** The time at which the sample should be presented. */
  public long timeUs;

  /**
   * Supplemental data related to the buffer, if {@link #hasSupplementalData()} returns true. If
   * present, the buffer is populated with supplemental data from position 0 to its limit.
   */
  @Nullable public ByteBuffer supplementalData;

  private final @BufferReplacementMode int bufferReplacementMode;
  private final int paddingSize;

  /** Returns a new instance that's not able to hold any data. */
  public static DecoderInputBuffer newNoDataInstance() {
    return new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED);
  }

  /**
   * Creates a new instance.
   *
   * @param bufferReplacementMode The {@link BufferReplacementMode} replacement mode.
   */
  public DecoderInputBuffer(@BufferReplacementMode int bufferReplacementMode) {
    this(bufferReplacementMode, /* paddingSize= */ 0);
  }

  /**
   * Creates a new instance.
   *
   * @param bufferReplacementMode The {@link BufferReplacementMode} replacement mode.
   * @param paddingSize If non-zero, {@link #ensureSpaceForWrite(int)} will ensure that the buffer
   *     is this number of bytes larger than the requested length. This can be useful for decoders
   *     that consume data in fixed size blocks, for efficiency. Setting the padding size to the
   *     decoder's fixed read size is necessary to prevent such a decoder from trying to read beyond
   *     the end of the buffer.
   */
  public DecoderInputBuffer(@BufferReplacementMode int bufferReplacementMode, int paddingSize) {
    this.cryptoInfo = new CryptoInfo();
    this.bufferReplacementMode = bufferReplacementMode;
    this.paddingSize = paddingSize;
  }

  /**
   * Clears {@link #supplementalData} and ensures that it's large enough to accommodate {@code
   * length} bytes.
   *
   * @param length The length of the supplemental data that must be accommodated, in bytes.
   */
  @EnsuresNonNull("supplementalData")
  public void resetSupplementalData(int length) {
    if (supplementalData == null || supplementalData.capacity() < length) {
      supplementalData = ByteBuffer.allocate(length);
    } else {
      supplementalData.clear();
    }
  }

  /**
   * Ensures that {@link #data} is large enough to accommodate a write of a given length at its
   * current position.
   *
   * <p>If the capacity of {@link #data} is sufficient this method does nothing. If the capacity is
   * insufficient then an attempt is made to replace {@link #data} with a new {@link ByteBuffer}
   * whose capacity is sufficient. Data up to the current position is copied to the new buffer.
   *
   * @param length The length of the write that must be accommodated, in bytes.
   * @throws InsufficientCapacityException If there is insufficient capacity to accommodate the
   *     write and {@link #bufferReplacementMode} is {@link #BUFFER_REPLACEMENT_MODE_DISABLED}.
   */
  @EnsuresNonNull("data")
  public void ensureSpaceForWrite(int length) {
    length += paddingSize;
    @Nullable ByteBuffer currentData = data;
    if (currentData == null) {
      data = createReplacementByteBuffer(length);
      return;
    }
    // Check whether the current buffer is sufficient.
    int capacity = currentData.capacity();
    int position = currentData.position();
    int requiredCapacity = position + length;
    if (capacity >= requiredCapacity) {
      data = currentData;
      return;
    }
    // Instantiate a new buffer if possible.
    ByteBuffer newData = createReplacementByteBuffer(requiredCapacity);
    newData.order(currentData.order());
    // Copy data up to the current position from the old buffer to the new one.
    if (position > 0) {
      currentData.flip();
      newData.put(currentData);
    }
    // Set the new buffer.
    data = newData;
  }

  /** Returns whether the {@link C#BUFFER_FLAG_ENCRYPTED} flag is set. */
  public final boolean isEncrypted() {
    return getFlag(C.BUFFER_FLAG_ENCRYPTED);
  }

  /**
   * Flips {@link #data} and {@link #supplementalData} in preparation for being queued to a decoder.
   *
   * @see java.nio.Buffer#flip()
   */
  public final void flip() {
    if (data != null) {
      data.flip();
    }
    if (supplementalData != null) {
      supplementalData.flip();
    }
  }

  @Override
  public void clear() {
    super.clear();
    if (data != null) {
      data.clear();
    }
    if (supplementalData != null) {
      supplementalData.clear();
    }
    waitingForKeys = false;
  }

  private ByteBuffer createReplacementByteBuffer(int requiredCapacity) {
    if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_NORMAL) {
      return ByteBuffer.allocate(requiredCapacity);
    } else if (bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DIRECT) {
      return ByteBuffer.allocateDirect(requiredCapacity);
    } else {
      int currentCapacity = data == null ? 0 : data.capacity();
      throw new InsufficientCapacityException(currentCapacity, requiredCapacity);
    }
  }
}