{"record":{"id":"d37f2d92012e0e63","repo":"google/ExoPlayer","slug":"invalid-output-mode","errorCode":null,"errorMessage":"Invalid output mode.","messagePattern":"Invalid output mode\\.","errorType":"validation","errorClass":"Gav1DecoderException","httpStatus":null,"severity":"error","filePath":"extensions/av1/src/main/java/com/google/android/exoplayer2/ext/av1/Gav1Decoder.java","lineNumber":177,"sourceCode":"   * @param outputMode The output mode.\n   */\n  public void setOutputMode(@C.VideoOutputMode int outputMode) {\n    this.outputMode = outputMode;\n  }\n\n  /**\n   * Renders output buffer to the given surface. Must only be called when in {@link\n   * C#VIDEO_OUTPUT_MODE_SURFACE_YUV} mode.\n   *\n   * @param outputBuffer Output buffer.\n   * @param surface Output surface.\n   * @throws Gav1DecoderException Thrown if called with invalid output mode or frame rendering\n   *     fails.\n   */\n  public void renderToSurface(VideoDecoderOutputBuffer outputBuffer, Surface surface)\n      throws Gav1DecoderException {\n    if (outputBuffer.mode != C.VIDEO_OUTPUT_MODE_SURFACE_YUV) {\n      throw new Gav1DecoderException(\"Invalid output mode.\");\n    }\n    if (gav1RenderFrame(gav1DecoderContext, surface, outputBuffer) == GAV1_ERROR) {\n      throw new Gav1DecoderException(\n          \"Buffer render error: \" + gav1GetErrorMessage(gav1DecoderContext));\n    }\n  }\n\n  /**\n   * Initializes a libgav1 decoder.\n   *\n   * @param threads Number of threads to be used by a libgav1 decoder.\n   * @return The address of the decoder context or {@link #GAV1_ERROR} if there was an error.\n   */\n  private native long gav1Init(int threads);\n\n  /**\n   * Deallocates the decoder context.\n   *","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/extensions/av1/src/main/java/com/google/android/exoplayer2/ext/av1/Gav1Decoder.java#L159-L195","documentation":"Gav1DecoderException thrown by Gav1Decoder.renderToSurface when outputBuffer.mode is not C.VIDEO_OUTPUT_MODE_SURFACE_YUV. renderToSurface is only valid when the decoder was configured to render YUV frames directly onto a surface; buffers produced in buffer-output mode (or default mode 0) cannot be pushed to the surface path.","triggerScenarios":"Calling renderToSurface without first calling setOutputMode(C.VIDEO_OUTPUT_MODE_SURFACE_YUV) on the decoder; calling it while the renderer operates in decoder-output-buffer mode; renderer called setDecoderOutputMode before the decoder instance existed, so the mode was never applied.","commonSituations":"Custom renderer code that renders to a SurfaceView-backed surface but never sets the output mode; switching between output modes mid-playback; using Libgav1VideoRenderer with a surface while another component forced buffer mode for screenshot/processing.","solutions":["Ensure setOutputMode(C.VIDEO_OUTPUT_MODE_SURFACE_YUV) is invoked on the decoder before any renderToSurface call (Libgav1VideoRenderer.setDecoderOutputMode does this, but only when decoder != null)","Set the decoder output mode immediately after constructing the decoder, before processing any buffers","If you need raw frames, use the buffer path (decodeToOutputBuffer) instead of the surface path"],"exampleFix":"// before\ndecoder.renderToSurface(outputBuffer, surface); // throws if mode never set\n\n// after\ndecoder.setOutputMode(C.VIDEO_OUTPUT_MODE_SURFACE_YUV);\ndecoder.renderToSurface(outputBuffer, surface);","handlingStrategy":"validation","validationCode":"if (outputBuffer.mode == C.VIDEO_OUTPUT_MODE_SURFACE_YUV) {\n  decoder.renderToSurface(outputBuffer, surface);\n} else {\n  // wrong path: consume the buffer via decodeToOutputBuffer() instead\n  outputBuffer.release();\n}","typeGuard":null,"tryCatchPattern":"try {\n  decoder.renderToSurface(outputBuffer, surface);\n} catch (Gav1DecoderException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"Invalid output mode\")) {\n    decoder.setOutputMode(C.VIDEO_OUTPUT_MODE_SURFACE_YUV); // correct state and retry once\n    decoder.renderToSurface(outputBuffer, surface);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Set the output mode immediately after decoder construction, before any buffers flow","Treat renderToSurface as valid only in SURFACE_YUV mode per its javadoc","Centralize mode selection in one place so the renderer and decoder cannot disagree"],"tags":["android","av1","video-output","surface","api-misuse"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}