/* * Copyright 2021 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 * * http://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.camera.video; import android.view.Surface; import androidx.annotation.RestrictTo; import androidx.annotation.RestrictTo.Scope; import androidx.camera.core.CameraInfo; import androidx.camera.core.SurfaceRequest; import androidx.camera.core.impl.ConstantObservable; import androidx.camera.core.impl.Observable; import androidx.camera.core.impl.Timebase; import androidx.core.util.Consumer; import org.jspecify.annotations.NonNull; import java.util.concurrent.Executor; /** * A class that will produce video data from a {@link Surface}. * *

Implementations will provide a {@link Surface} to a video frame producer via the * {@link SurfaceRequest} sent to {@link #onSurfaceRequested(SurfaceRequest)}. * *

The type of video data produced by a video output and API for saving or communicating that * data is left to the implementation. An implementation commonly used for local video saving is * {@link Recorder}. This interface is usually only needs to be implemented by applications for * advanced use cases. */ public interface VideoOutput { /** * A state which represents whether the video frame producer is producing frames to the * provided {@link Surface}. */ @RestrictTo(Scope.LIBRARY) enum SourceState { /** The video frame producer is active and is producing frames. */ ACTIVE_STREAMING, /** The video frame producer is active but is not producing frames. */ ACTIVE_NON_STREAMING, /** The video frame producer is inactive. */ INACTIVE } /** * Called when a new {@link Surface} has been requested by a video frame producer. * *

Users of this class should not call this method directly. It will be called by the * video frame producer. Implementors of this class should be aware that this method is * called when a video frame producer is ready to receive a surface that it can use to send * video frames to the video output. The video frame producer may repeatedly request a * surface more than once, but only the latest {@link SurfaceRequest} should be considered * active. All previous surface requests will complete by sending a * {@link androidx.camera.core.SurfaceRequest.Result} to the consumer passed to * {@link SurfaceRequest#provideSurface(Surface, Executor, Consumer)}. * *

A request is considered active until it is * {@linkplain SurfaceRequest#provideSurface(Surface, Executor, androidx.core.util.Consumer) * fulfilled}, {@linkplain SurfaceRequest#willNotProvideSurface() marked as 'will not * complete'}, or * {@linkplain SurfaceRequest#addRequestCancellationListener(Executor, Runnable) cancelled * by the video frame producer}. After one of these conditions occurs, a request is considered * completed. * *

Once a request is successfully completed, it is guaranteed that if a new request is * made, the {@link Surface} used to fulfill the previous request will be detached from the * video frame producer and the {@code resultListener} provided in * {@link SurfaceRequest#provideSurface(Surface, Executor, Consumer)} * will be invoked with a {@link androidx.camera.core.SurfaceRequest.Result} containing * {@link androidx.camera.core.SurfaceRequest.Result#RESULT_SURFACE_USED_SUCCESSFULLY}. * * @param request the request for a surface which contains the requirements of the * surface and methods for completing the request. */ void onSurfaceRequested(@NonNull SurfaceRequest request); /** * Called when a new {@link Surface} has been requested by a video frame producer. * * @param request the request for a surface which contains the requirements of the * surface and methods for completing the request. * @param timebase the video source timebase. * @param hasGlProcessing whether the video recording pipeline involves OpenGL processing. */ @RestrictTo(Scope.LIBRARY) default void onSurfaceRequested(@NonNull SurfaceRequest request, @NonNull Timebase timebase, boolean hasGlProcessing) { onSurfaceRequested(request); } /** * Returns an observable {@link StreamInfo} which contains the information of the * {@link VideoOutput}. */ @RestrictTo(Scope.LIBRARY) default @NonNull Observable getStreamInfo() { return StreamInfo.ALWAYS_ACTIVE_OBSERVABLE; } /** * Returns an observable {@link MediaSpec} which contains hints about what kind of input the * {@link VideoOutput} is expecting. * *

All values contained in the media specification are considered hints and may be ignored * by the video frame producer. The {@link VideoOutput} should always respect the surface * requirements given in the {@link SurfaceRequest} in * {@link #onSurfaceRequested(SurfaceRequest)}, or the video frame producer may not be able * to produce frames. * *

Implementations should be careful about updating the {@link MediaSpec} too often, as * changes may not come for free and may require the video frame producer to re-initialize, * which could cause a new {@link SurfaceRequest} to be sent to * {@link #onSurfaceRequested(SurfaceRequest)}. */ @RestrictTo(Scope.LIBRARY) default @NonNull Observable getMediaSpec() { return ConstantObservable.withValue(null); } /** * Returns an observable to know if the streaming from a video frame producer is required. * *

This should be true for cases like when user is starting a video recording or streaming * and false when user has decided to stop the recording/streaming. The video frame producer * will use this information to do know whether it's now safe to do operations which may disrupt * video quality/consistency (e.g. AE precapture). */ @RestrictTo(Scope.LIBRARY) default @NonNull Observable isSourceStreamRequired() { return ConstantObservable.withValue(false); } /** * Called when the state of the video frame producer is changed. */ @RestrictTo(Scope.LIBRARY) default void onSourceStateChanged(@NonNull SourceState sourceState) { } // TODO(b/278170231): wraps getMediaSpec and getMediaCapabilities for increased scalability and // easier retrieval of initial specs and capabilities. /** * Returns the {@link VideoCapabilities} information of the {@link VideoOutput}. */ @RestrictTo(Scope.LIBRARY) default @NonNull VideoCapabilities getMediaCapabilities(@NonNull CameraInfo cameraInfo, int sessionType) { return VideoCapabilities.EMPTY; } }