1 /*
2 * Copyright (C) 2022 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 /* Original code copied from NDK Native-media sample code */
18
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "NdkMediaCodec-jni"
21 #include <log/log.h>
22
23 #include <android/native_window_jni.h>
24 #include <assert.h>
25 #include <jni.h>
26 #include <string.h>
27 #include <unistd.h>
28
29
30 #include "media/NdkMediaExtractor.h"
31 #include "media/NdkMediaCodec.h"
32 #include "media/NdkMediaCrypto.h"
33 #include "media/NdkMediaDataSource.h"
34 #include "media/NdkMediaFormat.h"
35 #include "media/NdkMediaMuxer.h"
36
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateCodecByName(JNIEnv * env,jclass,jstring name)37 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateCodecByName(
38 JNIEnv *env, jclass /*clazz*/, jstring name) {
39
40 if (name == NULL) {
41 return 0;
42 }
43
44 const char *tmp = env->GetStringUTFChars(name, NULL);
45 if (tmp == NULL) {
46 return 0;
47 }
48
49 AMediaCodec *codec = AMediaCodec_createCodecByName(tmp);
50 if (codec == NULL) {
51 env->ReleaseStringUTFChars(name, tmp);
52 return 0;
53 }
54
55 env->ReleaseStringUTFChars(name, tmp);
56 return reinterpret_cast<jlong>(codec);
57
58 }
59
Java_android_media_cts_NdkMediaCodec_AMediaCodecDelete(JNIEnv *,jclass,jlong codec)60 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecDelete(
61 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
62 media_status_t err = AMediaCodec_delete(reinterpret_cast<AMediaCodec *>(codec));
63 return err == AMEDIA_OK;
64 }
65
Java_android_media_cts_NdkMediaCodec_AMediaCodecStart(JNIEnv *,jclass,jlong codec)66 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStart(
67 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
68 media_status_t err = AMediaCodec_start(reinterpret_cast<AMediaCodec *>(codec));
69 return err == AMEDIA_OK;
70 }
71
Java_android_media_cts_NdkMediaCodec_AMediaCodecStop(JNIEnv *,jclass,jlong codec)72 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStop(
73 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
74 media_status_t err = AMediaCodec_stop(reinterpret_cast<AMediaCodec *>(codec));
75 return err == AMEDIA_OK;
76 }
77
Java_android_media_cts_NdkMediaCodec_AMediaCodecConfigure(JNIEnv * env,jclass,jlong codec,jstring mime,jint width,jint height,jint colorFormat,jint bitRate,jint frameRate,jint iFrameInterval,jobject csd0,jobject csd1,jint flags,jint lowLatency,jobject surface,jint range,jint standard,jint transfer)78 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecConfigure(
79 JNIEnv *env,
80 jclass /*clazz*/,
81 jlong codec,
82 jstring mime,
83 jint width,
84 jint height,
85 jint colorFormat,
86 jint bitRate,
87 jint frameRate,
88 jint iFrameInterval,
89 jobject csd0,
90 jobject csd1,
91 jint flags,
92 jint lowLatency,
93 jobject surface,
94 jint range,
95 jint standard,
96 jint transfer) {
97
98 AMediaFormat* format = AMediaFormat_new();
99 if (format == NULL) {
100 return false;
101 }
102
103 const char *tmp = env->GetStringUTFChars(mime, NULL);
104 if (tmp == NULL) {
105 AMediaFormat_delete(format);
106 return false;
107 }
108
109 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, tmp);
110 env->ReleaseStringUTFChars(mime, tmp);
111
112 const char *keys[] = {
113 AMEDIAFORMAT_KEY_WIDTH,
114 AMEDIAFORMAT_KEY_HEIGHT,
115 AMEDIAFORMAT_KEY_COLOR_FORMAT,
116 AMEDIAFORMAT_KEY_BIT_RATE,
117 AMEDIAFORMAT_KEY_FRAME_RATE,
118 AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
119 // need to specify the actual string, since this test needs
120 // to run on API 29, where the symbol doesn't exist
121 "low-latency", // AMEDIAFORMAT_KEY_LOW_LATENCY
122 AMEDIAFORMAT_KEY_COLOR_RANGE,
123 AMEDIAFORMAT_KEY_COLOR_STANDARD,
124 AMEDIAFORMAT_KEY_COLOR_TRANSFER,
125 };
126
127 jint values[] = {width, height, colorFormat, bitRate, frameRate, iFrameInterval, lowLatency,
128 range, standard, transfer};
129 for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
130 if (values[i] >= 0) {
131 AMediaFormat_setInt32(format, keys[i], values[i]);
132 }
133 }
134
135 if (csd0 != NULL) {
136 void *csd0Ptr = env->GetDirectBufferAddress(csd0);
137 jlong csd0Size = env->GetDirectBufferCapacity(csd0);
138 AMediaFormat_setBuffer(format, "csd-0", csd0Ptr, csd0Size);
139 }
140
141 if (csd1 != NULL) {
142 void *csd1Ptr = env->GetDirectBufferAddress(csd1);
143 jlong csd1Size = env->GetDirectBufferCapacity(csd1);
144 AMediaFormat_setBuffer(format, "csd-1", csd1Ptr, csd1Size);
145 }
146
147 media_status_t err = AMediaCodec_configure(
148 reinterpret_cast<AMediaCodec *>(codec),
149 format,
150 surface == NULL ? NULL : ANativeWindow_fromSurface(env, surface),
151 NULL,
152 flags);
153
154 AMediaFormat_delete(format);
155 return err == AMEDIA_OK;
156
157 }
158
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(JNIEnv * env,jclass,jlong codec,jobject surface)159 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(
160 JNIEnv* env, jclass /*clazz*/, jlong codec, jobject surface) {
161
162 media_status_t err = AMediaCodec_setInputSurface(
163 reinterpret_cast<AMediaCodec *>(codec),
164 ANativeWindow_fromSurface(env, surface));
165
166 return err == AMEDIA_OK;
167
168 }
169
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(JNIEnv *,jclass,jlong codec,jlong nativeWindow)170 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(
171 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong nativeWindow) {
172
173 media_status_t err = AMediaCodec_setInputSurface(
174 reinterpret_cast<AMediaCodec *>(codec),
175 reinterpret_cast<ANativeWindow *>(nativeWindow));
176
177 return err == AMEDIA_OK;
178
179 }
180
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(JNIEnv *,jclass,jlong codec)181 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(
182 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
183
184 ANativeWindow *nativeWindow;
185 media_status_t err = AMediaCodec_createInputSurface(
186 reinterpret_cast<AMediaCodec *>(codec),
187 &nativeWindow);
188
189 if (err == AMEDIA_OK) {
190 return reinterpret_cast<jlong>(nativeWindow);
191 }
192
193 return 0;
194
195 }
196
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(JNIEnv *,jclass)197 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(
198 JNIEnv* /*env*/, jclass /*clazz*/) {
199
200 ANativeWindow *nativeWindow;
201 media_status_t err = AMediaCodec_createPersistentInputSurface(&nativeWindow);
202
203 if (err == AMEDIA_OK) {
204 return reinterpret_cast<jlong>(nativeWindow);
205 }
206
207 return 0;
208
209 }
210
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(JNIEnv * env,jclass,jlong codec)211 extern "C" jstring Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(
212 JNIEnv* env, jclass /*clazz*/, jlong codec) {
213
214 AMediaFormat *format = AMediaCodec_getOutputFormat(reinterpret_cast<AMediaCodec *>(codec));
215 const char *str = AMediaFormat_toString(format);
216 jstring jstr = env->NewStringUTF(str);
217 AMediaFormat_delete(format);
218 return jstr;
219
220 }
221
Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(JNIEnv *,jclass,jlong codec)222 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(
223 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
224
225 media_status_t err = AMediaCodec_signalEndOfInputStream(reinterpret_cast<AMediaCodec *>(codec));
226 return err == AMEDIA_OK;
227
228 }
229
Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(JNIEnv *,jclass,jlong codec,jint index,jboolean render)230 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(
231 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jint index, jboolean render) {
232
233 media_status_t err = AMediaCodec_releaseOutputBuffer(
234 reinterpret_cast<AMediaCodec *>(codec),
235 index,
236 render);
237
238 return err == AMEDIA_OK;
239
240 }
241
AMediaCodecGetBuffer(JNIEnv * env,jlong codec,jint index,uint8_t * (* getBuffer)(AMediaCodec *,size_t,size_t *))242 static jobject AMediaCodecGetBuffer(
243 JNIEnv* env,
244 jlong codec,
245 jint index,
246 uint8_t *(*getBuffer)(AMediaCodec*, size_t, size_t*)) {
247
248 size_t bufsize;
249 uint8_t *buf = getBuffer(
250 reinterpret_cast<AMediaCodec *>(codec),
251 index,
252 &bufsize);
253
254 return env->NewDirectByteBuffer(buf, bufsize);
255
256 }
257
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(JNIEnv * env,jclass,jlong codec,jint index)258 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(
259 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
260
261 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getOutputBuffer);
262
263 }
264
Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(JNIEnv * env,jclass,jlong codec,jlong timeoutUs)265 extern "C" jlongArray Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(
266 JNIEnv* env, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
267
268 AMediaCodecBufferInfo info;
269 memset(&info, 0, sizeof(info));
270 int status = AMediaCodec_dequeueOutputBuffer(
271 reinterpret_cast<AMediaCodec *>(codec),
272 &info,
273 timeoutUs);
274
275 jlong ret[5] = {0};
276 ret[0] = status;
277 ret[1] = 0; // NdkMediaCodec calls ABuffer::data, which already adds offset
278 ret[2] = info.size;
279 ret[3] = info.presentationTimeUs;
280 ret[4] = info.flags;
281
282 jlongArray jret = env->NewLongArray(5);
283 env->SetLongArrayRegion(jret, 0, 5, ret);
284 return jret;
285
286 }
287
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(JNIEnv * env,jclass,jlong codec,jint index)288 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(
289 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
290
291 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getInputBuffer);
292
293 }
294
Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(JNIEnv *,jclass,jlong codec,jlong timeoutUs)295 extern "C" jint Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(
296 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
297
298 return AMediaCodec_dequeueInputBuffer(
299 reinterpret_cast<AMediaCodec *>(codec),
300 timeoutUs);
301
302 }
303
Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(JNIEnv *,jclass,jlong codec,jint index,jint offset,jint size,jlong presentationTimeUs,jint flags)304 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(
305 JNIEnv* /*env*/,
306 jclass /*clazz*/,
307 jlong codec,
308 jint index,
309 jint offset,
310 jint size,
311 jlong presentationTimeUs,
312 jint flags) {
313
314 media_status_t err = AMediaCodec_queueInputBuffer(
315 reinterpret_cast<AMediaCodec *>(codec),
316 index,
317 offset,
318 size,
319 presentationTimeUs,
320 flags);
321
322 return err == AMEDIA_OK;
323
324 }
325
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(JNIEnv * env,jclass,jlong codec,jstring jkey,jint value)326 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(
327 JNIEnv* env, jclass /*clazz*/, jlong codec, jstring jkey, jint value) {
328
329 AMediaFormat* params = AMediaFormat_new();
330 if (params == NULL) {
331 return false;
332 }
333
334 const char *key = env->GetStringUTFChars(jkey, NULL);
335 if (key == NULL) {
336 AMediaFormat_delete(params);
337 return false;
338 }
339
340 AMediaFormat_setInt32(params, key, value);
341 media_status_t err = AMediaCodec_setParameters(
342 reinterpret_cast<AMediaCodec *>(codec),
343 params);
344 env->ReleaseStringUTFChars(jkey, key);
345 AMediaFormat_delete(params);
346 return err == AMEDIA_OK;
347
348 }