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, (OutputFormat)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 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_THREE_GPP);
64 bool isPass = true;
65 if (muxer != nullptr) {
66 AMediaMuxer_delete(muxer);
67 ALOGE("error: muxer constructor accepts read-only file descriptor");
68 isPass = false;
69 }
70 fclose(ofp);
71 env->ReleaseStringUTFChars(jdstPath, cdstPath);
72 return static_cast<jboolean>(isPass);
73 }
74
nativeTestIfNonSeekableFdIsRejected(JNIEnv *,jobject)75 static jboolean nativeTestIfNonSeekableFdIsRejected(JNIEnv*, jobject) {
76 int pipefd[2];
77 if (pipe(pipefd) == -1) {
78 ALOGE("unable to create pipe fd");
79 return false;
80 }
81 AMediaMuxer* muxer = AMediaMuxer_new(pipefd[1], (OutputFormat)OUTPUT_FORMAT_THREE_GPP);
82 bool isPass = true;
83 if (muxer != nullptr) {
84 AMediaMuxer_delete(muxer);
85 ALOGE("error: muxer constructor accepts non-seekable file descriptor");
86 isPass = false;
87 }
88 close(pipefd[0]);
89 close(pipefd[1]);
90 return static_cast<jboolean>(isPass);
91 }
92
nativeTestIfInvalidOutputFormatIsRejected(JNIEnv * env,jobject,jstring jdstPath)93 static jboolean nativeTestIfInvalidOutputFormatIsRejected(JNIEnv* env, jobject, jstring jdstPath) {
94 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
95 FILE* ofp = fopen(cdstPath, "wbe+");
96 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)(OUTPUT_FORMAT_LIST_END + 1));
97 bool isPass = true;
98 if (muxer != nullptr) {
99 AMediaMuxer_delete(muxer);
100 ALOGE("error: muxer constructor accepts invalid output format");
101 isPass = false;
102 }
103 fclose(ofp);
104 env->ReleaseStringUTFChars(jdstPath, cdstPath);
105 return static_cast<jboolean>(isPass);
106 }
107
nativeTestIfInvalidMediaFormatIsRejected(JNIEnv * env,jobject,jstring jdstPath)108 static jboolean nativeTestIfInvalidMediaFormatIsRejected(JNIEnv* env, jobject, jstring jdstPath) {
109 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
110 FILE* ofp = fopen(cdstPath, "wbe+");
111 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
112 AMediaFormat* format = AMediaFormat_new();
113 bool isPass = true;
114 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
115 ALOGE("error: muxer.addTrack succeeds with format that has no mediaType key");
116 isPass = false;
117 }
118
119 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "text/cea-608");
120 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
121 ALOGE("error: muxer.addTrack succeeds with format whose mediaType is non-compliant");
122 isPass = false;
123 }
124 AMediaFormat_delete(format);
125 AMediaMuxer_delete(muxer);
126 fclose(ofp);
127 env->ReleaseStringUTFChars(jdstPath, cdstPath);
128 return static_cast<jboolean>(isPass);
129 }
130
nativeTestIfCorruptMediaFormatIsRejected(JNIEnv * env,jobject,jstring jdstPath)131 static jboolean nativeTestIfCorruptMediaFormatIsRejected(JNIEnv* env, jobject, jstring jdstPath) {
132 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
133 FILE* ofp = fopen(cdstPath, "wbe+");
134 bool isPass = true;
135 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
136 AMediaFormat* format = AMediaFormat_new();
137 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_AUDIO_AAC);
138 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, -1);
139 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
140 ALOGE("error: muxer.addTrack succeeds with erroneous key-value pairs in media format");
141 isPass = false;
142 }
143 AMediaFormat_delete(format);
144 AMediaMuxer_delete(muxer);
145 fclose(ofp);
146 env->ReleaseStringUTFChars(jdstPath, cdstPath);
147 return static_cast<jboolean>(isPass);
148 }
149
nativeTestIfAddTrackSucceedsAfterStart(JNIEnv * env,jobject,jstring jdstPath)150 static jboolean nativeTestIfAddTrackSucceedsAfterStart(JNIEnv* env, jobject, jstring jdstPath) {
151 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
152 FILE* ofp = fopen(cdstPath, "wbe+");
153 bool isPass = true;
154 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
155 AMediaFormat* format = AMediaFormat_new();
156 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
157 isPass &= AMediaMuxer_addTrack(muxer, format) >= 0;
158 isPass &= (AMediaMuxer_start(muxer) == AMEDIA_OK);
159 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
160 ALOGE("error: muxer.addTrack succeeds after muxer.start");
161 isPass = false;
162 }
163 AMediaFormat_delete(format);
164 AMediaMuxer_delete(muxer);
165 fclose(ofp);
166 env->ReleaseStringUTFChars(jdstPath, cdstPath);
167 return static_cast<jboolean>(isPass);
168 }
169
nativeTestIfAddTrackSucceedsAfterWriteSampleData(JNIEnv * env,jobject,jstring jdstPath)170 static jboolean nativeTestIfAddTrackSucceedsAfterWriteSampleData(JNIEnv* env, jobject,
171 jstring jdstPath) {
172 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
173 FILE* ofp = fopen(cdstPath, "wbe+");
174 bool isPass = true;
175 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
176 AMediaFormat* format = AMediaFormat_new();
177 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
178 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
179 isPass &= trackID >= 0;
180 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
181 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
182 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
183 ALOGE("error: muxer.addTrack succeeds after muxer.writeSampleData");
184 isPass = false;
185 }
186 AMediaFormat_delete(format);
187 AMediaMuxer_delete(muxer);
188 fclose(ofp);
189 env->ReleaseStringUTFChars(jdstPath, cdstPath);
190 return static_cast<jboolean>(isPass);
191 }
192
nativeTestIfAddTrackSucceedsAfterStop(JNIEnv * env,jobject,jstring jdstPath)193 static jboolean nativeTestIfAddTrackSucceedsAfterStop(JNIEnv* env, jobject, jstring jdstPath) {
194 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
195 FILE* ofp = fopen(cdstPath, "wbe+");
196 bool isPass = true;
197 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
198 AMediaFormat* format = AMediaFormat_new();
199 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
200 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
201 isPass &= trackID >= 0;
202 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
203 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
204 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
205 if (AMediaMuxer_addTrack(muxer, format) >= 0) {
206 ALOGE("error: muxer.addTrack succeeds after muxer.stop");
207 isPass = false;
208 }
209 AMediaFormat_delete(format);
210 AMediaMuxer_delete(muxer);
211 fclose(ofp);
212 env->ReleaseStringUTFChars(jdstPath, cdstPath);
213 return static_cast<jboolean>(isPass);
214 }
215
nativeTestIfMuxerStartsBeforeAddTrack(JNIEnv * env,jobject,jstring jdstPath)216 static jboolean nativeTestIfMuxerStartsBeforeAddTrack(JNIEnv* env, jobject, jstring jdstPath) {
217 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
218 FILE* ofp = fopen(cdstPath, "wbe+");
219 bool isPass = true;
220 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
221 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
222 ALOGE("error: muxer.start succeeds before muxer.addTrack");
223 isPass = false;
224 }
225 AMediaMuxer_delete(muxer);
226 fclose(ofp);
227 env->ReleaseStringUTFChars(jdstPath, cdstPath);
228 return static_cast<jboolean>(isPass);
229 }
230
nativeTestIdempotentStart(JNIEnv * env,jobject,jstring jdstPath)231 static jboolean nativeTestIdempotentStart(JNIEnv* env, jobject, jstring jdstPath) {
232 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
233 FILE* ofp = fopen(cdstPath, "wbe+");
234 bool isPass = true;
235 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
236 AMediaFormat* format = AMediaFormat_new();
237 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
238 isPass &= AMediaMuxer_addTrack(muxer, format) >= 0;
239 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
240 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
241 ALOGE("error: double muxer.start succeeds");
242 isPass = false;
243 }
244 AMediaFormat_delete(format);
245 AMediaMuxer_delete(muxer);
246 fclose(ofp);
247 env->ReleaseStringUTFChars(jdstPath, cdstPath);
248 return static_cast<jboolean>(isPass);
249 }
250
nativeTestIfMuxerStartsAfterWriteSampleData(JNIEnv * env,jobject,jstring jdstPath)251 static jboolean nativeTestIfMuxerStartsAfterWriteSampleData(JNIEnv* env, jobject,
252 jstring jdstPath) {
253 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
254 FILE* ofp = fopen(cdstPath, "wbe+");
255 bool isPass = true;
256 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
257 AMediaFormat* format = AMediaFormat_new();
258 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
259 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
260 isPass &= trackID >= 0;
261 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
262 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
263 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
264 ALOGE("error: muxer.start succeeds after muxer.writeSampleData");
265 isPass = false;
266 }
267 AMediaFormat_delete(format);
268 AMediaMuxer_delete(muxer);
269 fclose(ofp);
270 env->ReleaseStringUTFChars(jdstPath, cdstPath);
271 return static_cast<jboolean>(isPass);
272 }
273
nativeTestIfMuxerStartsAfterStop(JNIEnv * env,jobject,jstring jdstPath)274 static jboolean nativeTestIfMuxerStartsAfterStop(JNIEnv* env, jobject, jstring jdstPath) {
275 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
276 FILE* ofp = fopen(cdstPath, "wbe+");
277 bool isPass = true;
278 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
279 AMediaFormat* format = AMediaFormat_new();
280 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
281 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
282 isPass &= trackID >= 0;
283 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
284 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
285 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
286 if (AMediaMuxer_start(muxer) == AMEDIA_OK) {
287 ALOGE("error: muxer.start succeeds after muxer.stop");
288 isPass = false;
289 }
290 AMediaFormat_delete(format);
291 AMediaMuxer_delete(muxer);
292 fclose(ofp);
293 env->ReleaseStringUTFChars(jdstPath, cdstPath);
294 return static_cast<jboolean>(isPass);
295 }
296
nativeTestStopOnANonStartedMuxer(JNIEnv * env,jobject,jstring jdstPath)297 static jboolean nativeTestStopOnANonStartedMuxer(JNIEnv* env, jobject, jstring jdstPath) {
298 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
299 FILE* ofp = fopen(cdstPath, "wbe+");
300 bool isPass = true;
301 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
302 AMediaFormat* format = AMediaFormat_new();
303 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
304 isPass &= AMediaMuxer_addTrack(muxer, format) >= 0;
305 if (AMEDIA_OK == AMediaMuxer_stop(muxer)) {
306 ALOGE("error: muxer.stop succeeds before muxer.start");
307 isPass = false;
308 }
309 AMediaFormat_delete(format);
310 AMediaMuxer_delete(muxer);
311 fclose(ofp);
312 env->ReleaseStringUTFChars(jdstPath, cdstPath);
313 return static_cast<jboolean>(isPass);
314 }
315
nativeTestIdempotentStop(JNIEnv * env,jobject,jstring jdstPath)316 static jboolean nativeTestIdempotentStop(JNIEnv* env, jobject, jstring jdstPath) {
317 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
318 FILE* ofp = fopen(cdstPath, "wbe+");
319 bool isPass = true;
320 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
321 AMediaFormat* format = AMediaFormat_new();
322 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
323 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
324 isPass &= trackID >= 0;
325 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
326 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
327 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
328 if (AMEDIA_OK == AMediaMuxer_stop(muxer)) {
329 ALOGE("error: double muxer.stop succeeds");
330 isPass = false;
331 }
332 AMediaFormat_delete(format);
333 AMediaMuxer_delete(muxer);
334 fclose(ofp);
335 env->ReleaseStringUTFChars(jdstPath, cdstPath);
336 return static_cast<jboolean>(isPass);
337 }
338
nativeTestSimpleStartStop(JNIEnv * env,jobject,jstring jdstPath)339 static jboolean nativeTestSimpleStartStop(JNIEnv* env, jobject, jstring jdstPath) {
340 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
341 FILE* ofp = fopen(cdstPath, "wbe+");
342 bool isPass = true;
343 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)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 &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
350 AMediaFormat_delete(format);
351 AMediaMuxer_delete(muxer);
352 fclose(ofp);
353 env->ReleaseStringUTFChars(jdstPath, cdstPath);
354 return static_cast<jboolean>(isPass);
355 }
356
nativeTestIfWriteSampleDataRejectsInvalidTrackIndex(JNIEnv * env,jobject,jstring jdstPath)357 static jboolean nativeTestIfWriteSampleDataRejectsInvalidTrackIndex(JNIEnv* env, jobject,
358 jstring jdstPath) {
359 bool isPass = true;
360 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
361 FILE* ofp = fopen(cdstPath, "wbe+");
362 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
363 AMediaFormat* format = AMediaFormat_new();
364 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
365 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
366 isPass &= trackID >= 0;
367 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
368 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
369 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, 22000, trackID + 1)) {
370 ALOGE("error: muxer.writeSampleData succeeds for invalid track ID");
371 isPass = false;
372 }
373 AMediaFormat_delete(format);
374 AMediaMuxer_delete(muxer);
375 fclose(ofp);
376 env->ReleaseStringUTFChars(jdstPath, cdstPath);
377 return static_cast<jboolean>(isPass);
378 }
379
nativeTestIfWriteSampleDataRejectsInvalidPts(JNIEnv * env,jobject,jstring jdstPath)380 static jboolean nativeTestIfWriteSampleDataRejectsInvalidPts(JNIEnv* env, jobject,
381 jstring jdstPath) {
382 bool isPass = true;
383 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
384 FILE* ofp = fopen(cdstPath, "wbe+");
385 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
386 AMediaFormat* format = AMediaFormat_new();
387 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
388 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
389 isPass &= trackID >= 0;
390 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
391 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
392 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, -33000, trackID)) {
393 ALOGE("error: muxer.writeSampleData succeeds for invalid pts");
394 isPass = false;
395 }
396 AMediaFormat_delete(format);
397 AMediaMuxer_delete(muxer);
398 fclose(ofp);
399 env->ReleaseStringUTFChars(jdstPath, cdstPath);
400 return static_cast<jboolean>(isPass);
401 }
402
nativeTestIfWriteSampleDataSucceedsBeforeStart(JNIEnv * env,jobject,jstring jdstPath)403 static jboolean nativeTestIfWriteSampleDataSucceedsBeforeStart(JNIEnv* env, jobject,
404 jstring jdstPath) {
405 bool isPass = true;
406 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
407 FILE* ofp = fopen(cdstPath, "wbe+");
408 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
409 AMediaFormat* format = AMediaFormat_new();
410 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
411 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
412 isPass &= trackID >= 0;
413 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, 0, trackID)) {
414 ALOGE("error: muxer.writeSampleData succeeds before muxer.start");
415 isPass = false;
416 }
417 AMediaFormat_delete(format);
418 AMediaMuxer_delete(muxer);
419 fclose(ofp);
420 env->ReleaseStringUTFChars(jdstPath, cdstPath);
421 return static_cast<jboolean>(isPass);
422 }
423
nativeTestIfWriteSampleDataSucceedsAfterStop(JNIEnv * env,jobject,jstring jdstPath)424 static jboolean nativeTestIfWriteSampleDataSucceedsAfterStop(JNIEnv* env, jobject,
425 jstring jdstPath) {
426 bool isPass = true;
427 const char* cdstPath = env->GetStringUTFChars(jdstPath, nullptr);
428 FILE* ofp = fopen(cdstPath, "wbe+");
429 AMediaMuxer* muxer = AMediaMuxer_new(fileno(ofp), (OutputFormat)OUTPUT_FORMAT_MPEG_4);
430 AMediaFormat* format = AMediaFormat_new();
431 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "application/x-subrip");
432 ssize_t trackID = AMediaMuxer_addTrack(muxer, format);
433 isPass &= trackID >= 0;
434 isPass &= AMediaMuxer_start(muxer) == AMEDIA_OK;
435 isPass &= insertPerFrameSubtitles(muxer, 0, trackID) == AMEDIA_OK;
436 isPass &= AMediaMuxer_stop(muxer) == AMEDIA_OK;
437 if (AMEDIA_OK == insertPerFrameSubtitles(muxer, 33000, trackID)) {
438 ALOGE("error: muxer.writeSampleData succeeds after muxer.stop");
439 isPass = false;
440 }
441 AMediaFormat_delete(format);
442 AMediaMuxer_delete(muxer);
443 fclose(ofp);
444 env->ReleaseStringUTFChars(jdstPath, cdstPath);
445 return static_cast<jboolean>(isPass);
446 }
447
registerAndroidMediaV2CtsMuxerUnitTestApi(JNIEnv * env)448 int registerAndroidMediaV2CtsMuxerUnitTestApi(JNIEnv* env) {
449 const JNINativeMethod methodTable[] = {
450 {"nativeTestIfInvalidFdIsRejected", "()Z", (void*)nativeTestIfInvalidFdIsRejected},
451 {"nativeTestIfReadOnlyFdIsRejected", "(Ljava/lang/String;)Z",
452 (void*)nativeTestIfReadOnlyFdIsRejected},
453 {"nativeTestIfNonSeekableFdIsRejected", "()Z",
454 (void*)nativeTestIfNonSeekableFdIsRejected},
455 {"nativeTestIfInvalidOutputFormatIsRejected", "(Ljava/lang/String;)Z",
456 (void*)nativeTestIfInvalidOutputFormatIsRejected},
457
458 {"nativeTestIfInvalidMediaFormatIsRejected", "(Ljava/lang/String;)Z",
459 (void*)nativeTestIfInvalidMediaFormatIsRejected},
460 {"nativeTestIfCorruptMediaFormatIsRejected", "(Ljava/lang/String;)Z",
461 (void*)nativeTestIfCorruptMediaFormatIsRejected},
462 {"nativeTestIfAddTrackSucceedsAfterStart", "(Ljava/lang/String;)Z",
463 (void*)nativeTestIfAddTrackSucceedsAfterStart},
464 {"nativeTestIfAddTrackSucceedsAfterWriteSampleData", "(Ljava/lang/String;)Z",
465 (void*)nativeTestIfAddTrackSucceedsAfterWriteSampleData},
466 {"nativeTestIfAddTrackSucceedsAfterStop", "(Ljava/lang/String;)Z",
467 (void*)nativeTestIfAddTrackSucceedsAfterStop},
468
469 {"nativeTestIfMuxerStartsBeforeAddTrack", "(Ljava/lang/String;)Z",
470 (void*)nativeTestIfMuxerStartsBeforeAddTrack},
471 {"nativeTestIdempotentStart", "(Ljava/lang/String;)Z",
472 (void*)nativeTestIdempotentStart},
473 {"nativeTestIfMuxerStartsAfterWriteSampleData", "(Ljava/lang/String;)Z",
474 (void*)nativeTestIfMuxerStartsAfterWriteSampleData},
475 {"nativeTestIfMuxerStartsAfterStop", "(Ljava/lang/String;)Z",
476 (void*)nativeTestIfMuxerStartsAfterStop},
477
478 {"nativeTestStopOnANonStartedMuxer", "(Ljava/lang/String;)Z",
479 (void*)nativeTestStopOnANonStartedMuxer},
480 {"nativeTestIdempotentStop", "(Ljava/lang/String;)Z", (void*)nativeTestIdempotentStop},
481 {"nativeTestSimpleStartStop", "(Ljava/lang/String;)Z",
482 (void*)nativeTestSimpleStartStop},
483
484 {"nativeTestIfWriteSampleDataRejectsInvalidTrackIndex", "(Ljava/lang/String;)Z",
485 (void*)nativeTestIfWriteSampleDataRejectsInvalidTrackIndex},
486 {"nativeTestIfWriteSampleDataRejectsInvalidPts", "(Ljava/lang/String;)Z",
487 (void*)nativeTestIfWriteSampleDataRejectsInvalidPts},
488 {"nativeTestIfWriteSampleDataSucceedsBeforeStart", "(Ljava/lang/String;)Z",
489 (void*)nativeTestIfWriteSampleDataSucceedsBeforeStart},
490 {"nativeTestIfWriteSampleDataSucceedsAfterStop", "(Ljava/lang/String;)Z",
491 (void*)nativeTestIfWriteSampleDataSucceedsAfterStop},
492 };
493 jclass c = env->FindClass("android/mediav2/cts/MuxerUnitTest$TestApiNative");
494 return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
495 }
496