{"record":{"id":"e99cf5bad8d5011e","repo":"google/ExoPlayer","slug":"invalid-header-missing-stream-map","errorCode":null,"errorMessage":"Invalid header, missing stream map","messagePattern":"Invalid header, missing stream map","errorType":"exception","errorClass":"OpusDecoderException","httpStatus":null,"severity":"error","filePath":"extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java","lineNumber":127,"sourceCode":"    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\");\n      }\n      // Read the channel mapping.\n      numStreams = headerBytes[19] & 0xFF;\n      numCoupled = headerBytes[20] & 0xFF;\n      System.arraycopy(headerBytes, 21, streamMap, 0, channelCount);\n    }\n    nativeDecoderContext =\n        opusInit(SAMPLE_RATE, channelCount, numStreams, numCoupled, gain, streamMap);\n    if (nativeDecoderContext == 0) {\n      throw new OpusDecoderException(\"Failed to initialize decoder\");","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java#L109-L145","documentation":"The Opus header declares channel mapping family 0 (byte 18 == 0), which supports at most stereo via the default layout, but the channel count read from the header is > 2. Family 0 headers carry no stream map, so the decoder cannot map more than 2 channels and rejects the header as internally inconsistent.","triggerScenarios":"initializationData[0][18] == 0 while the channel count byte (offset 9) is 3-8. Produced by malformed encoders or hand-authored headers that combine a multichannel count with mapping family 0.","commonSituations":"Files produced by broken transcoders or hand-edited headers; constructing Opus initializationData manually and forgetting to emit the full channel mapping table for multichannel audio.","solutions":["Re-encode/remux the file so multichannel Opus uses channel mapping family 1 (byte 18 = 1) with a proper stream map of 21 + channelCount bytes.","If you build the header yourself, either cap channels at 2 with family 0, or emit family >= 1 plus numStreams, numCoupled and the per-channel mapping table.","Reject the track at track-selection time if the header is inconsistent (family 0 and channels > 2)."],"exampleFix":"// before (hand-built header)\nheader[9] = 6;   // 6 channels\nheader[18] = 0;  // family 0 -> decoder throws\n\n// after\nheader[9] = 6;\nheader[18] = 1;  // family 1\nheader[19] = 4;  // numStreams\nheader[20] = 2;  // numCoupled\n// append 6 mapping bytes at offset 21...","handlingStrategy":"validation","validationCode":"int channels = h[9] & 0xFF;\nint family = h[18] & 0xFF;\nif (family == 0 && channels > 2) { /* inconsistent header: reject track */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When authoring headers, pair multichannel counts with mapping family >= 1.","Prefer files produced by libopus/ffmpeg rather than custom muxers.","Add header-consistency checks in ingest pipelines."],"tags":["opus","audio","channel-mapping","decoder","exoplayer-extension"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}