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.camera.core.SurfaceRequest;
23 import androidx.camera.core.impl.ConstantObservable;
24 import androidx.camera.core.impl.Observable;
25 
26 import com.google.auto.value.AutoValue;
27 
28 import org.jspecify.annotations.NonNull;
29 import org.jspecify.annotations.Nullable;
30 
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.HashSet;
34 import java.util.Set;
35 
36 /**
37  * A class that contains the information of an video output stream.
38  *
39  */
40 @RestrictTo(RestrictTo.Scope.LIBRARY)
41 @AutoValue
42 public abstract class StreamInfo {
43 
44     /** The stream hasn't been setup. */
45     static final int STREAM_ID_ANY = 0;
46 
47     /** The stream setup fails. */
48     static final int STREAM_ID_ERROR = -1;
49 
50     static final StreamInfo STREAM_INFO_ANY_INACTIVE = StreamInfo.of(STREAM_ID_ANY,
51             StreamState.INACTIVE);
52 
53     static final Set<Integer> NON_SURFACE_STREAM_ID = Collections.unmodifiableSet(
54             new HashSet<>(Arrays.asList(STREAM_ID_ANY, STREAM_ID_ERROR)));
55 
56     static final Observable<StreamInfo> ALWAYS_ACTIVE_OBSERVABLE =
57             ConstantObservable.withValue(StreamInfo.of(STREAM_ID_ANY, StreamState.ACTIVE));
58     /**
59      * A state which represents whether the video output is ready for frame streaming.
60      *
61      * <p>This is used in the observable returned by {@link #getStreamState()} to inform
62      * producers that they can start or stop producing frames.
63      */
64     @RestrictTo(RestrictTo.Scope.LIBRARY)
65     enum StreamState {
66         /** The video output is active and ready to receive frames. */
67         ACTIVE,
68         /** The video output is inactive and any frames sent will be discarded. */
69         INACTIVE;
70     }
71 
StreamInfo()72     StreamInfo() {
73 
74     }
75 
of(int id, @NonNull StreamState streamState)76     static @NonNull StreamInfo of(int id, @NonNull StreamState streamState) {
77         return new AutoValue_StreamInfo(id, streamState, null);
78     }
79 
of(int id, @NonNull StreamState streamState, SurfaceRequest.@Nullable TransformationInfo inProgressTransformationInfo)80     static @NonNull StreamInfo of(int id, @NonNull StreamState streamState,
81             SurfaceRequest.@Nullable TransformationInfo inProgressTransformationInfo) {
82         return new AutoValue_StreamInfo(id, streamState, inProgressTransformationInfo);
83     }
84 
85     /**
86      * Gets the ID of the video output stream.
87      *
88      * <p>The ID will be changed if the {@link Surface} provided to
89      * {@link VideoOutput#onSurfaceRequested} becomes invalid by the {@link VideoOutput}. A new
90      * {@link SurfaceRequest} has to be issued in order to obtain a new {@link Surface} to
91      * continue drawing frames to the {@link VideoOutput}.
92      *
93      * <p>The ID will be {@link #STREAM_ID_ANY} if the stream hasn't been setup and the ID will be
94      * {@link #STREAM_ID_ERROR} if the stream setup fails.
95      */
getId()96     public abstract int getId();
97 
98     /**
99      * Gets the stream state which can be used to determine if the video output is ready for
100      * streaming.
101      *
102      * <p>When the StreamState is ACTIVE, the {@link Surface} provided to
103      * {@link VideoOutput#onSurfaceRequested} should be ready to consume frames.
104      *
105      * <p>When the StreamState is INACTIVE, any frames drawn to the {@link Surface} may be
106      * discarded.
107      *
108      * <p>This can be used by video producers to determine when frames should be drawn to the
109      * {@link Surface} to ensure they are not doing excess work.
110      *
111      * <p>Implementers of the VideoOutput interface should consider overriding this method
112      * as a performance improvement. The default implementation returns an {@link Observable}
113      * which is always {@link StreamState#ACTIVE}.
114      */
getStreamState()115     public abstract @NonNull StreamState getStreamState();
116 
117     /**
118      * Returns the existing transformation information if there's an in-processing surface.
119      *
120      * @return the in-progress transformation information, or {@code null} if there's no
121      * in-processing surface.
122      */
getInProgressTransformationInfo()123     public abstract SurfaceRequest.@Nullable TransformationInfo getInProgressTransformationInfo();
124 }
125