• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package com.google.android.exoplayer2.ext.av1;
17 
18 import android.view.Surface;
19 import androidx.annotation.Nullable;
20 import com.google.android.exoplayer2.C;
21 import com.google.android.exoplayer2.decoder.SimpleDecoder;
22 import com.google.android.exoplayer2.util.Util;
23 import com.google.android.exoplayer2.video.VideoDecoderInputBuffer;
24 import com.google.android.exoplayer2.video.VideoDecoderOutputBuffer;
25 import java.nio.ByteBuffer;
26 
27 /** Gav1 decoder. */
28 /* package */ final class Gav1Decoder
29     extends SimpleDecoder<VideoDecoderInputBuffer, VideoDecoderOutputBuffer, Gav1DecoderException> {
30 
31   // LINT.IfChange
32   private static final int GAV1_ERROR = 0;
33   private static final int GAV1_OK = 1;
34   private static final int GAV1_DECODE_ONLY = 2;
35   // LINT.ThenChange(../../../../../../../jni/gav1_jni.cc)
36 
37   private final long gav1DecoderContext;
38 
39   @C.VideoOutputMode private volatile int outputMode;
40 
41   /**
42    * Creates a Gav1Decoder.
43    *
44    * @param numInputBuffers Number of input buffers.
45    * @param numOutputBuffers Number of output buffers.
46    * @param initialInputBufferSize The initial size of each input buffer, in bytes.
47    * @param threads Number of threads libgav1 will use to decode.
48    * @throws Gav1DecoderException Thrown if an exception occurs when initializing the decoder.
49    */
Gav1Decoder( int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, int threads)50   public Gav1Decoder(
51       int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, int threads)
52       throws Gav1DecoderException {
53     super(
54         new VideoDecoderInputBuffer[numInputBuffers],
55         new VideoDecoderOutputBuffer[numOutputBuffers]);
56     if (!Gav1Library.isAvailable()) {
57       throw new Gav1DecoderException("Failed to load decoder native library.");
58     }
59     gav1DecoderContext = gav1Init(threads);
60     if (gav1DecoderContext == GAV1_ERROR || gav1CheckError(gav1DecoderContext) == GAV1_ERROR) {
61       throw new Gav1DecoderException(
62           "Failed to initialize decoder. Error: " + gav1GetErrorMessage(gav1DecoderContext));
63     }
64     setInitialInputBufferSize(initialInputBufferSize);
65   }
66 
67   @Override
getName()68   public String getName() {
69     return "libgav1";
70   }
71 
72   /**
73    * Sets the output mode for frames rendered by the decoder.
74    *
75    * @param outputMode The output mode.
76    */
setOutputMode(@.VideoOutputMode int outputMode)77   public void setOutputMode(@C.VideoOutputMode int outputMode) {
78     this.outputMode = outputMode;
79   }
80 
81   @Override
createInputBuffer()82   protected VideoDecoderInputBuffer createInputBuffer() {
83     return new VideoDecoderInputBuffer();
84   }
85 
86   @Override
createOutputBuffer()87   protected VideoDecoderOutputBuffer createOutputBuffer() {
88     return new VideoDecoderOutputBuffer(this::releaseOutputBuffer);
89   }
90 
91   @Override
92   @Nullable
decode( VideoDecoderInputBuffer inputBuffer, VideoDecoderOutputBuffer outputBuffer, boolean reset)93   protected Gav1DecoderException decode(
94       VideoDecoderInputBuffer inputBuffer, VideoDecoderOutputBuffer outputBuffer, boolean reset) {
95     ByteBuffer inputData = Util.castNonNull(inputBuffer.data);
96     int inputSize = inputData.limit();
97     if (gav1Decode(gav1DecoderContext, inputData, inputSize) == GAV1_ERROR) {
98       return new Gav1DecoderException(
99           "gav1Decode error: " + gav1GetErrorMessage(gav1DecoderContext));
100     }
101 
102     boolean decodeOnly = inputBuffer.isDecodeOnly();
103     if (!decodeOnly) {
104       outputBuffer.init(inputBuffer.timeUs, outputMode, /* supplementalData= */ null);
105     }
106     // We need to dequeue the decoded frame from the decoder even when the input data is
107     // decode-only.
108     int getFrameResult = gav1GetFrame(gav1DecoderContext, outputBuffer, decodeOnly);
109     if (getFrameResult == GAV1_ERROR) {
110       return new Gav1DecoderException(
111           "gav1GetFrame error: " + gav1GetErrorMessage(gav1DecoderContext));
112     }
113     if (getFrameResult == GAV1_DECODE_ONLY) {
114       outputBuffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY);
115     }
116     if (!decodeOnly) {
117       outputBuffer.colorInfo = inputBuffer.colorInfo;
118     }
119 
120     return null;
121   }
122 
123   @Override
createUnexpectedDecodeException(Throwable error)124   protected Gav1DecoderException createUnexpectedDecodeException(Throwable error) {
125     return new Gav1DecoderException("Unexpected decode error", error);
126   }
127 
128   @Override
release()129   public void release() {
130     super.release();
131     gav1Close(gav1DecoderContext);
132   }
133 
134   @Override
releaseOutputBuffer(VideoDecoderOutputBuffer buffer)135   protected void releaseOutputBuffer(VideoDecoderOutputBuffer buffer) {
136     // Decode only frames do not acquire a reference on the internal decoder buffer and thus do not
137     // require a call to gav1ReleaseFrame.
138     if (buffer.mode == C.VIDEO_OUTPUT_MODE_SURFACE_YUV && !buffer.isDecodeOnly()) {
139       gav1ReleaseFrame(gav1DecoderContext, buffer);
140     }
141     super.releaseOutputBuffer(buffer);
142   }
143 
144   /**
145    * Renders output buffer to the given surface. Must only be called when in {@link
146    * C#VIDEO_OUTPUT_MODE_SURFACE_YUV} mode.
147    *
148    * @param outputBuffer Output buffer.
149    * @param surface Output surface.
150    * @throws Gav1DecoderException Thrown if called with invalid output mode or frame rendering
151    *     fails.
152    */
renderToSurface(VideoDecoderOutputBuffer outputBuffer, Surface surface)153   public void renderToSurface(VideoDecoderOutputBuffer outputBuffer, Surface surface)
154       throws Gav1DecoderException {
155     if (outputBuffer.mode != C.VIDEO_OUTPUT_MODE_SURFACE_YUV) {
156       throw new Gav1DecoderException("Invalid output mode.");
157     }
158     if (gav1RenderFrame(gav1DecoderContext, surface, outputBuffer) == GAV1_ERROR) {
159       throw new Gav1DecoderException(
160           "Buffer render error: " + gav1GetErrorMessage(gav1DecoderContext));
161     }
162   }
163 
164   /**
165    * Initializes a libgav1 decoder.
166    *
167    * @param threads Number of threads to be used by a libgav1 decoder.
168    * @return The address of the decoder context or {@link #GAV1_ERROR} if there was an error.
169    */
gav1Init(int threads)170   private native long gav1Init(int threads);
171 
172   /**
173    * Deallocates the decoder context.
174    *
175    * @param context Decoder context.
176    */
gav1Close(long context)177   private native void gav1Close(long context);
178 
179   /**
180    * Decodes the encoded data passed.
181    *
182    * @param context Decoder context.
183    * @param encodedData Encoded data.
184    * @param length Length of the data buffer.
185    * @return {@link #GAV1_OK} if successful, {@link #GAV1_ERROR} if an error occurred.
186    */
gav1Decode(long context, ByteBuffer encodedData, int length)187   private native int gav1Decode(long context, ByteBuffer encodedData, int length);
188 
189   /**
190    * Gets the decoded frame.
191    *
192    * @param context Decoder context.
193    * @param outputBuffer Output buffer for the decoded frame.
194    * @return {@link #GAV1_OK} if successful, {@link #GAV1_DECODE_ONLY} if successful but the frame
195    *     is decode-only, {@link #GAV1_ERROR} if an error occurred.
196    */
gav1GetFrame( long context, VideoDecoderOutputBuffer outputBuffer, boolean decodeOnly)197   private native int gav1GetFrame(
198       long context, VideoDecoderOutputBuffer outputBuffer, boolean decodeOnly);
199 
200   /**
201    * Renders the frame to the surface. Used with {@link C#VIDEO_OUTPUT_MODE_SURFACE_YUV} only.
202    *
203    * @param context Decoder context.
204    * @param surface Output surface.
205    * @param outputBuffer Output buffer with the decoded frame.
206    * @return {@link #GAV1_OK} if successful, {@link #GAV1_ERROR} if an error occurred.
207    */
gav1RenderFrame( long context, Surface surface, VideoDecoderOutputBuffer outputBuffer)208   private native int gav1RenderFrame(
209       long context, Surface surface, VideoDecoderOutputBuffer outputBuffer);
210 
211   /**
212    * Releases the frame. Used with {@link C#VIDEO_OUTPUT_MODE_SURFACE_YUV} only.
213    *
214    * @param context Decoder context.
215    * @param outputBuffer Output buffer.
216    */
gav1ReleaseFrame(long context, VideoDecoderOutputBuffer outputBuffer)217   private native void gav1ReleaseFrame(long context, VideoDecoderOutputBuffer outputBuffer);
218 
219   /**
220    * Returns a human-readable string describing the last error encountered in the given context.
221    *
222    * @param context Decoder context.
223    * @return A string describing the last encountered error.
224    */
gav1GetErrorMessage(long context)225   private native String gav1GetErrorMessage(long context);
226 
227   /**
228    * Returns whether an error occurred.
229    *
230    * @param context Decoder context.
231    * @return {@link #GAV1_OK} if there was no error, {@link #GAV1_ERROR} if an error occurred.
232    */
gav1CheckError(long context)233   private native int gav1CheckError(long context);
234 }
235