1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.camera.video;
18 
19 import android.view.Surface;
20 
21 import androidx.annotation.RestrictTo;
22 import androidx.annotation.RestrictTo.Scope;
23 import androidx.camera.core.CameraInfo;
24 import androidx.camera.core.SurfaceRequest;
25 import androidx.camera.core.impl.ConstantObservable;
26 import androidx.camera.core.impl.Observable;
27 import androidx.camera.core.impl.Timebase;
28 import androidx.core.util.Consumer;
29 
30 import org.jspecify.annotations.NonNull;
31 
32 import java.util.concurrent.Executor;
33 
34 /**
35  * A class that will produce video data from a {@link Surface}.
36  *
37  * <p>Implementations will provide a {@link Surface} to a video frame producer via the
38  * {@link SurfaceRequest} sent to {@link #onSurfaceRequested(SurfaceRequest)}.
39  *
40  * <p>The type of video data produced by a video output and API for saving or communicating that
41  * data is left to the implementation. An implementation commonly used for local video saving is
42  * {@link Recorder}. This interface is usually only needs to be implemented by applications for
43  * advanced use cases.
44  */
45 public interface VideoOutput {
46     /**
47      * A state which represents whether the video frame producer is producing frames to the
48      * provided {@link Surface}.
49      */
50     @RestrictTo(Scope.LIBRARY)
51     enum SourceState {
52         /** The video frame producer is active and is producing frames. */
53         ACTIVE_STREAMING,
54         /** The video frame producer is active but is not producing frames. */
55         ACTIVE_NON_STREAMING,
56         /** The video frame producer is inactive. */
57         INACTIVE
58     }
59 
60     /**
61      * Called when a new {@link Surface} has been requested by a video frame producer.
62      *
63      * <p>Users of this class should not call this method directly. It will be called by the
64      * video frame producer. Implementors of this class should be aware that this method is
65      * called when a video frame producer is ready to receive a surface that it can use to send
66      * video frames to the video output. The video frame producer may repeatedly request a
67      * surface more than once, but only the latest {@link SurfaceRequest} should be considered
68      * active. All previous surface requests will complete by sending a
69      * {@link androidx.camera.core.SurfaceRequest.Result} to the consumer passed to
70      * {@link SurfaceRequest#provideSurface(Surface, Executor, Consumer)}.
71      *
72      * <p>A request is considered active until it is
73      * {@linkplain SurfaceRequest#provideSurface(Surface, Executor, androidx.core.util.Consumer)
74      * fulfilled}, {@linkplain SurfaceRequest#willNotProvideSurface() marked as 'will not
75      * complete'}, or
76      * {@linkplain SurfaceRequest#addRequestCancellationListener(Executor, Runnable) cancelled
77      * by the video frame producer}. After one of these conditions occurs, a request is considered
78      * completed.
79      *
80      * <p>Once a request is successfully completed, it is guaranteed that if a new request is
81      * made, the {@link Surface} used to fulfill the previous request will be detached from the
82      * video frame producer and the {@code resultListener} provided in
83      * {@link SurfaceRequest#provideSurface(Surface, Executor, Consumer)}
84      * will be invoked with a {@link androidx.camera.core.SurfaceRequest.Result} containing
85      * {@link androidx.camera.core.SurfaceRequest.Result#RESULT_SURFACE_USED_SUCCESSFULLY}.
86      *
87      * @param request the request for a surface which contains the requirements of the
88      *                surface and methods for completing the request.
89      */
onSurfaceRequested(@onNull SurfaceRequest request)90     void onSurfaceRequested(@NonNull SurfaceRequest request);
91 
92     /**
93      * Called when a new {@link Surface} has been requested by a video frame producer.
94      *
95      * @param request the request for a surface which contains the requirements of the
96      *                surface and methods for completing the request.
97      * @param timebase the video source timebase.
98      * @param hasGlProcessing whether the video recording pipeline involves OpenGL processing.
99      */
100     @RestrictTo(Scope.LIBRARY)
onSurfaceRequested(@onNull SurfaceRequest request, @NonNull Timebase timebase, boolean hasGlProcessing)101     default void onSurfaceRequested(@NonNull SurfaceRequest request, @NonNull Timebase timebase,
102             boolean hasGlProcessing) {
103         onSurfaceRequested(request);
104     }
105 
106     /**
107      * Returns an observable {@link StreamInfo} which contains the information of the
108      * {@link VideoOutput}.
109      */
110     @RestrictTo(Scope.LIBRARY)
getStreamInfo()111     default @NonNull Observable<StreamInfo> getStreamInfo() {
112         return StreamInfo.ALWAYS_ACTIVE_OBSERVABLE;
113     }
114 
115     /**
116      * Returns an observable {@link MediaSpec} which contains hints about what kind of input the
117      * {@link VideoOutput} is expecting.
118      *
119      * <p>All values contained in the media specification are considered hints and may be ignored
120      * by the video frame producer. The {@link VideoOutput} should always respect the surface
121      * requirements given in the {@link SurfaceRequest} in
122      * {@link #onSurfaceRequested(SurfaceRequest)}, or the video frame producer may not be able
123      * to produce frames.
124      *
125      * <p>Implementations should be careful about updating the {@link MediaSpec} too often, as
126      * changes may not come for free and may require the video frame producer to re-initialize,
127      * which could cause a new {@link SurfaceRequest} to be sent to
128      * {@link #onSurfaceRequested(SurfaceRequest)}.
129      */
130     @RestrictTo(Scope.LIBRARY)
getMediaSpec()131     default @NonNull Observable<MediaSpec> getMediaSpec() {
132         return ConstantObservable.withValue(null);
133     }
134 
135     /**
136      * Returns an observable to know if the streaming from a video frame producer is required.
137      *
138      * <p> This should be true for cases like when user is starting a video recording or streaming
139      * and false when user has decided to stop the recording/streaming. The video frame producer
140      * will use this information to do know whether it's now safe to do operations which may disrupt
141      * video quality/consistency (e.g. AE precapture).
142      */
143     @RestrictTo(Scope.LIBRARY)
isSourceStreamRequired()144     default @NonNull Observable<Boolean> isSourceStreamRequired() {
145         return ConstantObservable.withValue(false);
146     }
147 
148     /**
149      * Called when the state of the video frame producer is changed.
150      */
151     @RestrictTo(Scope.LIBRARY)
onSourceStateChanged(@onNull SourceState sourceState)152     default void onSourceStateChanged(@NonNull SourceState sourceState) {
153 
154     }
155 
156     // TODO(b/278170231): wraps getMediaSpec and getMediaCapabilities for increased scalability and
157     //  easier retrieval of initial specs and capabilities.
158     /**
159      * Returns the {@link VideoCapabilities} information of the {@link VideoOutput}.
160      */
161     @RestrictTo(Scope.LIBRARY)
getMediaCapabilities(@onNull CameraInfo cameraInfo, int sessionType)162     default @NonNull VideoCapabilities getMediaCapabilities(@NonNull CameraInfo cameraInfo,
163             int sessionType) {
164         return VideoCapabilities.EMPTY;
165     }
166 }
167