1 /*
2 * Copyright (C) 2019 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NativeMuxerUnitTest"
19 #include <log/log.h>
20
21 #include <fcntl.h>
22 #include <jni.h>
23 #include <media/NdkMediaExtractor.h>
24 #include <media/NdkMediaFormat.h>
25 #include <media/NdkMediaMuxer.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 #include <cmath>
30 #include <cstring>
31 #include <fstream>
32 #include <map>
33 #include <vector>
34
35 #include "NativeMediaCommon.h"
36
insertPerFrameSubtitles(AMediaMuxer * muxer,long pts,size_t trackID)37 static media_status_t insertPerFrameSubtitles(AMediaMuxer* muxer, long pts, size_t trackID) {
38 const char* greeting = "hello world";
39 auto* info = new AMediaCodecBufferInfo;
40 info->offset = 0;
41 info->size = strlen(greeting);
42 info->presentationTimeUs = pts;
43 info->flags = 0;
44 media_status_t status = AMediaMuxer_writeSampleData(muxer, trackID, (uint8_t*)greeting, info);
45 delete info;
46 return status;
47 }
48
nativeTestIfInvalidFdIsRejected(JNIEnv *,jobject)49 static jboolean nativeTestIfInvalidFdIsRejected(JNIEnv*, jobject) {
50 AMediaMuxer* muxer = AMediaMuxer_new(-1, AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP);
51 bool isPass = true;
52 if (muxer != nullptr) {
53 AMediaMuxer_delete(muxer);
54 ALOGE("error: muxer constructor accepts invalid file descriptor");
55 isPass = false;
56 }
57 return static_cast<jboolean>(isPass);
58 }
59
nativeTestIfReadOnlyFdIsRejected(JNIEnv * env,jobject,jstring jdstPath)60 static jboolean nativeTestIfReadOnlyFdIsRejected(JNIEnv* env, jobject, jstring jdstPath) {
61 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
62 FILE* ofp = fopen(cdstPath, "rbe");
63 if (ofp == nullptr) {
64 ALOGE("Unable to open file %s", cdstPath);
65 env->ReleaseStringUTFChars(jdstPath, cdstPath);
66 return static_cast<jboolean>(false);
67 }
68 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP);
69 bool isPass = true;
70 if (muxer != nullptr) {
71 AMediaMuxer_delete(muxer);
72 ALOGE("error: muxer constructor accepts read-only file descriptor");
73 isPass = false;
74 }
75 fclose(ofp);
76 env->ReleaseStringUTFChars(jdstPath, cdstPath);
77 return static_cast<jboolean>(isPass);
78 }
79
nativeTestIfNonSeekableFdIsRejected(JNIEnv *,jobject)80 static jboolean nativeTestIfNonSeekableFdIsRejected(JNIEnv*, jobject) {
81 int pipefd[2];
82 if (pipe(pipefd) == -1) {
83 ALOGE("unable to create pipe fd");
84 return false;
85 }
86 AMediaMuxer* muxer = AMediaMuxer_new(pipefd[1], AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP);
87 bool isPass = true;
88 if (muxer != nullptr) {
89 AMediaMuxer_delete(muxer);
90 ALOGE("error: muxer constructor accepts non-seekable file descriptor");
91 isPass = false;
92 }
93 close(pipefd[0]);
94 close(pipefd[1]);
95 return static_cast<jboolean>(isPass);
96 }
97
nativeTestIfInvalidOutputFormatIsRejected(JNIEnv * env,jobject,jstring jdstPath)98 static jboolean nativeTestIfInvalidOutputFormatIsRejected(JNIEnv* env, jobject, jstring jdstPath) {
99 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
100 FILE* ofp = fopen(cdstPath, "wbe+");
101 if (ofp == nullptr) {
102 ALOGE("Unable to open file %s", cdstPath);
103 env->ReleaseStringUTFChars(jdstPath, cdstPath);
104 return static_cast<jboolean>(false);
105 }
106 AMediaMuxer* muxer = nullptr;
107 bool isPass = true;
108
109 muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)(-1));
110 if (muxer != nullptr) {
111 AMediaMuxer_delete(muxer);
112 ALOGE("error: muxer constructor accepts invalid (negative) output format");
113 isPass = false;
114 muxer = nullptr;
115 }
116 muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)(LOCAL_AMEDIAMUXER_OUTPUT_FORMAT_LAST + 1));
117 if (muxer != nullptr) {
118 AMediaMuxer_delete(muxer);
119 ALOGE("error: muxer constructor accepts invalid (too large) output format");
120 isPass = false;
121 muxer = nullptr;
122 }
123 fclose(ofp);
124 env->ReleaseStringUTFChars(jdstPath, cdstPath);
125 return static_cast<jboolean>(isPass);
126 }
127
nativeTestIfInvalidMediaFormatIsRejected(JNIEnv * env,jobject,jstring jdstPath)128 static jboolean nativeTestIfInvalidMediaFormatIsRejected(JNIEnv* env, jobject, jstring jdstPath) {
129 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
130 FILE* ofp = fopen(cdstPath, "wbe+");
131 if (ofp == nullptr) {
132 ALOGE("Unable to open file %s", cdstPath);
133 env->ReleaseStringUTFChars(jdstPath, cdstPath);
134 return static_cast<jboolean>(false);
135 }
136 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
137 AMediaFormat* format = AMediaFormat_new();
138 bool isPass = true;
139 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
140 ALOGE("error: muxer.addTrack succeeds with format that has no mediaType key");
141 isPass = false;
142 }
143
144 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "text/cea-608");
145 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
146 ALOGE("error: muxer.addTrack succeeds with format whose mediaType is non-compliant");
147 isPass = false;
148 }
149 AMediaFormat_delete(format);
150 AMediaMuxer_delete(muxer);
151 fclose(ofp);
152 env->ReleaseStringUTFChars(jdstPath, cdstPath);
153 return static_cast<jboolean>(isPass);
154 }
155
nativeTestIfCorruptMediaFormatIsRejected(JNIEnv * env,jobject,jstring jdstPath)156 static jboolean nativeTestIfCorruptMediaFormatIsRejected(JNIEnv* env, jobject, jstring jdstPath) {
157 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
158 FILE* ofp = fopen(cdstPath, "wbe+");
159 if (ofp == nullptr) {
160 ALOGE("Unable to open file %s", cdstPath);
161 env->ReleaseStringUTFChars(jdstPath, cdstPath);
162 return static_cast<jboolean>(false);
163 }
164 bool isPass = true;
165 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
166 AMediaFormat* format = AMediaFormat_new();
167 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_AUDIO_AAC);
168 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, -1);
169 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
170 ALOGE("error: muxer.addTrack succeeds with erroneous key-value pairs in media format");
171 isPass = false;
172 }
173 AMediaFormat_delete(format);
174 AMediaMuxer_delete(muxer);
175 fclose(ofp);
176 env->ReleaseStringUTFChars(jdstPath, cdstPath);
177 return static_cast<jboolean>(isPass);
178 }
179
nativeTestIfAddTrackSucceedsAfterStart(JNIEnv * env,jobject,jstring jdstPath)180 static jboolean nativeTestIfAddTrackSucceedsAfterStart(JNIEnv* env, jobject, jstring jdstPath) {
181 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
182 FILE* ofp = fopen(cdstPath, "wbe+");
183 if (ofp == nullptr) {
184 ALOGE("Unable to open file %s", cdstPath);
185 env->ReleaseStringUTFChars(jdstPath, cdstPath);
186 return static_cast<jboolean>(false);
187 }
188 bool isPass = true;
189 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
190 AMediaFormat* format = AMediaFormat_new();
191 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
192 isPass &= AMediaMuxer_addTrack(muxer, format) >= 0;
193 isPass &= (AMediaMuxer_start(muxer) == AMEDIA_OK);
194 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
195 ALOGE("error: muxer.addTrack succeeds after muxer.start");
196 isPass = false;
197 }
198 AMediaFormat_delete(format);
199 AMediaMuxer_delete(muxer);
200 fclose(ofp);
201 env->ReleaseStringUTFChars(jdstPath, cdstPath);
202 return static_cast<jboolean>(isPass);
203 }
204
nativeTestIfAddTrackSucceedsAfterWriteSampleData(JNIEnv * env,jobject,jstring jdstPath)205 static jboolean nativeTestIfAddTrackSucceedsAfterWriteSampleData(JNIEnv* env, jobject,
206 jstring jdstPath) {
207 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
208 FILE* ofp = fopen(cdstPath, "wbe+");
209 if (ofp == nullptr) {
210 ALOGE("Unable to open file %s", cdstPath);
211 env->ReleaseStringUTFChars(jdstPath, cdstPath);
212 return static_cast<jboolean>(false);
213 }
214 bool isPass = true;
215 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
216 AMediaFormat* format = AMediaFormat_new();
217 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
218 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
219 isPass &= trackID >= 0;
220 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
221 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
222 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
223 ALOGE("error: muxer.addTrack succeeds after muxer.writeSampleData");
224 isPass = false;
225 }
226 AMediaFormat_delete(format);
227 AMediaMuxer_delete(muxer);
228 fclose(ofp);
229 env->ReleaseStringUTFChars(jdstPath, cdstPath);
230 return static_cast<jboolean>(isPass);
231 }
232
nativeTestIfAddTrackSucceedsAfterStop(JNIEnv * env,jobject,jstring jdstPath)233 static jboolean nativeTestIfAddTrackSucceedsAfterStop(JNIEnv* env, jobject, jstring jdstPath) {
234 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
235 FILE* ofp = fopen(cdstPath, "wbe+");
236 if (ofp == nullptr) {
237 ALOGE("Unable to open file %s", cdstPath);
238 env->ReleaseStringUTFChars(jdstPath, cdstPath);
239 return static_cast<jboolean>(false);
240 }
241 bool isPass = true;
242 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
243 AMediaFormat* format = AMediaFormat_new();
244 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
245 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
246 isPass &= trackID >= 0;
247 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
248 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
249 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
250 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
251 ALOGE("error: muxer.addTrack succeeds after muxer.stop");
252 isPass = false;
253 }
254 AMediaFormat_delete(format);
255 AMediaMuxer_delete(muxer);
256 fclose(ofp);
257 env->ReleaseStringUTFChars(jdstPath, cdstPath);
258 return static_cast<jboolean>(isPass);
259 }
260
nativeTestIfMuxerStartsBeforeAddTrack(JNIEnv * env,jobject,jstring jdstPath)261 static jboolean nativeTestIfMuxerStartsBeforeAddTrack(JNIEnv* env, jobject, jstring jdstPath) {
262 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
263 FILE* ofp = fopen(cdstPath, "wbe+");
264 if (ofp == nullptr) {
265 ALOGE("Unable to open file %s", cdstPath);
266 env->ReleaseStringUTFChars(jdstPath, cdstPath);
267 return static_cast<jboolean>(false);
268 }
269 bool isPass = true;
270 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
271 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
272 ALOGE("error: muxer.start succeeds before muxer.addTrack");
273 isPass = false;
274 }
275 AMediaMuxer_delete(muxer);
276 fclose(ofp);
277 env->ReleaseStringUTFChars(jdstPath, cdstPath);
278 return static_cast<jboolean>(isPass);
279 }
280
nativeTestIdempotentStart(JNIEnv * env,jobject,jstring jdstPath)281 static jboolean nativeTestIdempotentStart(JNIEnv* env, jobject, jstring jdstPath) {
282 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
283 FILE* ofp = fopen(cdstPath, "wbe+");
284 if (ofp == nullptr) {
285 ALOGE("Unable to open file %s", cdstPath);
286 env->ReleaseStringUTFChars(jdstPath, cdstPath);
287 return static_cast<jboolean>(false);
288 }
289 bool isPass = true;
290 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
291 AMediaFormat* format = AMediaFormat_new();
292 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
293 isPass &= AMediaMuxer_addTrack(muxer, format) >= 0;
294 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
295 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
296 ALOGE("error: double muxer.start succeeds");
297 isPass = false;
298 }
299 AMediaFormat_delete(format);
300 AMediaMuxer_delete(muxer);
301 fclose(ofp);
302 env->ReleaseStringUTFChars(jdstPath, cdstPath);
303 return static_cast<jboolean>(isPass);
304 }
305
nativeTestIfMuxerStartsAfterWriteSampleData(JNIEnv * env,jobject,jstring jdstPath)306 static jboolean nativeTestIfMuxerStartsAfterWriteSampleData(JNIEnv* env, jobject,
307 jstring jdstPath) {
308 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
309 FILE* ofp = fopen(cdstPath, "wbe+");
310 if (ofp == nullptr) {
311 ALOGE("Unable to open file %s", cdstPath);
312 env->ReleaseStringUTFChars(jdstPath, cdstPath);
313 return static_cast<jboolean>(false);
314 }
315 bool isPass = true;
316 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
317 AMediaFormat* format = AMediaFormat_new();
318 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
319 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
320 isPass &= trackID >= 0;
321 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
322 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
323 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
324 ALOGE("error: muxer.start succeeds after muxer.writeSampleData");
325 isPass = false;
326 }
327 AMediaFormat_delete(format);
328 AMediaMuxer_delete(muxer);
329 fclose(ofp);
330 env->ReleaseStringUTFChars(jdstPath, cdstPath);
331 return static_cast<jboolean>(isPass);
332 }
333
nativeTestIfMuxerStartsAfterStop(JNIEnv * env,jobject,jstring jdstPath)334 static jboolean nativeTestIfMuxerStartsAfterStop(JNIEnv* env, jobject, jstring jdstPath) {
335 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
336 FILE* ofp = fopen(cdstPath, "wbe+");
337 if (ofp == nullptr) {
338 ALOGE("Unable to open file %s", cdstPath);
339 env->ReleaseStringUTFChars(jdstPath, cdstPath);
340 return static_cast<jboolean>(false);
341 }
342 bool isPass = true;
343 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
344 AMediaFormat* format = AMediaFormat_new();
345 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
346 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
347 isPass &= trackID >= 0;
348 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
349 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
350 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
351 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
352 ALOGE("error: muxer.start succeeds after muxer.stop");
353 isPass = false;
354 }
355 AMediaFormat_delete(format);
356 AMediaMuxer_delete(muxer);
357 fclose(ofp);
358 env->ReleaseStringUTFChars(jdstPath, cdstPath);
359 return static_cast<jboolean>(isPass);
360 }
361
nativeTestStopOnANonStartedMuxer(JNIEnv * env,jobject,jstring jdstPath)362 static jboolean nativeTestStopOnANonStartedMuxer(JNIEnv* env, jobject, jstring jdstPath) {
363 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
364 FILE* ofp = fopen(cdstPath, "wbe+");
365 if (ofp == nullptr) {
366 ALOGE("Unable to open file %s", cdstPath);
367 env->ReleaseStringUTFChars(jdstPath, cdstPath);
368 return static_cast<jboolean>(false);
369 }
370 bool isPass = true;
371 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
372 AMediaFormat* format = AMediaFormat_new();
373 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
374 isPass &= AMediaMuxer_addTrack(muxer, format) >= 0;
375 if (AMEDIA_OK == AMediaMuxer_stop(muxer)) {
376 ALOGE("error: muxer.stop succeeds before muxer.start");
377 isPass = false;
378 }
379 AMediaFormat_delete(format);
380 AMediaMuxer_delete(muxer);
381 fclose(ofp);
382 env->ReleaseStringUTFChars(jdstPath, cdstPath);
383 return static_cast<jboolean>(isPass);
384 }
385
nativeTestIdempotentStop(JNIEnv * env,jobject,jstring jdstPath)386 static jboolean nativeTestIdempotentStop(JNIEnv* env, jobject, jstring jdstPath) {
387 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
388 FILE* ofp = fopen(cdstPath, "wbe+");
389 if (ofp == nullptr) {
390 ALOGE("Unable to open file %s", cdstPath);
391 env->ReleaseStringUTFChars(jdstPath, cdstPath);
392 return static_cast<jboolean>(false);
393 }
394 bool isPass = true;
395 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
396 AMediaFormat* format = AMediaFormat_new();
397 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
398 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
399 isPass &= trackID >= 0;
400 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
401 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
402 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
403 if (AMEDIA_OK == AMediaMuxer_stop(muxer)) {
404 ALOGE("error: double muxer.stop succeeds");
405 isPass = false;
406 }
407 AMediaFormat_delete(format);
408 AMediaMuxer_delete(muxer);
409 fclose(ofp);
410 env->ReleaseStringUTFChars(jdstPath, cdstPath);
411 return static_cast<jboolean>(isPass);
412 }
413
nativeTestSimpleStartStop(JNIEnv * env,jobject,jstring jdstPath)414 static jboolean nativeTestSimpleStartStop(JNIEnv* env, jobject, jstring jdstPath) {
415 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
416 FILE* ofp = fopen(cdstPath, "wbe+");
417 if (ofp == nullptr) {
418 ALOGE("Unable to open file %s", cdstPath);
419 env->ReleaseStringUTFChars(jdstPath, cdstPath);
420 return static_cast<jboolean>(false);
421 }
422 bool isPass = true;
423 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
424 AMediaFormat* format = AMediaFormat_new();
425 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
426 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
427 isPass &= trackID >= 0;
428 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
429 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
430 AMediaFormat_delete(format);
431 AMediaMuxer_delete(muxer);
432 fclose(ofp);
433 env->ReleaseStringUTFChars(jdstPath, cdstPath);
434 return static_cast<jboolean>(isPass);
435 }
436
nativeTestIfWriteSampleDataRejectsInvalidTrackIndex(JNIEnv * env,jobject,jstring jdstPath)437 static jboolean nativeTestIfWriteSampleDataRejectsInvalidTrackIndex(JNIEnv* env, jobject,
438 jstring jdstPath) {
439 bool isPass = true;
440 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
441 FILE* ofp = fopen(cdstPath, "wbe+");
442 if (ofp == nullptr) {
443 ALOGE("Unable to open file %s", cdstPath);
444 env->ReleaseStringUTFChars(jdstPath, cdstPath);
445 return static_cast<jboolean>(false);
446 }
447 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
448 AMediaFormat* format = AMediaFormat_new();
449 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
450 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
451 isPass &= trackID >= 0;
452 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
453 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
454 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, 22000, trackID + 1)) {
455 ALOGE("error: muxer.writeSampleData succeeds for invalid track ID");
456 isPass = false;
457 }
458 AMediaFormat_delete(format);
459 AMediaMuxer_delete(muxer);
460 fclose(ofp);
461 env->ReleaseStringUTFChars(jdstPath, cdstPath);
462 return static_cast<jboolean>(isPass);
463 }
464
nativeTestIfWriteSampleDataRejectsInvalidPts(JNIEnv * env,jobject,jstring jdstPath)465 static jboolean nativeTestIfWriteSampleDataRejectsInvalidPts(JNIEnv* env, jobject,
466 jstring jdstPath) {
467 bool isPass = true;
468 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
469 FILE* ofp = fopen(cdstPath, "wbe+");
470 if (ofp == nullptr) {
471 ALOGE("Unable to open file %s", cdstPath);
472 env->ReleaseStringUTFChars(jdstPath, cdstPath);
473 return static_cast<jboolean>(false);
474 }
475 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
476 AMediaFormat* format = AMediaFormat_new();
477 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
478 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
479 isPass &= trackID >= 0;
480 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
481 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
482 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, -33000, trackID)) {
483 ALOGE("error: muxer.writeSampleData succeeds for invalid pts");
484 isPass = false;
485 }
486 AMediaFormat_delete(format);
487 AMediaMuxer_delete(muxer);
488 fclose(ofp);
489 env->ReleaseStringUTFChars(jdstPath, cdstPath);
490 return static_cast<jboolean>(isPass);
491 }
492
nativeTestIfWriteSampleDataSucceedsBeforeStart(JNIEnv * env,jobject,jstring jdstPath)493 static jboolean nativeTestIfWriteSampleDataSucceedsBeforeStart(JNIEnv* env, jobject,
494 jstring jdstPath) {
495 bool isPass = true;
496 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
497 FILE* ofp = fopen(cdstPath, "wbe+");
498 if (ofp == nullptr) {
499 ALOGE("Unable to open file %s", cdstPath);
500 env->ReleaseStringUTFChars(jdstPath, cdstPath);
501 return static_cast<jboolean>(false);
502 }
503 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
504 AMediaFormat* format = AMediaFormat_new();
505 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
506 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
507 isPass &= trackID >= 0;
508 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, 0, trackID)) {
509 ALOGE("error: muxer.writeSampleData succeeds before muxer.start");
510 isPass = false;
511 }
512 AMediaFormat_delete(format);
513 AMediaMuxer_delete(muxer);
514 fclose(ofp);
515 env->ReleaseStringUTFChars(jdstPath, cdstPath);
516 return static_cast<jboolean>(isPass);
517 }
518
nativeTestIfWriteSampleDataSucceedsAfterStop(JNIEnv * env,jobject,jstring jdstPath)519 static jboolean nativeTestIfWriteSampleDataSucceedsAfterStop(JNIEnv* env, jobject,
520 jstring jdstPath) {
521 bool isPass = true;
522 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
523 FILE* ofp = fopen(cdstPath, "wbe+");
524 if (ofp == nullptr) {
525 ALOGE("Unable to open file %s", cdstPath);
526 env->ReleaseStringUTFChars(jdstPath, cdstPath);
527 return static_cast<jboolean>(false);
528 }
529 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
530 AMediaFormat* format = AMediaFormat_new();
531 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
532 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
533 isPass &= trackID >= 0;
534 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
535 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
536 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
537 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, 33000, trackID)) {
538 ALOGE("error: muxer.writeSampleData succeeds after muxer.stop");
539 isPass = false;
540 }
541 AMediaFormat_delete(format);
542 AMediaMuxer_delete(muxer);
543 fclose(ofp);
544 env->ReleaseStringUTFChars(jdstPath, cdstPath);
545 return static_cast<jboolean>(isPass);
546 }
547
registerAndroidMediaV2CtsMuxerUnitTestApi(JNIEnv * env)548 int registerAndroidMediaV2CtsMuxerUnitTestApi(JNIEnv* env) {
549 const JNINativeMethod methodTable[] = {
550 {"nativeTestIfInvalidFdIsRejected", "()Z", (void*)nativeTestIfInvalidFdIsRejected},
551 {"nativeTestIfReadOnlyFdIsRejected", "(Ljava/lang/String;)Z",
552 (void*)nativeTestIfReadOnlyFdIsRejected},
553 {"nativeTestIfNonSeekableFdIsRejected", "()Z",
554 (void*)nativeTestIfNonSeekableFdIsRejected},
555 {"nativeTestIfInvalidOutputFormatIsRejected", "(Ljava/lang/String;)Z",
556 (void*)nativeTestIfInvalidOutputFormatIsRejected},
557
558 {"nativeTestIfInvalidMediaFormatIsRejected", "(Ljava/lang/String;)Z",
559 (void*)nativeTestIfInvalidMediaFormatIsRejected},
560 {"nativeTestIfCorruptMediaFormatIsRejected", "(Ljava/lang/String;)Z",
561 (void*)nativeTestIfCorruptMediaFormatIsRejected},
562 {"nativeTestIfAddTrackSucceedsAfterStart", "(Ljava/lang/String;)Z",
563 (void*)nativeTestIfAddTrackSucceedsAfterStart},
564 {"nativeTestIfAddTrackSucceedsAfterWriteSampleData", "(Ljava/lang/String;)Z",
565 (void*)nativeTestIfAddTrackSucceedsAfterWriteSampleData},
566 {"nativeTestIfAddTrackSucceedsAfterStop", "(Ljava/lang/String;)Z",
567 (void*)nativeTestIfAddTrackSucceedsAfterStop},
568
569 {"nativeTestIfMuxerStartsBeforeAddTrack", "(Ljava/lang/String;)Z",
570 (void*)nativeTestIfMuxerStartsBeforeAddTrack},
571 {"nativeTestIdempotentStart", "(Ljava/lang/String;)Z",
572 (void*)nativeTestIdempotentStart},
573 {"nativeTestIfMuxerStartsAfterWriteSampleData", "(Ljava/lang/String;)Z",
574 (void*)nativeTestIfMuxerStartsAfterWriteSampleData},
575 {"nativeTestIfMuxerStartsAfterStop", "(Ljava/lang/String;)Z",
576 (void*)nativeTestIfMuxerStartsAfterStop},
577
578 {"nativeTestStopOnANonStartedMuxer", "(Ljava/lang/String;)Z",
579 (void*)nativeTestStopOnANonStartedMuxer},
580 {"nativeTestIdempotentStop", "(Ljava/lang/String;)Z", (void*)nativeTestIdempotentStop},
581 {"nativeTestSimpleStartStop", "(Ljava/lang/String;)Z",
582 (void*)nativeTestSimpleStartStop},
583
584 {"nativeTestIfWriteSampleDataRejectsInvalidTrackIndex", "(Ljava/lang/String;)Z",
585 (void*)nativeTestIfWriteSampleDataRejectsInvalidTrackIndex},
586 {"nativeTestIfWriteSampleDataRejectsInvalidPts", "(Ljava/lang/String;)Z",
587 (void*)nativeTestIfWriteSampleDataRejectsInvalidPts},
588 {"nativeTestIfWriteSampleDataSucceedsBeforeStart", "(Ljava/lang/String;)Z",
589 (void*)nativeTestIfWriteSampleDataSucceedsBeforeStart},
590 {"nativeTestIfWriteSampleDataSucceedsAfterStop", "(Ljava/lang/String;)Z",
591 (void*)nativeTestIfWriteSampleDataSucceedsAfterStop},
592 };
593 jclass c = env->FindClass("android/mediav2/cts/MuxerUnitTest$TestApiNative");
594 return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
595 }
596