1 /*
2  * Copyright (C) 2017 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 android.media.cts;
18 
19 import android.media.MediaCodec;
20 import android.media.MediaCodec.BufferInfo;
21 import android.media.MediaCodec.Callback;
22 import android.media.MediaFormat;
23 import android.os.Build;
24 import android.os.Bundle;
25 import android.util.Log;
26 import android.view.Surface;
27 
28 import com.android.compatibility.common.util.ApiLevelUtil;
29 
30 import java.nio.ByteBuffer;
31 
32 public class NdkMediaCodec implements MediaCodecWrapper {
33 
34     private static final String CSD_0 = "csd-0";
35     private static final String CSD_1 = "csd-1";
36     private static final String CSD_2 = "csd-2";
37     private long mNdkMediaCodec;
38     private final String mName;
39 
40     static {
41         Log.i("@@@", "before loadlibrary");
42         System.loadLibrary("ctsmediacommon_jni");
43         Log.i("@@@", "after loadlibrary");
44     }
45 
AMediaCodecCreateCodecByName(String name)46     private static native long AMediaCodecCreateCodecByName(String name);
AMediaCodecDelete(long ndkMediaCodec)47     private static native boolean AMediaCodecDelete(long ndkMediaCodec);
AMediaCodecStart(long ndkMediaCodec)48     private static native boolean AMediaCodecStart(long ndkMediaCodec);
AMediaCodecStop(long ndkMediaCodec)49     private static native boolean AMediaCodecStop(long ndkMediaCodec);
AMediaCodecGetOutputFormatString(long ndkMediaCodec)50     private static native String AMediaCodecGetOutputFormatString(long ndkMediaCodec);
AMediaCodecSetInputSurface(long ndkMediaCodec, Surface surface)51     private static native boolean AMediaCodecSetInputSurface(long ndkMediaCodec, Surface surface);
AMediaCodecSetNativeInputSurface(long ndkMediaCodec, long aNativeWindow)52     private static native boolean AMediaCodecSetNativeInputSurface(long ndkMediaCodec, long aNativeWindow);
AMediaCodecCreateInputSurface(long ndkMediaCodec)53     private static native long AMediaCodecCreateInputSurface(long ndkMediaCodec);
AMediaCodecCreatePersistentInputSurface()54     private static native long AMediaCodecCreatePersistentInputSurface();
AMediaCodecSignalEndOfInputStream(long ndkMediaCodec)55     private static native boolean AMediaCodecSignalEndOfInputStream(long ndkMediaCodec);
AMediaCodecReleaseOutputBuffer(long ndkMediaCodec, int index, boolean render)56     private static native boolean AMediaCodecReleaseOutputBuffer(long ndkMediaCodec, int index, boolean render);
AMediaCodecGetOutputBuffer(long ndkMediaCodec, int index)57     private static native ByteBuffer AMediaCodecGetOutputBuffer(long ndkMediaCodec, int index);
AMediaCodecDequeueOutputBuffer(long ndkMediaCodec, long timeoutUs)58     private static native long[] AMediaCodecDequeueOutputBuffer(long ndkMediaCodec, long timeoutUs);
AMediaCodecGetInputBuffer(long ndkMediaCodec, int index)59     private static native ByteBuffer AMediaCodecGetInputBuffer(long ndkMediaCodec, int index);
AMediaCodecDequeueInputBuffer(long ndkMediaCodec, long timeoutUs)60     private static native int AMediaCodecDequeueInputBuffer(long ndkMediaCodec, long timeoutUs);
AMediaCodecSetParameter(long ndkMediaCodec, String key, int value)61     private static native boolean AMediaCodecSetParameter(long ndkMediaCodec, String key, int value);
62 
AMediaCodecConfigure( long ndkMediaCodec, String mime, int width, int height, int colorFormat, int bitRate, int frameRate, int iFrameInterval, ByteBuffer csd0, ByteBuffer csd1, int flags, int lowLatency, Surface surface, int range, int standard, int transfer)63     private static native boolean AMediaCodecConfigure(
64             long ndkMediaCodec,
65             String mime,
66             int width,
67             int height,
68             int colorFormat,
69             int bitRate,
70             int frameRate,
71             int iFrameInterval,
72             ByteBuffer csd0,
73             ByteBuffer csd1,
74             int flags,
75             int lowLatency,
76             Surface surface,
77             int range,
78             int standard,
79             int transfer);
80 
AMediaCodecQueueInputBuffer( long ndkMediaCodec, int index, int offset, int size, long presentationTimeUs, int flags)81     private static native boolean AMediaCodecQueueInputBuffer(
82             long ndkMediaCodec,
83             int index,
84             int offset,
85             int size,
86             long presentationTimeUs,
87             int flags);
88 
NdkMediaCodec(String name)89     public NdkMediaCodec(String name) {
90         mName = name;
91         mNdkMediaCodec = AMediaCodecCreateCodecByName(name);
92     }
93 
94     @Override
finalize()95     protected void finalize() throws Throwable {
96         AMediaCodecDelete(mNdkMediaCodec);
97     }
98 
99     @Override
release()100     public void release() {
101         AMediaCodecDelete(mNdkMediaCodec);
102         mNdkMediaCodec = 0;
103     }
104 
105     @Override
start()106     public void start() {
107         AMediaCodecStart(mNdkMediaCodec);
108     }
109 
110     @Override
stop()111     public void stop() {
112         AMediaCodecStop(mNdkMediaCodec);
113     }
114 
115     @Override
configure(MediaFormat format, int flags)116     public void configure(MediaFormat format, int flags) {
117         configure(format, flags, null /* surface */);
118     }
119 
120     @Override
configure(MediaFormat format, int flags, Surface surface)121     public void configure(MediaFormat format, int flags, Surface surface) {
122 
123         int width = format.getInteger(MediaFormat.KEY_WIDTH, -1);
124         int height = format.getInteger(MediaFormat.KEY_HEIGHT, -1);
125         int colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT, -1);
126         int bitRate = format.getInteger(MediaFormat.KEY_BIT_RATE, -1);
127         int frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE, -1);
128         int iFrameInterval = format.getInteger(MediaFormat.KEY_I_FRAME_INTERVAL, -1);
129         int lowLatency = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R) ?
130                 format.getInteger(MediaFormat.KEY_LOW_LATENCY, -1) : -1;
131         int range = format.getInteger(MediaFormat.KEY_COLOR_RANGE, -1);
132         int standard = format.getInteger(MediaFormat.KEY_COLOR_STANDARD, -1);
133         int transfer = format.getInteger(MediaFormat.KEY_COLOR_TRANSFER, -1);
134 
135         ByteBuffer csd0BufCopy = null;
136         if (format.containsKey(CSD_0)) {
137             ByteBuffer csd0BufOld = format.getByteBuffer(CSD_0);
138             csd0BufCopy = ByteBuffer.allocateDirect(csd0BufOld.remaining());
139             csd0BufCopy.put(csd0BufOld);
140             csd0BufCopy.position(0);
141         }
142 
143         ByteBuffer csd1BufCopy = null;
144         if (format.containsKey(CSD_1)) {
145             ByteBuffer csd1BufOld = format.getByteBuffer(CSD_1);
146             csd1BufCopy = ByteBuffer.allocateDirect(csd1BufOld.remaining());
147             csd1BufCopy.put(csd1BufOld);
148             csd1BufCopy.position(0);
149         }
150 
151         // fail loudly so the test can be properly extended.
152         if (format.containsKey(CSD_2)) {
153             throw new UnsupportedOperationException("test error: does not handle csd-2");
154         }
155 
156         AMediaCodecConfigure(
157                 mNdkMediaCodec,
158                 format.getString(MediaFormat.KEY_MIME),
159                 width,
160                 height,
161                 colorFormat,
162                 bitRate,
163                 frameRate,
164                 iFrameInterval ,
165                 csd0BufCopy,
166                 csd1BufCopy,
167                 flags,
168                 lowLatency,
169                 surface,
170                 range,
171                 standard,
172                 transfer);
173     }
174 
175     @Override
setInputSurface(InputSurfaceInterface surface)176     public void setInputSurface(InputSurfaceInterface surface) {
177         surface.configure(this);
178     }
179 
setInputSurface(Surface surface)180     public void setInputSurface(Surface surface) {
181         AMediaCodecSetInputSurface(mNdkMediaCodec, surface);
182     }
183 
setInputSurface(long aNativeWindow)184     public void setInputSurface(long aNativeWindow) {
185         AMediaCodecSetNativeInputSurface(mNdkMediaCodec, aNativeWindow);
186     }
187 
188     @Override
createInputSurface()189     public InputSurfaceInterface createInputSurface() {
190         return new NdkInputSurface(AMediaCodecCreateInputSurface(mNdkMediaCodec));
191     }
192 
createPersistentInputSurface()193     public static InputSurfaceInterface createPersistentInputSurface() {
194         return new NdkInputSurface(AMediaCodecCreatePersistentInputSurface());
195     }
196 
197     @Override
dequeueOutputBuffer(BufferInfo info, long timeoutUs)198     public int dequeueOutputBuffer(BufferInfo info, long timeoutUs) {
199         long[] ret = AMediaCodecDequeueOutputBuffer(mNdkMediaCodec, timeoutUs);
200         if (ret[0] >= 0) {
201             info.offset = (int)ret[1];
202             info.size = (int)ret[2];
203             info.presentationTimeUs = ret[3];
204             info.flags = (int)ret[4];
205         }
206         return (int)ret[0];
207     }
208 
209     @Override
getOutputBuffer(int index)210     public ByteBuffer getOutputBuffer(int index) {
211         return AMediaCodecGetOutputBuffer(mNdkMediaCodec, index);
212     }
213 
214     @Override
releaseOutputBuffer(int index, boolean render)215     public void releaseOutputBuffer(int index, boolean render) {
216         AMediaCodecReleaseOutputBuffer(mNdkMediaCodec, index, render);
217     }
218 
219     @Override
signalEndOfInputStream()220     public void signalEndOfInputStream() {
221         AMediaCodecSignalEndOfInputStream(mNdkMediaCodec);
222     }
223 
224     @Override
getOutputFormatString()225     public String getOutputFormatString() {
226         return AMediaCodecGetOutputFormatString(mNdkMediaCodec);
227     }
228 
229     @Override
getOutputBuffers()230     public ByteBuffer[] getOutputBuffers() {
231         return null;
232     }
233 
234     @Override
getInputBuffer(int index)235     public ByteBuffer getInputBuffer(int index) {
236         return AMediaCodecGetInputBuffer(mNdkMediaCodec, index);
237     }
238 
239     @Override
getInputBuffers()240     public ByteBuffer[] getInputBuffers() {
241         return null;
242     }
243 
244     @Override
queueInputBuffer( int index, int offset, int size, long presentationTimeUs, int flags)245     public void queueInputBuffer(
246             int index,
247             int offset,
248             int size,
249             long presentationTimeUs,
250             int flags) {
251 
252         AMediaCodecQueueInputBuffer(mNdkMediaCodec, index, offset, size, presentationTimeUs, flags);
253 
254     }
255 
256     @Override
dequeueInputBuffer(long timeoutUs)257     public int dequeueInputBuffer(long timeoutUs) {
258         return AMediaCodecDequeueInputBuffer(mNdkMediaCodec, timeoutUs);
259     }
260 
261     @Override
setParameters(Bundle params)262     public void setParameters(Bundle params) {
263 
264         String keys[] = new String[] {
265                 MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME,
266                 MediaCodec.PARAMETER_KEY_VIDEO_BITRATE};
267 
268         for (String key : keys) {
269             if (params.containsKey(key)) {
270                 int value = params.getInt(key);
271                 AMediaCodecSetParameter(mNdkMediaCodec, key, value);
272             }
273         }
274 
275     }
276 
277     @Override
setCallback(Callback mCallback)278     public void setCallback(Callback mCallback) {
279         throw new UnsupportedOperationException(mCallback.toString());
280     }
281 
282     @Override
toString()283     public String toString() {
284         return String.format("%s(%s, %x)", getClass(), mName, mNdkMediaCodec);
285     }
286 }
287