DrKLO/Telegram · error · OpusDecoderException

Invalid initialization data size

Error message

Invalid initialization data size

What it means

The OpusDecoder constructor requires the codec initializationData list to hold exactly 1 element (just the Opus identification header) or exactly 3 elements (header plus two 8-byte buffers for codec delay and seek pre-roll, the layout produced by ExoPlayer's Opus extractor). Any other size is treated as malformed codec private data and rejected before any header bytes are read.

Source

Thrown at TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:93

  public OpusDecoder(
      int numInputBuffers,
      int numOutputBuffers,
      int initialInputBufferSize,
      List<byte[]> initializationData,
      @Nullable CryptoConfig cryptoConfig,
      boolean outputFloat)
      throws OpusDecoderException {
    super(new DecoderInputBuffer[numInputBuffers], new SimpleDecoderOutputBuffer[numOutputBuffers]);
    if (!OpusLibrary.isAvailable()) {
      throw new OpusDecoderException("Failed to load decoder native libraries");
    }
    this.cryptoConfig = cryptoConfig;
    if (cryptoConfig != null && !OpusLibrary.opusIsSecureDecodeSupported()) {
      throw new OpusDecoderException("Opus decoder does not support secure decode");
    }
    int initializationDataSize = initializationData.size();
    if (initializationDataSize != 1 && initializationDataSize != 3) {
      throw new OpusDecoderException("Invalid initialization data size");
    }
    if (initializationDataSize == 3
        && (initializationData.get(1).length != 8 || initializationData.get(2).length != 8)) {
      throw new OpusDecoderException("Invalid pre-skip or seek pre-roll");
    }
    preSkipSamples = getPreSkipSamples(initializationData);
    seekPreRollSamples = getSeekPreRollSamples(initializationData);
    skipSamples = preSkipSamples;

    byte[] headerBytes = initializationData.get(0);
    if (headerBytes.length < 19) {
      throw new OpusDecoderException("Invalid header length");
    }
    channelCount = getChannelCount(headerBytes);
    if (channelCount > 8) {
      throw new OpusDecoderException("Invalid channel count: " + channelCount);
    }
    int gain = readSignedLittleEndian16(headerBytes, 16);

View on GitHub (pinned to 45ab8f4308)

Solutions

  1. Let ExoPlayer's built-in Opus extractor (Ogg/Opus or Matroska/Opus) populate initializationData rather than building the list by hand.
  2. Ensure initializationData is exactly Collections.singletonList(header) or [header, codecDelay(8 bytes), seekPreRoll(8 bytes)].
  3. Validate the source is a real Opus stream before routing it to LibopusAudioRenderer.

Example fix

// before
List<byte[]> init = new ArrayList<>();
init.add(header);
init.add(codecDelayShort); // wrong size -> forces 2-element list
new OpusDecoder(..., init, ...);

// after - either 1 header, or header + two 8-byte longs
List<byte[]> init = Collections.singletonList(header);
// or: Arrays.asList(header, longToBytes(codecDelayNs), longToBytes(seekPreRollNs));
new OpusDecoder(..., init, ...);
Defensive patterns

Strategy: validation

Validate before calling

List<byte[]> init = format.initializationData;
if (init == null || (init.size() != 1 && init.size() != 3)) {
  throw new IllegalArgumentException(
      "Opus initializationData must have 1 or 3 buffers, got " + (init == null ? 0 : init.size()));
}
new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, initSize, init, cryptoConfig, outputFloat);

Try / catch

try {
  new OpusDecoder(..., format.initializationData, cryptoConfig, outputFloat);
} catch (OpusDecoderException e) {
  if (e.getMessage().startsWith("Invalid initialization data size")) {
    // mark format unsupported / re-extract
  } else { throw e; }
}

Prevention

When it happens

Trigger: Constructing OpusDecoder with a Format whose initializationData was populated with the wrong number of buffers - a hand-built Format, a buggy custom extractor, or a file that is not genuinely Opus being fed to the Opus renderer.

Common situations: Unit tests that build a Format manually and forget the extra buffers; a demuxer that emits 2 or 4 buffers; media mislabeled as audio/opus; partial container corruption that makes the extractor emit no header buffer.

Related errors


AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14). Data as JSON: /api/errors/3f8313c1e4ac700a. Report an issue: GitHub.