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