public final class

CodecSpecificDataUtil

extends java.lang.Object

 java.lang.Object

↳androidx.media3.common.util.CodecSpecificDataUtil

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-common', version: '1.0.0-alpha03'

  • groupId: androidx.media3
  • artifactId: media3-common
  • version: 1.0.0-alpha03

Artifact androidx.media3:media3-common:1.0.0-alpha03 it located at Google repository (https://maven.google.com/)

Overview

Provides utilities for handling various types of codec-specific data.

Summary

Methods
public static java.lang.StringbuildAvcCodecString(int profileIdc, int constraintsFlagsAndReservedZero2Bits, int levelIdc)

Builds an RFC 6381 AVC codec string using the provided parameters.

public static java.util.List<UnknownReference>buildCea708InitializationData(boolean isWideAspectRatio)

Returns initialization data for formats with MIME type MimeTypes.APPLICATION_CEA708.

public static java.lang.StringbuildHevcCodecString(int generalProfileSpace, boolean generalTierFlag, int generalProfileIdc, int generalProfileCompatibilityFlags, int[] constraintBytes[], int generalLevelIdc)

Builds an RFC 6381 HEVC codec string using the provided parameters.

public static byte[]buildNalUnit(byte[] data[], int offset, int length)

Constructs a NAL unit consisting of the NAL start code followed by the specified data.

public static <any>parseAlacAudioSpecificConfig(byte[] audioSpecificConfig[])

Parses an ALAC AudioSpecificConfig (i.e.

public static booleanparseCea708InitializationData(java.util.List<UnknownReference> initializationData)

Returns whether the CEA-708 closed caption service with the given initialization data is formatted for displays with 16:9 aspect ratio.

public static byte[][]splitNalUnits(byte[] data[])

Splits an array of NAL units.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public static <any> parseAlacAudioSpecificConfig(byte[] audioSpecificConfig[])

Parses an ALAC AudioSpecificConfig (i.e. an ALACSpecificConfig).

Parameters:

audioSpecificConfig: A byte array containing the AudioSpecificConfig to parse.

Returns:

A pair consisting of the sample rate in Hz and the channel count.

public static java.util.List<UnknownReference> buildCea708InitializationData(boolean isWideAspectRatio)

Returns initialization data for formats with MIME type MimeTypes.APPLICATION_CEA708.

Parameters:

isWideAspectRatio: Whether the CEA-708 closed caption service is formatted for displays with 16:9 aspect ratio.

Returns:

Initialization data for formats with MIME type MimeTypes.APPLICATION_CEA708.

public static boolean parseCea708InitializationData(java.util.List<UnknownReference> initializationData)

Returns whether the CEA-708 closed caption service with the given initialization data is formatted for displays with 16:9 aspect ratio.

Parameters:

initializationData: The initialization data to parse.

Returns:

Whether the CEA-708 closed caption service is formatted for displays with 16:9 aspect ratio.

public static java.lang.String buildAvcCodecString(int profileIdc, int constraintsFlagsAndReservedZero2Bits, int levelIdc)

Builds an RFC 6381 AVC codec string using the provided parameters.

Parameters:

profileIdc: The encoding profile.
constraintsFlagsAndReservedZero2Bits: The constraint flags followed by the reserved zero 2 bits, all contained in the least significant byte of the integer.
levelIdc: The encoding level.

Returns:

An RFC 6381 AVC codec string built using the provided parameters.

public static java.lang.String buildHevcCodecString(int generalProfileSpace, boolean generalTierFlag, int generalProfileIdc, int generalProfileCompatibilityFlags, int[] constraintBytes[], int generalLevelIdc)

Builds an RFC 6381 HEVC codec string using the provided parameters.

public static byte[] buildNalUnit(byte[] data[], int offset, int length)

Constructs a NAL unit consisting of the NAL start code followed by the specified data.

Parameters:

data: An array containing the data that should follow the NAL start code.
offset: The start offset into data.
length: The number of bytes to copy from data

Returns:

The constructed NAL unit.

public static byte[][] splitNalUnits(byte[] data[])

Splits an array of NAL units.

If the input consists of NAL start code delimited units, then the returned array consists of the split NAL units, each of which is still prefixed with the NAL start code. For any other input, null is returned.

Parameters:

data: An array of data.

Returns:

The individual NAL units, or null if the input did not consist of NAL start code delimited units.

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.common.util;

import android.util.Pair;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.MimeTypes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/** Provides utilities for handling various types of codec-specific data. */
@UnstableApi
public final class CodecSpecificDataUtil {

  private static final byte[] NAL_START_CODE = new byte[] {0, 0, 0, 1};
  private static final String[] HEVC_GENERAL_PROFILE_SPACE_STRINGS =
      new String[] {"", "A", "B", "C"};

  /**
   * Parses an ALAC AudioSpecificConfig (i.e. an <a
   * href="https://github.com/macosforge/alac/blob/master/ALACMagicCookieDescription.txt">ALACSpecificConfig</a>).
   *
   * @param audioSpecificConfig A byte array containing the AudioSpecificConfig to parse.
   * @return A pair consisting of the sample rate in Hz and the channel count.
   */
  public static Pair<Integer, Integer> parseAlacAudioSpecificConfig(byte[] audioSpecificConfig) {
    ParsableByteArray byteArray = new ParsableByteArray(audioSpecificConfig);
    byteArray.setPosition(9);
    int channelCount = byteArray.readUnsignedByte();
    byteArray.setPosition(20);
    int sampleRate = byteArray.readUnsignedIntToInt();
    return Pair.create(sampleRate, channelCount);
  }

  /**
   * Returns initialization data for formats with MIME type {@link MimeTypes#APPLICATION_CEA708}.
   *
   * @param isWideAspectRatio Whether the CEA-708 closed caption service is formatted for displays
   *     with 16:9 aspect ratio.
   * @return Initialization data for formats with MIME type {@link MimeTypes#APPLICATION_CEA708}.
   */
  public static List<byte[]> buildCea708InitializationData(boolean isWideAspectRatio) {
    return Collections.singletonList(isWideAspectRatio ? new byte[] {1} : new byte[] {0});
  }

  /**
   * Returns whether the CEA-708 closed caption service with the given initialization data is
   * formatted for displays with 16:9 aspect ratio.
   *
   * @param initializationData The initialization data to parse.
   * @return Whether the CEA-708 closed caption service is formatted for displays with 16:9 aspect
   *     ratio.
   */
  public static boolean parseCea708InitializationData(List<byte[]> initializationData) {
    return initializationData.size() == 1
        && initializationData.get(0).length == 1
        && initializationData.get(0)[0] == 1;
  }

  /**
   * Builds an RFC 6381 AVC codec string using the provided parameters.
   *
   * @param profileIdc The encoding profile.
   * @param constraintsFlagsAndReservedZero2Bits The constraint flags followed by the reserved zero
   *     2 bits, all contained in the least significant byte of the integer.
   * @param levelIdc The encoding level.
   * @return An RFC 6381 AVC codec string built using the provided parameters.
   */
  public static String buildAvcCodecString(
      int profileIdc, int constraintsFlagsAndReservedZero2Bits, int levelIdc) {
    return String.format(
        "avc1.%02X%02X%02X", profileIdc, constraintsFlagsAndReservedZero2Bits, levelIdc);
  }

  /** Builds an RFC 6381 HEVC codec string using the provided parameters. */
  public static String buildHevcCodecString(
      int generalProfileSpace,
      boolean generalTierFlag,
      int generalProfileIdc,
      int generalProfileCompatibilityFlags,
      int[] constraintBytes,
      int generalLevelIdc) {
    StringBuilder builder =
        new StringBuilder(
            Util.formatInvariant(
                "hvc1.%s%d.%X.%c%d",
                HEVC_GENERAL_PROFILE_SPACE_STRINGS[generalProfileSpace],
                generalProfileIdc,
                generalProfileCompatibilityFlags,
                generalTierFlag ? 'H' : 'L',
                generalLevelIdc));
    // Omit trailing zero bytes.
    int trailingZeroIndex = constraintBytes.length;
    while (trailingZeroIndex > 0 && constraintBytes[trailingZeroIndex - 1] == 0) {
      trailingZeroIndex--;
    }
    for (int i = 0; i < trailingZeroIndex; i++) {
      builder.append(String.format(".%02X", constraintBytes[i]));
    }
    return builder.toString();
  }

  /**
   * Constructs a NAL unit consisting of the NAL start code followed by the specified data.
   *
   * @param data An array containing the data that should follow the NAL start code.
   * @param offset The start offset into {@code data}.
   * @param length The number of bytes to copy from {@code data}
   * @return The constructed NAL unit.
   */
  public static byte[] buildNalUnit(byte[] data, int offset, int length) {
    byte[] nalUnit = new byte[length + NAL_START_CODE.length];
    System.arraycopy(NAL_START_CODE, 0, nalUnit, 0, NAL_START_CODE.length);
    System.arraycopy(data, offset, nalUnit, NAL_START_CODE.length, length);
    return nalUnit;
  }

  /**
   * Splits an array of NAL units.
   *
   * <p>If the input consists of NAL start code delimited units, then the returned array consists of
   * the split NAL units, each of which is still prefixed with the NAL start code. For any other
   * input, null is returned.
   *
   * @param data An array of data.
   * @return The individual NAL units, or null if the input did not consist of NAL start code
   *     delimited units.
   */
  @Nullable
  public static byte[][] splitNalUnits(byte[] data) {
    if (!isNalStartCode(data, 0)) {
      // data does not consist of NAL start code delimited units.
      return null;
    }
    List<Integer> starts = new ArrayList<>();
    int nalUnitIndex = 0;
    do {
      starts.add(nalUnitIndex);
      nalUnitIndex = findNalStartCode(data, nalUnitIndex + NAL_START_CODE.length);
    } while (nalUnitIndex != C.INDEX_UNSET);
    byte[][] split = new byte[starts.size()][];
    for (int i = 0; i < starts.size(); i++) {
      int startIndex = starts.get(i);
      int endIndex = i < starts.size() - 1 ? starts.get(i + 1) : data.length;
      byte[] nal = new byte[endIndex - startIndex];
      System.arraycopy(data, startIndex, nal, 0, nal.length);
      split[i] = nal;
    }
    return split;
  }

  /**
   * Finds the next occurrence of the NAL start code from a given index.
   *
   * @param data The data in which to search.
   * @param index The first index to test.
   * @return The index of the first byte of the found start code, or {@link C#INDEX_UNSET}.
   */
  private static int findNalStartCode(byte[] data, int index) {
    int endIndex = data.length - NAL_START_CODE.length;
    for (int i = index; i <= endIndex; i++) {
      if (isNalStartCode(data, i)) {
        return i;
      }
    }
    return C.INDEX_UNSET;
  }

  /**
   * Tests whether there exists a NAL start code at a given index.
   *
   * @param data The data.
   * @param index The index to test.
   * @return Whether there exists a start code that begins at {@code index}.
   */
  private static boolean isNalStartCode(byte[] data, int index) {
    if (data.length - index <= NAL_START_CODE.length) {
      return false;
    }
    for (int j = 0; j < NAL_START_CODE.length; j++) {
      if (data[index + j] != NAL_START_CODE[j]) {
        return false;
      }
    }
    return true;
  }

  private CodecSpecificDataUtil() {}
}