public final class

BitmapFactoryImageDecoder

extends SimpleDecoder<DecoderInputBuffer, ImageOutputBuffer, ImageDecoderException>

implements ImageDecoder

 java.lang.Object

androidx.media3.decoder.SimpleDecoder<DecoderInputBuffer, ImageOutputBuffer, ImageDecoderException>

↳androidx.media3.exoplayer.image.BitmapFactoryImageDecoder

Gradle dependencies

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

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

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

Overview

An image decoder that uses BitmapFactory to decode images.

Only supports decoding one input buffer into one output buffer (i.e. one Bitmap alongside one timestamp)).

Summary

Methods
protected abstract DecoderInputBuffercreateInputBuffer()

Creates a new input buffer.

protected abstract DecoderOutputBuffercreateOutputBuffer()

Creates a new output buffer.

protected abstract DecoderExceptioncreateUnexpectedDecodeException(java.lang.Throwable error)

Creates an exception to propagate for an unexpected decode error.

protected abstract DecoderExceptiondecode(DecoderInputBuffer inputBuffer, DecoderOutputBuffer outputBuffer, boolean reset)

Decodes the inputBuffer and stores any decoded output in outputBuffer.

public java.lang.StringgetName()

from SimpleDecoder<I, O, E>dequeueInputBuffer, dequeueOutputBuffer, flush, isAtLeastOutputStartTimeUs, queueInputBuffer, release, releaseOutputBuffer, setInitialInputBufferSize, setOutputStartTimeUs
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public java.lang.String getName()

protected abstract DecoderInputBuffer createInputBuffer()

Creates a new input buffer.

protected abstract DecoderOutputBuffer createOutputBuffer()

Creates a new output buffer.

protected abstract DecoderException createUnexpectedDecodeException(java.lang.Throwable error)

Creates an exception to propagate for an unexpected decode error.

Parameters:

error: The unexpected decode error.

Returns:

The exception to propagate.

protected abstract DecoderException decode(DecoderInputBuffer inputBuffer, DecoderOutputBuffer outputBuffer, boolean reset)

Decodes the inputBuffer and stores any decoded output in outputBuffer.

Parameters:

inputBuffer: The buffer to decode.
outputBuffer: The output buffer to store decoded data. The output buffer will not be made available to dequeue if its DecoderOutputBuffer.timeUs is not at least the output start time or when it's marked with DecoderOutputBuffer.shouldBeSkipped. The output buffer may not have been populated in these cases.
reset: Whether the decoder must be reset before decoding.

Returns:

A decoder exception if an error occurred, or null if decoding was successful.

Source

/*
 * Copyright 2023 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.exoplayer.image;

import static androidx.annotation.VisibleForTesting.PRIVATE;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.isBitmapFactorySupportedMimeType;
import static androidx.media3.decoder.DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.C;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.BitmapUtil;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.decoder.SimpleDecoder;
import androidx.media3.exoplayer.RendererCapabilities;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * An image decoder that uses {@link BitmapFactory} to decode images.
 *
 * <p>Only supports decoding one input buffer into one output buffer (i.e. one {@link Bitmap}
 * alongside one timestamp)).
 */
@UnstableApi
public final class BitmapFactoryImageDecoder
    extends SimpleDecoder<DecoderInputBuffer, ImageOutputBuffer, ImageDecoderException>
    implements ImageDecoder {

  /** A functional interface for turning byte arrays into bitmaps. */
  @VisibleForTesting(otherwise = PRIVATE)
  public interface BitmapDecoder {

    /**
     * Decodes data into a {@link Bitmap}.
     *
     * @param data An array holding the data to be decoded, starting at position 0.
     * @param length The length of the input to be decoded.
     * @return The decoded {@link Bitmap}.
     * @throws ImageDecoderException If a decoding error occurs.
     */
    Bitmap decode(byte[] data, int length) throws ImageDecoderException;
  }

  /** A factory for {@link BitmapFactoryImageDecoder} instances. */
  public static final class Factory implements ImageDecoder.Factory {

    private final BitmapDecoder bitmapDecoder;

    /**
     * Creates an instance using a {@link BitmapFactory} implementation of {@link BitmapDecoder}.
     */
    public Factory() {
      this.bitmapDecoder = BitmapFactoryImageDecoder::decode;
    }

    /**
     * Creates an instance.
     *
     * @param bitmapDecoder The {@link BitmapDecoder} used to turn a byte arrays into a bitmap.
     */
    public Factory(BitmapDecoder bitmapDecoder) {
      this.bitmapDecoder = bitmapDecoder;
    }

    @Override
    public @RendererCapabilities.Capabilities int supportsFormat(Format format) {
      if (format.sampleMimeType == null || !MimeTypes.isImage(format.sampleMimeType)) {
        return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
      }
      return isBitmapFactorySupportedMimeType(format.sampleMimeType)
          ? RendererCapabilities.create(C.FORMAT_HANDLED)
          : RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
    }

    @Override
    public BitmapFactoryImageDecoder createImageDecoder() {
      return new BitmapFactoryImageDecoder(bitmapDecoder);
    }
  }

  private final BitmapDecoder bitmapDecoder;

  private BitmapFactoryImageDecoder(BitmapDecoder bitmapDecoder) {
    super(new DecoderInputBuffer[1], new ImageOutputBuffer[1]);
    this.bitmapDecoder = bitmapDecoder;
  }

  @Override
  public String getName() {
    return "BitmapFactoryImageDecoder";
  }

  @Override
  protected DecoderInputBuffer createInputBuffer() {
    return new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_NORMAL);
  }

  @Override
  protected ImageOutputBuffer createOutputBuffer() {
    return new ImageOutputBuffer() {
      @Override
      public void release() {
        BitmapFactoryImageDecoder.this.releaseOutputBuffer(this);
      }
    };
  }

  @Override
  protected ImageDecoderException createUnexpectedDecodeException(Throwable error) {
    return new ImageDecoderException("Unexpected decode error", error);
  }

  @Nullable
  @Override
  protected ImageDecoderException decode(
      DecoderInputBuffer inputBuffer, ImageOutputBuffer outputBuffer, boolean reset) {
    try {
      ByteBuffer inputData = checkNotNull(inputBuffer.data);
      checkState(inputData.hasArray());
      checkArgument(inputData.arrayOffset() == 0);
      outputBuffer.bitmap = bitmapDecoder.decode(inputData.array(), inputData.remaining());
      outputBuffer.timeUs = inputBuffer.timeUs;
      return null;
    } catch (ImageDecoderException e) {
      return e;
    }
  }

  /**
   * Decodes data into a {@link Bitmap}.
   *
   * @param data An array holding the data to be decoded, starting at position 0.
   * @param length The length of the input to be decoded.
   * @return The decoded {@link Bitmap}.
   * @throws ImageDecoderException If a decoding error occurs.
   */
  private static Bitmap decode(byte[] data, int length) throws ImageDecoderException {
    try {
      return BitmapUtil.decode(data, length, /* options= */ null);
    } catch (ParserException e) {
      throw new ImageDecoderException(
          "Could not decode image data with BitmapFactory. (data.length = "
              + data.length
              + ", input length = "
              + length
              + ")",
          e);
    } catch (IOException e) {
      throw new ImageDecoderException(e);
    }
  }
}