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 "NativeExtractorUnitTest"
19 #include <log/log.h>
20 
21 #include <NdkMediaExtractor.h>
22 #include <jni.h>
23 #include <sys/stat.h>
24 
25 #include <cstdlib>
26 #include <cstring>
27 
setExtractorDataSource(AMediaExtractor * extractor,FILE * fp)28 static media_status_t setExtractorDataSource(AMediaExtractor* extractor, FILE* fp) {
29     media_status_t status = AMEDIA_ERROR_BASE;
30     struct stat buf {};
31     if (fp && !fstat(fileno(fp), &buf))
32         status = AMediaExtractor_setDataSourceFd(extractor, fileno(fp), 0, buf.st_size);
33     if (status != AMEDIA_OK) ALOGE("error: AMediaExtractor_setDataSourceFd failed %d", status);
34     return status;
35 }
36 
nativeTestGetTrackCountBeforeSetDataSource(JNIEnv *,jobject)37 static jboolean nativeTestGetTrackCountBeforeSetDataSource(JNIEnv*, jobject) {
38     AMediaExtractor* extractor = AMediaExtractor_new();
39     bool isPass = (0 == AMediaExtractor_getTrackCount(extractor));
40     if (!isPass) ALOGE("error: received valid trackCount before setDataSource");
41     AMediaExtractor_delete(extractor);
42     return static_cast<jboolean>(isPass);
43 }
44 
nativeTestSelectTrackBeforeSetDataSource(JNIEnv *,jobject)45 static jboolean nativeTestSelectTrackBeforeSetDataSource(JNIEnv*, jobject) {
46     AMediaExtractor* extractor = AMediaExtractor_new();
47     bool isPass = (AMEDIA_OK != AMediaExtractor_selectTrack(extractor, 0));
48     if (!isPass) ALOGE("error: selectTrack succeeds before setDataSource");
49     AMediaExtractor_delete(extractor);
50     return static_cast<jboolean>(isPass);
51 }
52 
nativeTestSelectTrackForInvalidIndex(JNIEnv * env,jobject,jstring jsrcPath)53 static jboolean nativeTestSelectTrackForInvalidIndex(JNIEnv* env, jobject, jstring jsrcPath) {
54     bool isPass = false;
55     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
56     AMediaExtractor* extractor = AMediaExtractor_new();
57     FILE* srcFp = fopen(csrcPath, "rbe");
58     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
59         if (AMEDIA_OK !=
60             AMediaExtractor_selectTrack(extractor, AMediaExtractor_getTrackCount(extractor))) {
61             isPass = true;
62         } else {
63             ALOGE("error: selectTrack succeeds for out of bounds track index: %zu",
64                   AMediaExtractor_getTrackCount(extractor));
65         }
66     }
67     AMediaExtractor_delete(extractor);
68     if (srcFp) fclose(srcFp);
69     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
70     return static_cast<jboolean>(isPass);
71 }
72 
nativeTestIdempotentSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)73 static jboolean nativeTestIdempotentSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
74     bool isPass = false;
75     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
76     AMediaExtractor* extractor = AMediaExtractor_new();
77     FILE* srcFp = fopen(csrcPath, "rbe");
78     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
79         isPass = AMediaExtractor_selectTrack(extractor, 0) == AMEDIA_OK;
80         isPass &= AMediaExtractor_selectTrack(extractor, 0) == AMEDIA_OK;
81         if (!isPass) ALOGE("error: multiple selection of same track has failed");
82     }
83     AMediaExtractor_delete(extractor);
84     if (srcFp) fclose(srcFp);
85     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
86     return static_cast<jboolean>(isPass);
87 }
88 
nativeTestUnselectTrackBeforeSetDataSource(JNIEnv *,jobject)89 static jboolean nativeTestUnselectTrackBeforeSetDataSource(JNIEnv*, jobject) {
90     AMediaExtractor* extractor = AMediaExtractor_new();
91     bool isPass = (AMEDIA_OK != AMediaExtractor_unselectTrack(extractor, 0));
92     if (!isPass) ALOGE("error: unselectTrack succeeds before setDataSource");
93     AMediaExtractor_delete(extractor);
94     return static_cast<jboolean>(isPass);
95 }
96 
nativeTestUnselectTrackForInvalidIndex(JNIEnv * env,jobject,jstring jsrcPath)97 static jboolean nativeTestUnselectTrackForInvalidIndex(JNIEnv* env, jobject, jstring jsrcPath) {
98     bool isPass = false;
99     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
100     AMediaExtractor* extractor = AMediaExtractor_new();
101     FILE* srcFp = fopen(csrcPath, "rbe");
102     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
103         if (AMEDIA_OK !=
104             AMediaExtractor_unselectTrack(extractor, AMediaExtractor_getTrackCount(extractor))) {
105             isPass = true;
106         } else {
107             ALOGE("error: unselectTrack succeeds for out of bounds track index: %zu",
108                   AMediaExtractor_getTrackCount(extractor));
109         }
110     }
111     AMediaExtractor_delete(extractor);
112     if (srcFp) fclose(srcFp);
113     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
114     return static_cast<jboolean>(isPass);
115 }
116 
nativeTestUnselectTrackForUnSelectedTrackIndex(JNIEnv * env,jobject,jstring jsrcPath)117 static jboolean nativeTestUnselectTrackForUnSelectedTrackIndex(JNIEnv* env, jobject,
118                                                                jstring jsrcPath) {
119     bool isPass = false;
120     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
121     AMediaExtractor* extractor = AMediaExtractor_new();
122     FILE* srcFp = fopen(csrcPath, "rbe");
123     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
124         isPass = (AMediaExtractor_unselectTrack(extractor, 0) == AMEDIA_OK);
125         if (!isPass) ALOGE("error: un-selection of non-selected track has failed");
126     }
127     AMediaExtractor_delete(extractor);
128     if (srcFp) fclose(srcFp);
129     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
130     return static_cast<jboolean>(isPass);
131 }
132 
nativeTestIdempotentUnselectTrack(JNIEnv * env,jobject,jstring jsrcPath)133 static jboolean nativeTestIdempotentUnselectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
134     bool isPass = false;
135     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
136     AMediaExtractor* extractor = AMediaExtractor_new();
137     FILE* srcFp = fopen(csrcPath, "rbe");
138     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
139         isPass = AMediaExtractor_selectTrack(extractor, 0) == AMEDIA_OK;
140         if (isPass) {
141             isPass = AMediaExtractor_unselectTrack(extractor, 0) == AMEDIA_OK;
142             isPass &= AMediaExtractor_unselectTrack(extractor, 0) == AMEDIA_OK;
143             if (!isPass) ALOGE("error: multiple unselection of selected track has failed");
144         } else {
145             ALOGE("error: selection of track 0 has failed for file %s", csrcPath);
146         }
147     }
148     AMediaExtractor_delete(extractor);
149     if (srcFp) fclose(srcFp);
150     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
151     return static_cast<jboolean>(isPass);
152 }
153 
nativeTestSeekToBeforeSetDataSource(JNIEnv *,jobject)154 static jboolean nativeTestSeekToBeforeSetDataSource(JNIEnv*, jobject) {
155     AMediaExtractor* extractor = AMediaExtractor_new();
156     bool isPass = AMediaExtractor_seekTo(extractor, 0, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC) != AMEDIA_OK;
157     if (!isPass) ALOGE("error: seekTo() succeeds before setting data source");
158     AMediaExtractor_delete(extractor);
159     return static_cast<jboolean>(isPass);
160 }
161 
nativeTestSeekToBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)162 static jboolean nativeTestSeekToBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
163     bool isPass = false;
164     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
165     AMediaExtractor* extractor = AMediaExtractor_new();
166     FILE* srcFp = fopen(csrcPath, "rbe");
167     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
168         isPass = AMediaExtractor_seekTo(extractor, 0, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC) != AMEDIA_OK;
169         if (!isPass) ALOGE("error: seekTo() succeeds before selecting track");
170     }
171     AMediaExtractor_delete(extractor);
172     if (srcFp) fclose(srcFp);
173     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
174     return static_cast<jboolean>(isPass);
175 }
176 
nativeTestGetCachedDurationBeforeSetDataSource(JNIEnv *,jobject)177 static jboolean nativeTestGetCachedDurationBeforeSetDataSource(JNIEnv*, jobject) {
178     AMediaExtractor* extractor = AMediaExtractor_new();
179     bool isPass = AMediaExtractor_getCachedDuration(extractor) == -1;
180     if (!isPass) ALOGE("error: getCachedDuration returns unexpected value before setDataSource");
181     AMediaExtractor_delete(extractor);
182     return static_cast<jboolean>(isPass);
183 }
184 
nativeTestIfGetFileFormatSucceedsBeforeSetDataSource(JNIEnv *,jobject)185 static jboolean nativeTestIfGetFileFormatSucceedsBeforeSetDataSource(JNIEnv*, jobject) {
186     AMediaExtractor* extractor = AMediaExtractor_new();
187     AMediaFormat* empty = AMediaFormat_new();
188     AMediaFormat* format = AMediaExtractor_getFileFormat(extractor);
189     bool isPass = true;
190     if (format == nullptr ||
191         strcmp(AMediaFormat_toString(empty), AMediaFormat_toString(format)) != 0) {
192         isPass = false;
193         ALOGE("error: getFileFormat before set data source yields unexpected result");
194     }
195     if (format) AMediaFormat_delete(format);
196     AMediaFormat_delete(empty);
197     AMediaExtractor_delete(extractor);
198     return static_cast<jboolean>(isPass);
199 }
200 
nativeTestAdvanceBeforeSetDataSource(JNIEnv *,jobject)201 static jboolean nativeTestAdvanceBeforeSetDataSource(JNIEnv*, jobject) {
202     AMediaExtractor* extractor = AMediaExtractor_new();
203     bool isPass = !AMediaExtractor_advance(extractor);
204     if (!isPass) ALOGE("error: advance succeeds before setDataSource");
205     AMediaExtractor_delete(extractor);
206     return static_cast<jboolean>(isPass);
207 }
208 
nativeTestAdvanceBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)209 static jboolean nativeTestAdvanceBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
210     bool isPass = false;
211     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
212     AMediaExtractor* extractor = AMediaExtractor_new();
213     FILE* srcFp = fopen(csrcPath, "rbe");
214     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
215         isPass = !AMediaExtractor_advance(extractor);
216         if (!isPass) ALOGE("error: advance succeeds without any active tracks");
217     }
218     AMediaExtractor_delete(extractor);
219     if (srcFp) fclose(srcFp);
220     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
221     return static_cast<jboolean>(isPass);
222 }
223 
nativeTestGetSampleFlagsBeforeSetDataSource(JNIEnv *,jobject)224 static jboolean nativeTestGetSampleFlagsBeforeSetDataSource(JNIEnv*, jobject) {
225     AMediaExtractor* extractor = AMediaExtractor_new();
226     bool isPass = AMediaExtractor_getSampleFlags(extractor) == -1;
227     if (!isPass) ALOGE("error: received valid sample flag before setDataSource");
228     AMediaExtractor_delete(extractor);
229     return static_cast<jboolean>(isPass);
230 }
231 
nativeTestGetSampleFlagsBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)232 static jboolean nativeTestGetSampleFlagsBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
233     bool isPass = false;
234     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
235     AMediaExtractor* extractor = AMediaExtractor_new();
236     FILE* srcFp = fopen(csrcPath, "rbe");
237     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
238         isPass = AMediaExtractor_getSampleFlags(extractor) == -1;
239         if (!isPass) ALOGE("error: received valid sample flag without any active tracks");
240     }
241     AMediaExtractor_delete(extractor);
242     if (srcFp) fclose(srcFp);
243     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
244     return static_cast<jboolean>(isPass);
245 }
246 
nativeTestGetSampleTimeBeforeSetDataSource(JNIEnv *,jobject)247 static jboolean nativeTestGetSampleTimeBeforeSetDataSource(JNIEnv*, jobject) {
248     AMediaExtractor* extractor = AMediaExtractor_new();
249     bool isPass = AMediaExtractor_getSampleTime(extractor) == -1;
250     if (!isPass) ALOGE("error: received valid pts before setDataSource");
251     AMediaExtractor_delete(extractor);
252     return static_cast<jboolean>(isPass);
253 }
254 
nativeTestGetSampleTimeBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)255 static jboolean nativeTestGetSampleTimeBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
256     bool isPass = false;
257     AMediaExtractor* extractor = AMediaExtractor_new();
258     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
259     FILE* srcFp = fopen(csrcPath, "rbe");
260     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
261         isPass = AMediaExtractor_getSampleTime(extractor) == -1;
262         if (!isPass) ALOGE("error: received valid pts without any active tracks");
263     }
264     AMediaExtractor_delete(extractor);
265     if (srcFp) fclose(srcFp);
266     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
267     return static_cast<jboolean>(isPass);
268 }
269 
nativeTestGetSampleSizeBeforeSetDataSource(JNIEnv *,jobject)270 static jboolean nativeTestGetSampleSizeBeforeSetDataSource(JNIEnv*, jobject) {
271     AMediaExtractor* extractor = AMediaExtractor_new();
272     bool isPass = AMediaExtractor_getSampleSize(extractor) == -1;
273     if (!isPass) ALOGE("error: received valid sample size before setDataSource");
274     AMediaExtractor_delete(extractor);
275     return static_cast<jboolean>(isPass);
276 }
277 
nativeTestGetSampleSizeBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)278 static jboolean nativeTestGetSampleSizeBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
279     bool isPass = false;
280     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
281     AMediaExtractor* extractor = AMediaExtractor_new();
282     FILE* srcFp = fopen(csrcPath, "rbe");
283     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
284         isPass = AMediaExtractor_getSampleSize(extractor) == -1;
285         if (!isPass) ALOGE("error: received valid sample size without any active tracks");
286     }
287     AMediaExtractor_delete(extractor);
288     if (srcFp) fclose(srcFp);
289     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
290     return static_cast<jboolean>(isPass);
291 }
292 
nativeTestIfGetSampleFormatBeforeSetDataSource(JNIEnv *,jobject)293 static jboolean nativeTestIfGetSampleFormatBeforeSetDataSource(JNIEnv*, jobject) {
294     AMediaExtractor* extractor = AMediaExtractor_new();
295     AMediaFormat* format = AMediaFormat_new();
296     bool isPass = AMediaExtractor_getSampleFormat(extractor, format) != AMEDIA_OK;
297     if (!isPass) ALOGE("error: getSampleFormat succeeds before setDataSource");
298     AMediaFormat_delete(format);
299     AMediaExtractor_delete(extractor);
300     return static_cast<jboolean>(isPass);
301 }
302 
nativeTestIfGetSampleFormatBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)303 static jboolean nativeTestIfGetSampleFormatBeforeSelectTrack(JNIEnv* env, jobject,
304                                                              jstring jsrcPath) {
305     bool isPass = false;
306     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
307     AMediaExtractor* extractor = AMediaExtractor_new();
308     AMediaFormat* format = AMediaFormat_new();
309     FILE* srcFp = fopen(csrcPath, "rbe");
310     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
311         isPass = AMediaExtractor_getSampleFormat(extractor, format) != AMEDIA_OK;
312         if (!isPass) ALOGE("error: getSampleFormat succeeds without any active tracks");
313     }
314     AMediaFormat_delete(format);
315     AMediaExtractor_delete(extractor);
316     if (srcFp) fclose(srcFp);
317     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
318     return static_cast<jboolean>(isPass);
319 }
320 
nativeTestVideoSampleFileOffsetByGetSampleFormat(JNIEnv * env,jobject,jstring jsrcPath)321 static jboolean nativeTestVideoSampleFileOffsetByGetSampleFormat(JNIEnv* env, jobject,
322                                                              jstring jsrcPath) {
323     int64_t video_sample_offsets[] = {6522, 95521, 118719, 126219, 137578};
324     bool isPass = true;
325     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
326     AMediaExtractor* extractor = AMediaExtractor_new();
327     AMediaFormat* format = AMediaFormat_new();
328     FILE* srcFp = fopen(csrcPath, "rbe");
329     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
330         if (AMEDIA_OK == AMediaExtractor_selectTrack(extractor, 0 /* video */)) {
331             for(int i = 0; i < sizeof(video_sample_offsets)/sizeof(int64_t); ++i) {
332                 if (AMEDIA_OK == AMediaExtractor_getSampleFormat(extractor, format)) {
333                     ALOGV("AMediaFormat_toString:%s", AMediaFormat_toString(format));
334                     int64_t offset = 0;
335                     if (AMediaFormat_getInt64(format, "sample-file-offset", &offset)) {
336                         if (offset != video_sample_offsets[i]) {
337                             ALOGD("offset:%lld, video_sample_offsets[%d]:%lld",
338                                         (long long)offset, i, (long long)video_sample_offsets[i]);
339                             isPass = false;
340                             break;
341                         }
342                     } else {
343                         ALOGD("error: sample-file-offset not found");
344                         isPass = false;
345                         break;
346                     }
347                 }
348                 AMediaExtractor_advance(extractor);
349             }
350         }
351     }
352     AMediaExtractor_delete(extractor);
353     AMediaFormat_delete(format);
354     if (srcFp) fclose(srcFp);
355     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
356     return static_cast<jboolean>(isPass);
357 }
358 
nativeTestAudioSampleFileOffsetByGetSampleFormat(JNIEnv * env,jobject,jstring jsrcPath)359 static jboolean nativeTestAudioSampleFileOffsetByGetSampleFormat(JNIEnv* env, jobject,
360                                                              jstring jsrcPath) {
361     int64_t audio_sample_offsets[] = {186125, 186682, 187286, 187944, 188551};
362     bool isPass = true;
363     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
364     AMediaExtractor* extractor = AMediaExtractor_new();
365     AMediaFormat* format = AMediaFormat_new();
366     FILE* srcFp = fopen(csrcPath, "rbe");
367     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
368         if (AMEDIA_OK == AMediaExtractor_selectTrack(extractor, 1 /* audio */)) {
369             for(int i = 0; i < sizeof(audio_sample_offsets)/sizeof(int64_t); ++i) {
370                 if (AMEDIA_OK == AMediaExtractor_getSampleFormat(extractor, format)) {
371                     ALOGV("AMediaFormat_toString:%s", AMediaFormat_toString(format));
372                     int64_t offset = 0;
373                     if (AMediaFormat_getInt64(format, "sample-file-offset", &offset)) {
374                         if (offset != audio_sample_offsets[i]) {
375                             ALOGD("offset:%lld, audio_sample_offsets[%d]:%lld",
376                                         (long long)offset, i, (long long)audio_sample_offsets[i]);
377                             isPass = false;
378                             break;
379                         }
380                     } else {
381                         ALOGE("error: sample-file-offset not found");
382                         isPass = false;
383                         break;
384                     }
385                 }
386                 AMediaExtractor_advance(extractor);
387             }
388         }
389     }
390     AMediaExtractor_delete(extractor);
391     AMediaFormat_delete(format);
392     if (srcFp) fclose(srcFp);
393     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
394     return static_cast<jboolean>(isPass);
395 }
396 
nativeTestGetSampleTrackIndexBeforeSetDataSource(JNIEnv *,jobject)397 static jboolean nativeTestGetSampleTrackIndexBeforeSetDataSource(JNIEnv*, jobject) {
398     AMediaExtractor* extractor = AMediaExtractor_new();
399     bool isPass = AMediaExtractor_getSampleTrackIndex(extractor) == -1;
400     if (!isPass) ALOGE("error: received valid track index before setDataSource");
401     AMediaExtractor_delete(extractor);
402     return static_cast<jboolean>(isPass);
403 }
404 
nativeTestGetSampleTrackIndexBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)405 static jboolean nativeTestGetSampleTrackIndexBeforeSelectTrack(JNIEnv* env, jobject,
406                                                                jstring jsrcPath) {
407     bool isPass = false;
408     AMediaExtractor* extractor = AMediaExtractor_new();
409     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
410     FILE* srcFp = fopen(csrcPath, "rbe");
411     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
412         isPass = AMediaExtractor_getSampleTrackIndex(extractor) == -1;
413         if (!isPass) ALOGE("error: received valid track index without any active tracks");
414     }
415     AMediaExtractor_delete(extractor);
416     if (srcFp) fclose(srcFp);
417     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
418     return static_cast<jboolean>(isPass);
419 }
420 
nativeTestGetTrackFormatBeforeSetDataSource(JNIEnv *,jobject)421 static jboolean nativeTestGetTrackFormatBeforeSetDataSource(JNIEnv*, jobject) {
422     bool isPass = true;
423     AMediaExtractor* extractor = AMediaExtractor_new();
424     AMediaFormat* empty = AMediaFormat_new();
425     AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, 0);
426     if (format == nullptr ||
427         strcmp(AMediaFormat_toString(empty), AMediaFormat_toString(format)) != 0) {
428         isPass = false;
429         ALOGE("error: getTrackFormat before setDataSource yields unexpected result");
430     }
431     if (format) AMediaFormat_delete(format);
432     AMediaFormat_delete(empty);
433     AMediaExtractor_delete(extractor);
434     return static_cast<jboolean>(isPass);
435 }
436 
nativeTestGetTrackFormatForInvalidIndex(JNIEnv * env,jobject,jstring jsrcPath)437 static jboolean nativeTestGetTrackFormatForInvalidIndex(JNIEnv* env, jobject, jstring jsrcPath) {
438     bool isPass = true;
439     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
440     AMediaExtractor* extractor = AMediaExtractor_new();
441     FILE* srcFp = fopen(csrcPath, "rbe");
442     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
443         AMediaFormat* format =
444                 AMediaExtractor_getTrackFormat(extractor, AMediaExtractor_getTrackCount(extractor));
445         AMediaFormat* empty = AMediaFormat_new();
446         if (format == nullptr ||
447             strcmp(AMediaFormat_toString(empty), AMediaFormat_toString(format)) != 0) {
448             isPass = false;
449             ALOGE("error: getTrackFormat for out of bound track index %zu yields unexpected result",
450                   AMediaExtractor_getTrackCount(extractor));
451         }
452         if (format) AMediaFormat_delete(format);
453         AMediaFormat_delete(empty);
454     } else {
455         isPass = false;
456     }
457     AMediaExtractor_delete(extractor);
458     if (srcFp) fclose(srcFp);
459     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
460     return static_cast<jboolean>(isPass);
461 }
462 
nativeTestReadSampleDataBeforeSetDataSource(JNIEnv *,jobject)463 static jboolean nativeTestReadSampleDataBeforeSetDataSource(JNIEnv*, jobject) {
464     AMediaExtractor* extractor = AMediaExtractor_new();
465     const int maxSampleSize = 512 * 1024;
466     auto buffer = new uint8_t[maxSampleSize];
467     bool isPass = AMediaExtractor_readSampleData(extractor, buffer, maxSampleSize) < 0;
468     if (!isPass) ALOGE("error: readSampleData return non-negative readBytes before setDataSource");
469     delete[] buffer;
470     AMediaExtractor_delete(extractor);
471     return static_cast<jboolean>(isPass);
472 }
473 
nativeTestReadSampleDataBeforeSelectTrack(JNIEnv * env,jobject,jstring jsrcPath)474 static jboolean nativeTestReadSampleDataBeforeSelectTrack(JNIEnv* env, jobject, jstring jsrcPath) {
475     bool isPass = false;
476     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
477     AMediaExtractor* extractor = AMediaExtractor_new();
478     const int maxSampleSize = (512 * 1024);
479     auto buffer = new uint8_t[maxSampleSize];
480     FILE* srcFp = fopen(csrcPath, "rbe");
481     if (AMEDIA_OK == setExtractorDataSource(extractor, srcFp)) {
482         isPass = AMediaExtractor_readSampleData(extractor, buffer, maxSampleSize) < 0;
483         if (!isPass) {
484             ALOGE("error: readSampleData returns non-negative readBytes with out active tracks");
485         }
486     }
487     delete[] buffer;
488     AMediaExtractor_delete(extractor);
489     if (srcFp) fclose(srcFp);
490     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
491     return static_cast<jboolean>(isPass);
492 }
493 
nativeTestIfNullLocationIsRejectedBySetDataSource(JNIEnv *,jobject)494 static jboolean nativeTestIfNullLocationIsRejectedBySetDataSource(JNIEnv*, jobject) {
495     AMediaExtractor* extractor = AMediaExtractor_new();
496     bool isPass = AMediaExtractor_setDataSource(extractor, nullptr) != AMEDIA_OK;
497     if (!isPass) ALOGE("error: setDataSource succeeds with null location");
498     AMediaExtractor_delete(extractor);
499     return static_cast<jboolean>(isPass);
500 }
501 
registerAndroidMediaV2CtsExtractorUnitTestApi(JNIEnv * env)502 int registerAndroidMediaV2CtsExtractorUnitTestApi(JNIEnv* env) {
503     const JNINativeMethod methodTable[] = {
504             {"nativeTestGetTrackCountBeforeSetDataSource", "()Z",
505              (void*)nativeTestGetTrackCountBeforeSetDataSource},
506             {"nativeTestSelectTrackBeforeSetDataSource", "()Z",
507              (void*)nativeTestSelectTrackBeforeSetDataSource},
508             {"nativeTestSelectTrackForInvalidIndex", "(Ljava/lang/String;)Z",
509              (void*)nativeTestSelectTrackForInvalidIndex},
510             {"nativeTestIdempotentSelectTrack", "(Ljava/lang/String;)Z",
511              (void*)nativeTestIdempotentSelectTrack},
512             {"nativeTestUnselectTrackBeforeSetDataSource", "()Z",
513              (void*)nativeTestUnselectTrackBeforeSetDataSource},
514             {"nativeTestUnselectTrackForInvalidIndex", "(Ljava/lang/String;)Z",
515              (void*)nativeTestUnselectTrackForInvalidIndex},
516             {"nativeTestUnselectTrackForUnSelectedTrackIndex", "(Ljava/lang/String;)Z",
517              (void*)nativeTestUnselectTrackForUnSelectedTrackIndex},
518             {"nativeTestIdempotentUnselectTrack", "(Ljava/lang/String;)Z",
519              (void*)nativeTestIdempotentUnselectTrack},
520             {"nativeTestSeekToBeforeSetDataSource", "()Z",
521              (void*)nativeTestSeekToBeforeSetDataSource},
522             {"nativeTestSeekToBeforeSelectTrack", "(Ljava/lang/String;)Z",
523              (void*)nativeTestSeekToBeforeSelectTrack},
524             {"nativeTestGetCachedDurationBeforeSetDataSource", "()Z",
525              (void*)nativeTestGetCachedDurationBeforeSetDataSource},
526             {"nativeTestIfGetFileFormatSucceedsBeforeSetDataSource", "()Z",
527              (void*)nativeTestIfGetFileFormatSucceedsBeforeSetDataSource},
528             {"nativeTestAdvanceBeforeSetDataSource", "()Z",
529              (void*)nativeTestAdvanceBeforeSetDataSource},
530             {"nativeTestAdvanceBeforeSelectTrack", "(Ljava/lang/String;)Z",
531              (void*)nativeTestAdvanceBeforeSelectTrack},
532             {"nativeTestGetSampleFlagsBeforeSetDataSource", "()Z",
533              (void*)nativeTestGetSampleFlagsBeforeSetDataSource},
534             {"nativeTestGetSampleFlagsBeforeSelectTrack", "(Ljava/lang/String;)Z",
535              (void*)nativeTestGetSampleFlagsBeforeSelectTrack},
536             {"nativeTestGetSampleTimeBeforeSetDataSource", "()Z",
537              (void*)nativeTestGetSampleTimeBeforeSetDataSource},
538             {"nativeTestGetSampleTimeBeforeSelectTrack", "(Ljava/lang/String;)Z",
539              (void*)nativeTestGetSampleTimeBeforeSelectTrack},
540             {"nativeTestGetSampleSizeBeforeSetDataSource", "()Z",
541              (void*)nativeTestGetSampleSizeBeforeSetDataSource},
542             {"nativeTestGetSampleSizeBeforeSelectTrack", "(Ljava/lang/String;)Z",
543              (void*)nativeTestGetSampleSizeBeforeSelectTrack},
544             {"nativeTestIfGetSampleFormatBeforeSetDataSource", "()Z",
545              (void*)nativeTestIfGetSampleFormatBeforeSetDataSource},
546             {"nativeTestIfGetSampleFormatBeforeSelectTrack", "(Ljava/lang/String;)Z",
547              (void*)nativeTestIfGetSampleFormatBeforeSelectTrack},
548             {"nativeTestGetSampleTrackIndexBeforeSetDataSource", "()Z",
549              (void*)nativeTestGetSampleTrackIndexBeforeSetDataSource},
550             {"nativeTestGetSampleTrackIndexBeforeSelectTrack", "(Ljava/lang/String;)Z",
551              (void*)nativeTestGetSampleTrackIndexBeforeSelectTrack},
552             {"nativeTestGetTrackFormatBeforeSetDataSource", "()Z",
553              (void*)nativeTestGetTrackFormatBeforeSetDataSource},
554             {"nativeTestGetTrackFormatForInvalidIndex", "(Ljava/lang/String;)Z",
555              (void*)nativeTestGetTrackFormatForInvalidIndex},
556             {"nativeTestReadSampleDataBeforeSetDataSource", "()Z",
557              (void*)nativeTestReadSampleDataBeforeSetDataSource},
558             {"nativeTestReadSampleDataBeforeSelectTrack", "(Ljava/lang/String;)Z",
559              (void*)nativeTestReadSampleDataBeforeSelectTrack},
560             {"nativeTestIfNullLocationIsRejectedBySetDataSource", "()Z",
561              (void*)nativeTestIfNullLocationIsRejectedBySetDataSource},
562             {"nativeTestVideoSampleFileOffsetByGetSampleFormat", "(Ljava/lang/String;)Z",
563              (void*)nativeTestVideoSampleFileOffsetByGetSampleFormat},
564             {"nativeTestAudioSampleFileOffsetByGetSampleFormat", "(Ljava/lang/String;)Z",
565              (void*)nativeTestAudioSampleFileOffsetByGetSampleFormat},
566     };
567     jclass c = env->FindClass("android/mediav2/cts/ExtractorUnitTest$TestApiNative");
568     return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
569 }
570