{"record":{"id":"34936149f4be8b4c","repo":"google/ExoPlayer","slug":"invalid-channel-count-channelcount","errorCode":null,"errorMessage":"Invalid channel count: ${channelCount}","messagePattern":"Invalid channel count: (.+?)","errorType":"exception","errorClass":"OpusDecoderException","httpStatus":null,"severity":"error","filePath":"extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java","lineNumber":117,"sourceCode":"    int initializationDataSize = initializationData.size();\n    if (initializationDataSize != 1 && initializationDataSize != 3) {\n      throw new OpusDecoderException(\"Invalid initialization data size\");\n    }\n    if (initializationDataSize == 3\n        && (initializationData.get(1).length != 8 || initializationData.get(2).length != 8)) {\n      throw new OpusDecoderException(\"Invalid pre-skip or seek pre-roll\");\n    }\n    preSkipSamples = getPreSkipSamples(initializationData);\n    seekPreRollSamples = getSeekPreRollSamples(initializationData);\n    skipSamples = preSkipSamples;\n\n    byte[] headerBytes = initializationData.get(0);\n    if (headerBytes.length < 19) {\n      throw new OpusDecoderException(\"Invalid header length\");\n    }\n    channelCount = getChannelCount(headerBytes);\n    if (channelCount > 8) {\n      throw new OpusDecoderException(\"Invalid channel count: \" + channelCount);\n    }\n    int gain = readSignedLittleEndian16(headerBytes, 16);\n\n    byte[] streamMap = new byte[8];\n    int numStreams;\n    int numCoupled;\n    if (headerBytes[18] == 0) { // Channel mapping\n      // If there is no channel mapping, use the defaults.\n      if (channelCount > 2) { // Maximum channel count with default layout.\n        throw new OpusDecoderException(\"Invalid header, missing stream map\");\n      }\n      numStreams = 1;\n      numCoupled = (channelCount == 2) ? 1 : 0;\n      streamMap[0] = 0;\n      streamMap[1] = 1;\n    } else {\n      if (headerBytes.length < 21 + channelCount) {\n        throw new OpusDecoderException(\"Invalid header length\");","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java#L99-L135","documentation":"The Opus identification header declares a channel count greater than 8, which the ExoPlayer Opus extension refuses to initialize. libopus multistream is capped here at 8 channels; anything higher indicates a corrupt or non-Opus header byte being read at offset 9.","triggerScenarios":"getChannelCount(headerBytes) reads the unsigned byte at offset 9 of initializationData[0] and it is > 8. Caused by files whose header is actually not an Opus ID header (wrong initializationData), corrupted headers, or hand-built initializationData with the wrong layout.","commonSituations":"Misrouted audio track (e.g. a different codec's CodecPrivate passed as Opus header); corrupted downloads or malformed transcodes producing a garbage channel byte; incorrect manual Format construction in IMA/media-source code.","solutions":["Inspect initializationData[0]: it must start with 'OpusHead' and byte 9 must be 1-8; fix the producer of that header if not.","Confirm the track's MIME type is audio/opus so non-Opus streams never reach OpusDecoder.","Re-transcode or re-mux the source file if the header in the container itself is corrupt.","Exclude the Opus extension renderer via RenderersFactory filtering if you only meant to play standard MediaCodec audio."],"exampleFix":"// before\n// format passed straight from extractor to Opus renderer, header byte 9 = 200\n\n// after\nbyte[] h = format.initializationData.get(0);\nint channels = h[9] & 0xFF;\nif (channels < 1 || channels > 8) {\n  // skip / deselect this track instead of letting the decoder throw\n  selectionParameters.overrideExclude(audioTrackGroup); \n}","handlingStrategy":"validation","validationCode":"int channels = h[9] & 0xFF;\nif (channels < 1 || channels > 8) { /* reject track before renderer init */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check the channel byte (offset 9) of the Opus ID header is 1..8 before playback.","Validate that initializationData[0] really is an Opus header via the 'OpusHead' magic.","Re-mux suspicious files with ffmpeg to normalize headers."],"tags":["opus","audio","channels","decoder","exoplayer-extension"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}