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