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