• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }