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