VideoGraph.java

/*
 * Copyright 2023 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
 *
 *      https://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;

import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi;

/** Represents a graph for processing decoded video frames. */
@UnstableApi
public interface VideoGraph {

  /** Listener for video frame processing events. */
  @UnstableApi
  interface Listener {
    /**
     * Called when the output size changes.
     *
     * @param width The new output width in pixels.
     * @param height The new output width in pixels.
     */
    void onOutputSizeChanged(int width, int height);

    /**
     * Called when an output frame with the given {@code presentationTimeUs} becomes available for
     * rendering.
     *
     * @param presentationTimeUs The presentation time of the frame, in microseconds.
     */
    void onOutputFrameAvailableForRendering(long presentationTimeUs);

    /**
     * Called after the {@link VideoGraph} has rendered its final output frame.
     *
     * @param finalFramePresentationTimeUs The timestamp of the last output frame, in microseconds.
     */
    void onEnded(long finalFramePresentationTimeUs);

    /**
     * Called when an exception occurs during video frame processing.
     *
     * <p>If this is called, the calling {@link VideoGraph} must immediately be {@linkplain
     * #release() released}.
     */
    void onError(VideoFrameProcessingException exception);
  }

  /**
   * Initialize the {@code VideoGraph}.
   *
   * <p>This method must be called before calling other methods.
   *
   * <p>If the method throws, the caller must call {@link #release}.
   */
  void initialize() throws VideoFrameProcessingException;

  /**
   * Registers a new input to the {@code VideoGraph}.
   *
   * <p>A underlying processing {@link VideoFrameProcessor} is created every time this method is
   * called.
   *
   * <p>If the method throws, the caller must call {@link #release}.
   *
   * @return The id of the registered input, which can be used to get the underlying {@link
   *     VideoFrameProcessor} via {@link #getProcessor(int)}.
   */
  int registerInput() throws VideoFrameProcessingException;

  /**
   * Returns the {@link VideoFrameProcessor} that handles the processing for an input registered via
   * {@link #registerInput()}. If the {@code inputId} is not {@linkplain #registerInput()
   * registered} before, this method will throw an {@link IllegalStateException}.
   */
  VideoFrameProcessor getProcessor(int inputId);

  /**
   * Sets the output surface and supporting information.
   *
   * <p>The new output {@link SurfaceInfo} is applied from the next output frame rendered onwards.
   * If the output {@link SurfaceInfo} is {@code null}, the {@code VideoGraph} will stop rendering
   * pending frames and resume rendering once a non-null {@link SurfaceInfo} is set.
   *
   * <p>If the dimensions given in {@link SurfaceInfo} do not match the {@linkplain
   * Listener#onOutputSizeChanged(int,int) output size after applying the final effect} the frames
   * are resized before rendering to the surface and letter/pillar-boxing is applied.
   *
   * <p>The caller is responsible for tracking the lifecycle of the {@link SurfaceInfo#surface}
   * including calling this method with a new surface if it is destroyed. When this method returns,
   * the previous output surface is no longer being used and can safely be released by the caller.
   */
  void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo);

  /**
   * Returns whether the {@code VideoGraph} has produced a frame with zero presentation timestamp.
   */
  boolean hasProducedFrameWithTimestampZero();

  /**
   * Releases the associated resources.
   *
   * <p>This {@code VideoGraph} instance must not be used after this method is called.
   */
  void release();
}