1 /* 2 * Copyright (C) 2014 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 TAG "NativeMedia" 21 #include <log/log.h> 22 23 #include <assert.h> 24 #include <jni.h> 25 #include <pthread.h> 26 #include <stdio.h> 27 #include <string.h> 28 #include <unistd.h> 29 #include <semaphore.h> 30 31 #include <android/native_window_jni.h> 32 #include <EGL/egl.h> 33 #include <EGL/eglext.h> 34 35 #include "media/NdkMediaExtractor.h" 36 #include "media/NdkMediaCodec.h" 37 #include "media/NdkMediaCrypto.h" 38 #include "media/NdkMediaFormat.h" 39 #include "media/NdkMediaMuxer.h" 40 41 template <class T> 42 class simplevector { 43 T *storage; 44 int capacity; 45 int numfilled; 46 public: 47 simplevector() { 48 capacity = 16; 49 numfilled = 0; 50 storage = new T[capacity]; 51 } 52 ~simplevector() { 53 delete[] storage; 54 } 55 56 void add(T item) { 57 if (numfilled == capacity) { 58 T *old = storage; 59 capacity *= 2; 60 storage = new T[capacity]; 61 for (int i = 0; i < numfilled; i++) { 62 storage[i] = old[i]; 63 } 64 delete[] old; 65 } 66 storage[numfilled] = item; 67 numfilled++; 68 } 69 70 int size() { 71 return numfilled; 72 } 73 74 T* data() { 75 return storage; 76 } 77 }; 78 79 80 81 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) { 82 83 simplevector<int> sizes; 84 int numtracks = AMediaExtractor_getTrackCount(ex); 85 sizes.add(numtracks); 86 for (int i = 0; i < numtracks; i++) { 87 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i); 88 const char *s = AMediaFormat_toString(format); 89 ALOGI("track %d format: %s", i, s); 90 const char *mime; 91 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) { 92 ALOGE("no mime type"); 93 return NULL; 94 } else if (!strncmp(mime, "audio/", 6)) { 95 sizes.add(0); 96 int32_t val32; 97 int64_t val64; 98 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &val32); 99 sizes.add(val32); 100 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &val32); 101 sizes.add(val32); 102 AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64); 103 sizes.add(val64); 104 } else if (!strncmp(mime, "video/", 6)) { 105 sizes.add(1); 106 int32_t val32; 107 int64_t val64; 108 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &val32); 109 sizes.add(val32); 110 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &val32); 111 sizes.add(val32); 112 AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64); 113 sizes.add(val64); 114 } else { 115 ALOGE("expected audio or video mime type, got %s", mime); 116 } 117 AMediaFormat_delete(format); 118 AMediaExtractor_selectTrack(ex, i); 119 } 120 int bufsize = 1024*1024; 121 uint8_t *buf = new uint8_t[bufsize]; 122 while(true) { 123 int n = AMediaExtractor_readSampleData(ex, buf, bufsize); 124 if (n < 0) { 125 break; 126 } 127 sizes.add(n); 128 sizes.add(AMediaExtractor_getSampleTrackIndex(ex)); 129 sizes.add(AMediaExtractor_getSampleFlags(ex)); 130 sizes.add(AMediaExtractor_getSampleTime(ex)); 131 AMediaExtractor_advance(ex); 132 } 133 134 // allocate java int array for result and return it 135 int *data = sizes.data(); 136 int numsamples = sizes.size(); 137 jintArray ret = env->NewIntArray(numsamples); 138 jboolean isCopy; 139 jint *dst = env->GetIntArrayElements(ret, &isCopy); 140 for (int i = 0; i < numsamples; ++i) { 141 dst[i] = data[i]; 142 } 143 env->ReleaseIntArrayElements(ret, dst, 0); 144 145 delete[] buf; 146 AMediaExtractor_delete(ex); 147 return ret; 148 } 149 150 151 // get the sample sizes for the file 152 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv *env, 153 jclass /*clazz*/, int fd, jlong offset, jlong size) 154 { 155 AMediaExtractor *ex = AMediaExtractor_new(); 156 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size); 157 if (err != 0) { 158 ALOGE("setDataSource error: %d", err); 159 return NULL; 160 } 161 return testExtractor(ex, env); 162 } 163 164 // get the sample sizes for the path 165 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv *env, 166 jclass /*clazz*/, jstring jpath) 167 { 168 AMediaExtractor *ex = AMediaExtractor_new(); 169 170 const char *tmp = env->GetStringUTFChars(jpath, NULL); 171 if (tmp == NULL) { // Out of memory 172 return NULL; 173 } 174 175 int err = AMediaExtractor_setDataSource(ex, tmp); 176 177 env->ReleaseStringUTFChars(jpath, tmp); 178 179 if (err != 0) { 180 ALOGE("setDataSource error: %d", err); 181 return NULL; 182 } 183 return testExtractor(ex, env); 184 } 185 186 static int adler32(const uint8_t *input, int len) { 187 188 int a = 1; 189 int b = 0; 190 for (int i = 0; i < len; i++) { 191 a += input[i]; 192 b += a; 193 } 194 a = a % 65521; 195 b = b % 65521; 196 int ret = b * 65536 + a; 197 ALOGV("adler %d/%d", len, ret); 198 return ret; 199 } 200 201 static int checksum(const uint8_t *in, int len, AMediaFormat *format) { 202 int width, stride, height; 203 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) { 204 width = len; 205 } 206 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) { 207 stride = width; 208 } 209 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) { 210 height = 1; 211 } 212 uint8_t *bb = new uint8_t[width * height]; 213 for (int i = 0; i < height; i++) { 214 memcpy(bb + i * width, in + i * stride, width); 215 } 216 // bb is filled with data 217 int sum = adler32(bb, width * height); 218 delete[] bb; 219 return sum; 220 } 221 222 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv *env, 223 jclass /*clazz*/, int fd, jlong offset, jlong size) { 224 ALOGV("getDecodedDataNative"); 225 226 AMediaExtractor *ex = AMediaExtractor_new(); 227 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size); 228 if (err != 0) { 229 ALOGE("setDataSource error: %d", err); 230 return NULL; 231 } 232 233 int numtracks = AMediaExtractor_getTrackCount(ex); 234 235 AMediaCodec **codec = new AMediaCodec*[numtracks]; 236 AMediaFormat **format = new AMediaFormat*[numtracks]; 237 bool *sawInputEOS = new bool[numtracks]; 238 bool *sawOutputEOS = new bool[numtracks]; 239 simplevector<int> *sizes = new simplevector<int>[numtracks]; 240 241 ALOGV("input has %d tracks", numtracks); 242 for (int i = 0; i < numtracks; i++) { 243 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i); 244 const char *s = AMediaFormat_toString(format); 245 ALOGI("track %d format: %s", i, s); 246 const char *mime; 247 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) { 248 ALOGE("no mime type"); 249 return NULL; 250 } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) { 251 codec[i] = AMediaCodec_createDecoderByType(mime); 252 AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0); 253 AMediaCodec_start(codec[i]); 254 sawInputEOS[i] = false; 255 sawOutputEOS[i] = false; 256 } else { 257 ALOGE("expected audio or video mime type, got %s", mime); 258 return NULL; 259 } 260 AMediaFormat_delete(format); 261 AMediaExtractor_selectTrack(ex, i); 262 } 263 int eosCount = 0; 264 while(eosCount < numtracks) { 265 int t = AMediaExtractor_getSampleTrackIndex(ex); 266 if (t >=0) { 267 ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000); 268 ALOGV("track %d, input buffer %zd", t, bufidx); 269 if (bufidx >= 0) { 270 size_t bufsize; 271 uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize); 272 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize); 273 ALOGV("read %d", sampleSize); 274 if (sampleSize < 0) { 275 sampleSize = 0; 276 sawInputEOS[t] = true; 277 ALOGV("EOS"); 278 //break; 279 } 280 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex); 281 282 AMediaCodec_queueInputBuffer(codec[t], bufidx, 0, sampleSize, presentationTimeUs, 283 sawInputEOS[t] ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0); 284 AMediaExtractor_advance(ex); 285 } 286 } else { 287 ALOGV("@@@@ no more input samples"); 288 for (int tt = 0; tt < numtracks; tt++) { 289 if (!sawInputEOS[tt]) { 290 // we ran out of samples without ever signaling EOS to the codec, 291 // so do that now 292 int bufidx = AMediaCodec_dequeueInputBuffer(codec[tt], 5000); 293 if (bufidx >= 0) { 294 AMediaCodec_queueInputBuffer(codec[tt], bufidx, 0, 0, 0, 295 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); 296 sawInputEOS[tt] = true; 297 } 298 } 299 } 300 } 301 302 // check all codecs for available data 303 AMediaCodecBufferInfo info; 304 for (int tt = 0; tt < numtracks; tt++) { 305 if (!sawOutputEOS[tt]) { 306 int status = AMediaCodec_dequeueOutputBuffer(codec[tt], &info, 1); 307 ALOGV("dequeueoutput on track %d: %d", tt, status); 308 if (status >= 0) { 309 if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { 310 ALOGV("EOS on track %d", tt); 311 sawOutputEOS[tt] = true; 312 eosCount++; 313 } 314 ALOGV("got decoded buffer for track %d, size %d", tt, info.size); 315 if (info.size > 0) { 316 size_t bufsize; 317 uint8_t *buf = AMediaCodec_getOutputBuffer(codec[tt], status, &bufsize); 318 int adler = checksum(buf, info.size, format[tt]); 319 sizes[tt].add(adler); 320 } 321 AMediaCodec_releaseOutputBuffer(codec[tt], status, false); 322 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) { 323 ALOGV("output buffers changed for track %d", tt); 324 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) { 325 format[tt] = AMediaCodec_getOutputFormat(codec[tt]); 326 ALOGV("format changed for track %d: %s", tt, AMediaFormat_toString(format[tt])); 327 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) { 328 ALOGV("no output buffer right now for track %d", tt); 329 } else { 330 ALOGV("unexpected info code for track %d : %d", tt, status); 331 } 332 } else { 333 ALOGV("already at EOS on track %d", tt); 334 } 335 } 336 } 337 ALOGV("decoding loop done"); 338 339 // allocate java int array for result and return it 340 int numsamples = 0; 341 for (int i = 0; i < numtracks; i++) { 342 numsamples += sizes[i].size(); 343 } 344 ALOGV("checksums: %d", numsamples); 345 jintArray ret = env->NewIntArray(numsamples); 346 jboolean isCopy; 347 jint *org = env->GetIntArrayElements(ret, &isCopy); 348 jint *dst = org; 349 for (int i = 0; i < numtracks; i++) { 350 int *data = sizes[i].data(); 351 int len = sizes[i].size(); 352 ALOGV("copying %d", len); 353 for (int j = 0; j < len; j++) { 354 *dst++ = data[j]; 355 } 356 } 357 env->ReleaseIntArrayElements(ret, org, 0); 358 359 delete[] sizes; 360 delete[] sawOutputEOS; 361 delete[] sawInputEOS; 362 for (int i = 0; i < numtracks; i++) { 363 AMediaFormat_delete(format[i]); 364 AMediaCodec_stop(codec[i]); 365 AMediaCodec_delete(codec[i]); 366 } 367 delete[] format; 368 delete[] codec; 369 AMediaExtractor_delete(ex); 370 return ret; 371 } 372 373 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv *env, 374 jclass /*clazz*/, jobject surface, int fd, jlong offset, jlong size) { 375 376 ANativeWindow *window = ANativeWindow_fromSurface(env, surface); 377 ALOGI("@@@@ native window: %p", window); 378 379 AMediaExtractor *ex = AMediaExtractor_new(); 380 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size); 381 if (err != 0) { 382 ALOGE("setDataSource error: %d", err); 383 return false; 384 } 385 386 int numtracks = AMediaExtractor_getTrackCount(ex); 387 388 AMediaCodec *codec = NULL; 389 AMediaFormat *format = NULL; 390 bool sawInputEOS = false; 391 bool sawOutputEOS = false; 392 393 ALOGV("input has %d tracks", numtracks); 394 for (int i = 0; i < numtracks; i++) { 395 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i); 396 const char *s = AMediaFormat_toString(format); 397 ALOGI("track %d format: %s", i, s); 398 const char *mime; 399 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) { 400 ALOGE("no mime type"); 401 return false; 402 } else if (!strncmp(mime, "video/", 6)) { 403 codec = AMediaCodec_createDecoderByType(mime); 404 AMediaCodec_configure(codec, format, window, NULL, 0); 405 AMediaCodec_start(codec); 406 AMediaExtractor_selectTrack(ex, i); 407 } 408 AMediaFormat_delete(format); 409 } 410 411 while (!sawOutputEOS) { 412 ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000); 413 ALOGV("input buffer %zd", bufidx); 414 if (bufidx >= 0) { 415 size_t bufsize; 416 uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize); 417 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize); 418 ALOGV("read %d", sampleSize); 419 if (sampleSize < 0) { 420 sampleSize = 0; 421 sawInputEOS = true; 422 ALOGV("EOS"); 423 } 424 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex); 425 426 AMediaCodec_queueInputBuffer(codec, bufidx, 0, sampleSize, presentationTimeUs, 427 sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0); 428 AMediaExtractor_advance(ex); 429 } 430 431 AMediaCodecBufferInfo info; 432 int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1); 433 ALOGV("dequeueoutput returned: %d", status); 434 if (status >= 0) { 435 if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { 436 ALOGV("output EOS"); 437 sawOutputEOS = true; 438 } 439 ALOGV("got decoded buffer size %d", info.size); 440 AMediaCodec_releaseOutputBuffer(codec, status, true); 441 usleep(20000); 442 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) { 443 ALOGV("output buffers changed"); 444 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) { 445 format = AMediaCodec_getOutputFormat(codec); 446 ALOGV("format changed to: %s", AMediaFormat_toString(format)); 447 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) { 448 ALOGV("no output buffer right now"); 449 } else { 450 ALOGV("unexpected info code: %d", status); 451 } 452 } 453 454 AMediaCodec_stop(codec); 455 AMediaCodec_delete(codec); 456 AMediaExtractor_delete(ex); 457 return true; 458 } 459 460 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv */*env*/, 461 jclass /*clazz*/, int infd, jlong inoffset, jlong insize, int outfd, jboolean webm) { 462 463 464 AMediaMuxer *muxer = AMediaMuxer_new(outfd, 465 webm ? AMEDIAMUXER_OUTPUT_FORMAT_WEBM : AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4); 466 467 AMediaExtractor *ex = AMediaExtractor_new(); 468 int err = AMediaExtractor_setDataSourceFd(ex, infd, inoffset, insize); 469 if (err != 0) { 470 ALOGE("setDataSource error: %d", err); 471 return false; 472 } 473 474 int numtracks = AMediaExtractor_getTrackCount(ex); 475 ALOGI("input tracks: %d", numtracks); 476 for (int i = 0; i < numtracks; i++) { 477 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i); 478 const char *s = AMediaFormat_toString(format); 479 ALOGI("track %d format: %s", i, s); 480 const char *mime; 481 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) { 482 ALOGE("no mime type"); 483 return false; 484 } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) { 485 ssize_t tidx = AMediaMuxer_addTrack(muxer, format); 486 ALOGI("track %d -> %zd format %s", i, tidx, s); 487 AMediaExtractor_selectTrack(ex, i); 488 } else { 489 ALOGE("expected audio or video mime type, got %s", mime); 490 return false; 491 } 492 AMediaFormat_delete(format); 493 AMediaExtractor_selectTrack(ex, i); 494 } 495 AMediaMuxer_start(muxer); 496 497 int bufsize = 1024*1024; 498 uint8_t *buf = new uint8_t[bufsize]; 499 AMediaCodecBufferInfo info; 500 while(true) { 501 int n = AMediaExtractor_readSampleData(ex, buf, bufsize); 502 if (n < 0) { 503 break; 504 } 505 info.offset = 0; 506 info.size = n; 507 info.presentationTimeUs = AMediaExtractor_getSampleTime(ex); 508 info.flags = AMediaExtractor_getSampleFlags(ex); 509 510 size_t idx = (size_t) AMediaExtractor_getSampleTrackIndex(ex); 511 AMediaMuxer_writeSampleData(muxer, idx, buf, &info); 512 513 AMediaExtractor_advance(ex); 514 } 515 516 AMediaExtractor_delete(ex); 517 AMediaMuxer_stop(muxer); 518 AMediaMuxer_delete(muxer); 519 return true; 520 521 } 522 523 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/, 524 jclass /*clazz*/) { 525 AMediaFormat* format = AMediaFormat_new(); 526 if (!format) { 527 return false; 528 } 529 530 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 8000); 531 int32_t bitrate = 0; 532 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate) || bitrate != 8000) { 533 ALOGE("AMediaFormat_getInt32 fail: %d", bitrate); 534 return false; 535 } 536 537 AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, 123456789123456789ll); 538 int64_t duration = 0; 539 if (!AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &duration) 540 || duration != 123456789123456789ll) { 541 ALOGE("AMediaFormat_getInt64 fail: %lld", (long long) duration); 542 return false; 543 } 544 545 AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, 25.0f); 546 float framerate = 0.0f; 547 if (!AMediaFormat_getFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, &framerate) 548 || framerate != 25.0f) { 549 ALOGE("AMediaFormat_getFloat fail: %f", framerate); 550 return false; 551 } 552 553 const char* value = "audio/mpeg"; 554 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, value); 555 const char* readback = NULL; 556 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &readback) 557 || strcmp(value, readback) || value == readback) { 558 ALOGE("AMediaFormat_getString fail"); 559 return false; 560 } 561 562 uint32_t foo = 0xdeadbeef; 563 AMediaFormat_setBuffer(format, "csd-0", &foo, sizeof(foo)); 564 foo = 0xabadcafe; 565 void *bytes; 566 size_t bytesize = 0; 567 if(!AMediaFormat_getBuffer(format, "csd-0", &bytes, &bytesize) 568 || bytesize != sizeof(foo) || *((uint32_t*)bytes) != 0xdeadbeef) { 569 ALOGE("AMediaFormat_getBuffer fail"); 570 return false; 571 } 572 573 return true; 574 } 575 576 577 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/, 578 jclass /*clazz*/, int fd, jlong offset, jlong size) { 579 580 AMediaExtractor *ex = AMediaExtractor_new(); 581 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size); 582 if (err != 0) { 583 ALOGE("setDataSource error: %d", err); 584 return false; 585 } 586 587 PsshInfo* info = AMediaExtractor_getPsshInfo(ex); 588 if (info == NULL) { 589 ALOGI("null pssh"); 590 return false; 591 } 592 593 ALOGI("pssh has %zd entries", info->numentries); 594 if (info->numentries != 2) { 595 return false; 596 } 597 598 for (size_t i = 0; i < info->numentries; i++) { 599 PsshEntry *entry = &info->entries[i]; 600 ALOGI("entry uuid %02x%02x..%02x%02x, data size %zd", 601 entry->uuid[0], 602 entry->uuid[1], 603 entry->uuid[14], 604 entry->uuid[15], 605 entry->datalen); 606 607 AMediaCrypto *crypto = AMediaCrypto_new(entry->uuid, entry->data, entry->datalen); 608 if (crypto) { 609 ALOGI("got crypto"); 610 AMediaCrypto_delete(crypto); 611 } else { 612 ALOGI("no crypto"); 613 } 614 } 615 return true; 616 } 617 618 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/, 619 jclass /*clazz*/) { 620 621 size_t numsubsamples = 4; 622 uint8_t key[16] = { 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 }; 623 uint8_t iv[16] = { 4,3,2,1,4,3,2,1,4,3,2,1,4,3,2,1 }; 624 size_t clearbytes[4] = { 5, 6, 7, 8 }; 625 size_t encryptedbytes[4] = { 8, 7, 6, 5 }; 626 627 AMediaCodecCryptoInfo *ci = 628 AMediaCodecCryptoInfo_new(numsubsamples, key, iv, AMEDIACODECRYPTOINFO_MODE_CLEAR, clearbytes, encryptedbytes); 629 630 if (AMediaCodecCryptoInfo_getNumSubSamples(ci) != 4) { 631 ALOGE("numsubsamples mismatch"); 632 return false; 633 } 634 uint8_t bytes[16]; 635 AMediaCodecCryptoInfo_getKey(ci, bytes); 636 if (memcmp(key, bytes, 16) != 0) { 637 ALOGE("key mismatch"); 638 return false; 639 } 640 AMediaCodecCryptoInfo_getIV(ci, bytes); 641 if (memcmp(iv, bytes, 16) != 0) { 642 ALOGE("IV mismatch"); 643 return false; 644 } 645 if (AMediaCodecCryptoInfo_getMode(ci) != AMEDIACODECRYPTOINFO_MODE_CLEAR) { 646 ALOGE("mode mismatch"); 647 return false; 648 } 649 size_t sizes[numsubsamples]; 650 AMediaCodecCryptoInfo_getClearBytes(ci, sizes); 651 if (memcmp(clearbytes, sizes, sizeof(size_t) * numsubsamples)) { 652 ALOGE("clear size mismatch"); 653 return false; 654 } 655 AMediaCodecCryptoInfo_getEncryptedBytes(ci, sizes); 656 if (memcmp(encryptedbytes, sizes, sizeof(size_t) * numsubsamples)) { 657 ALOGE("encrypted size mismatch"); 658 return false; 659 } 660 return true; 661 } 662 663 // === NdkMediaCodec 664 665 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateCodecByName( 666 JNIEnv *env, jclass /*clazz*/, jstring name) { 667 668 if (name == NULL) { 669 return 0; 670 } 671 672 const char *tmp = env->GetStringUTFChars(name, NULL); 673 if (tmp == NULL) { 674 return 0; 675 } 676 677 AMediaCodec *codec = AMediaCodec_createCodecByName(tmp); 678 if (codec == NULL) { 679 env->ReleaseStringUTFChars(name, tmp); 680 return 0; 681 } 682 683 env->ReleaseStringUTFChars(name, tmp); 684 return reinterpret_cast<jlong>(codec); 685 686 } 687 688 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecDelete( 689 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) { 690 media_status_t err = AMediaCodec_delete(reinterpret_cast<AMediaCodec *>(codec)); 691 return err == AMEDIA_OK; 692 } 693 694 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStart( 695 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) { 696 media_status_t err = AMediaCodec_start(reinterpret_cast<AMediaCodec *>(codec)); 697 return err == AMEDIA_OK; 698 } 699 700 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStop( 701 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) { 702 media_status_t err = AMediaCodec_stop(reinterpret_cast<AMediaCodec *>(codec)); 703 return err == AMEDIA_OK; 704 } 705 706 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecConfigure( 707 JNIEnv *env, 708 jclass /*clazz*/, 709 jlong codec, 710 jstring mime, 711 jint width, 712 jint height, 713 jint colorFormat, 714 jint bitRate, 715 jint frameRate, 716 jint iFrameInterval, 717 jobject csd, 718 jint flags) { 719 720 AMediaFormat* format = AMediaFormat_new(); 721 if (format == NULL) { 722 return false; 723 } 724 725 const char *tmp = env->GetStringUTFChars(mime, NULL); 726 if (tmp == NULL) { 727 AMediaFormat_delete(format); 728 return false; 729 } 730 731 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, tmp); 732 env->ReleaseStringUTFChars(mime, tmp); 733 734 const char *keys[] = { 735 AMEDIAFORMAT_KEY_WIDTH, 736 AMEDIAFORMAT_KEY_HEIGHT, 737 AMEDIAFORMAT_KEY_COLOR_FORMAT, 738 AMEDIAFORMAT_KEY_BIT_RATE, 739 AMEDIAFORMAT_KEY_FRAME_RATE, 740 AMEDIAFORMAT_KEY_I_FRAME_INTERVAL 741 }; 742 743 jint values[] = {width, height, colorFormat, bitRate, frameRate, iFrameInterval}; 744 for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) { 745 if (values[i] >= 0) { 746 AMediaFormat_setInt32(format, keys[i], values[i]); 747 } 748 } 749 750 if (csd != NULL) { 751 void *csdPtr = env->GetDirectBufferAddress(csd); 752 jlong csdSize = env->GetDirectBufferCapacity(csd); 753 AMediaFormat_setBuffer(format, "csd-0", csdPtr, csdSize); 754 } 755 756 media_status_t err = AMediaCodec_configure( 757 reinterpret_cast<AMediaCodec *>(codec), 758 format, 759 NULL, 760 NULL, 761 flags); 762 763 AMediaFormat_delete(format); 764 return err == AMEDIA_OK; 765 766 } 767 768 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface( 769 JNIEnv* env, jclass /*clazz*/, jlong codec, jobject surface) { 770 771 media_status_t err = AMediaCodec_setInputSurface( 772 reinterpret_cast<AMediaCodec *>(codec), 773 ANativeWindow_fromSurface(env, surface)); 774 775 return err == AMEDIA_OK; 776 777 } 778 779 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface( 780 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong nativeWindow) { 781 782 media_status_t err = AMediaCodec_setInputSurface( 783 reinterpret_cast<AMediaCodec *>(codec), 784 reinterpret_cast<ANativeWindow *>(nativeWindow)); 785 786 return err == AMEDIA_OK; 787 788 } 789 790 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface( 791 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) { 792 793 ANativeWindow *nativeWindow; 794 media_status_t err = AMediaCodec_createInputSurface( 795 reinterpret_cast<AMediaCodec *>(codec), 796 &nativeWindow); 797 798 if (err == AMEDIA_OK) { 799 return reinterpret_cast<jlong>(nativeWindow); 800 } 801 802 return 0; 803 804 } 805 806 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface( 807 JNIEnv* /*env*/, jclass /*clazz*/) { 808 809 ANativeWindow *nativeWindow; 810 media_status_t err = AMediaCodec_createPersistentInputSurface(&nativeWindow); 811 812 if (err == AMEDIA_OK) { 813 return reinterpret_cast<jlong>(nativeWindow); 814 } 815 816 return 0; 817 818 } 819 820 extern "C" jstring Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString( 821 JNIEnv* env, jclass /*clazz*/, jlong codec) { 822 823 AMediaFormat *format = AMediaCodec_getOutputFormat(reinterpret_cast<AMediaCodec *>(codec)); 824 const char *str = AMediaFormat_toString(format); 825 jstring jstr = env->NewStringUTF(str); 826 AMediaFormat_delete(format); 827 return jstr; 828 829 } 830 831 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream( 832 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) { 833 834 media_status_t err = AMediaCodec_signalEndOfInputStream(reinterpret_cast<AMediaCodec *>(codec)); 835 return err == AMEDIA_OK; 836 837 } 838 839 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer( 840 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jint index, jboolean render) { 841 842 media_status_t err = AMediaCodec_releaseOutputBuffer( 843 reinterpret_cast<AMediaCodec *>(codec), 844 index, 845 render); 846 847 return err == AMEDIA_OK; 848 849 } 850 851 static jobject AMediaCodecGetBuffer( 852 JNIEnv* env, 853 jlong codec, 854 jint index, 855 uint8_t *(*getBuffer)(AMediaCodec*, size_t, size_t*)) { 856 857 size_t bufsize; 858 uint8_t *buf = getBuffer( 859 reinterpret_cast<AMediaCodec *>(codec), 860 index, 861 &bufsize); 862 863 return env->NewDirectByteBuffer(buf, bufsize); 864 865 } 866 867 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer( 868 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) { 869 870 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getOutputBuffer); 871 872 } 873 874 extern "C" jlongArray Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer( 875 JNIEnv* env, jclass /*clazz*/, jlong codec, jlong timeoutUs) { 876 877 AMediaCodecBufferInfo info; 878 memset(&info, 0, sizeof(info)); 879 int status = AMediaCodec_dequeueOutputBuffer( 880 reinterpret_cast<AMediaCodec *>(codec), 881 &info, 882 timeoutUs); 883 884 jlong ret[5] = {0}; 885 ret[0] = status; 886 ret[1] = 0; // NdkMediaCodec calls ABuffer::data, which already adds offset 887 ret[2] = info.size; 888 ret[3] = info.presentationTimeUs; 889 ret[4] = info.flags; 890 891 jlongArray jret = env->NewLongArray(5); 892 env->SetLongArrayRegion(jret, 0, 5, ret); 893 return jret; 894 895 } 896 897 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer( 898 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) { 899 900 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getInputBuffer); 901 902 } 903 904 extern "C" jint Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer( 905 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong timeoutUs) { 906 907 return AMediaCodec_dequeueInputBuffer( 908 reinterpret_cast<AMediaCodec *>(codec), 909 timeoutUs); 910 911 } 912 913 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer( 914 JNIEnv* /*env*/, 915 jclass /*clazz*/, 916 jlong codec, 917 jint index, 918 jint offset, 919 jint size, 920 jlong presentationTimeUs, 921 jint flags) { 922 923 media_status_t err = AMediaCodec_queueInputBuffer( 924 reinterpret_cast<AMediaCodec *>(codec), 925 index, 926 offset, 927 size, 928 presentationTimeUs, 929 flags); 930 931 return err == AMEDIA_OK; 932 933 } 934 935 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter( 936 JNIEnv* env, jclass /*clazz*/, jlong codec, jstring jkey, jint value) { 937 938 AMediaFormat* params = AMediaFormat_new(); 939 if (params == NULL) { 940 return false; 941 } 942 943 const char *key = env->GetStringUTFChars(jkey, NULL); 944 if (key == NULL) { 945 AMediaFormat_delete(params); 946 return false; 947 } 948 949 AMediaFormat_setInt32(params, key, value); 950 media_status_t err = AMediaCodec_setParameters( 951 reinterpret_cast<AMediaCodec *>(codec), 952 params); 953 env->ReleaseStringUTFChars(jkey, key); 954 AMediaFormat_delete(params); 955 return err == AMEDIA_OK; 956 957 } 958 959 // === NdkInputSurface 960 961 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglGetDisplay(JNIEnv * /*env*/, jclass /*clazz*/) { 962 963 EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 964 if (eglDisplay == EGL_NO_DISPLAY) { 965 return 0; 966 } 967 968 EGLint major, minor; 969 if (!eglInitialize(eglDisplay, &major, &minor)) { 970 return 0; 971 } 972 973 return reinterpret_cast<jlong>(eglDisplay); 974 975 } 976 977 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglChooseConfig( 978 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay) { 979 980 // Configure EGL for recordable and OpenGL ES 2.0. We want enough RGB bits 981 // to minimize artifacts from possible YUV conversion. 982 EGLint attribList[] = { 983 EGL_RED_SIZE, 8, 984 EGL_GREEN_SIZE, 8, 985 EGL_BLUE_SIZE, 8, 986 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 987 EGL_RECORDABLE_ANDROID, 1, 988 EGL_NONE 989 }; 990 991 EGLConfig configs[1]; 992 EGLint numConfigs[1]; 993 if (!eglChooseConfig(reinterpret_cast<EGLDisplay>(eglDisplay), attribList, configs, 1, numConfigs)) { 994 return 0; 995 } 996 return reinterpret_cast<jlong>(configs[0]); 997 998 } 999 1000 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglCreateContext( 1001 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig) { 1002 1003 // Configure context for OpenGL ES 2.0. 1004 int attrib_list[] = { 1005 EGL_CONTEXT_CLIENT_VERSION, 2, 1006 EGL_NONE 1007 }; 1008 1009 EGLConfig eglContext = eglCreateContext( 1010 reinterpret_cast<EGLDisplay>(eglDisplay), 1011 reinterpret_cast<EGLConfig>(eglConfig), 1012 EGL_NO_CONTEXT, 1013 attrib_list); 1014 1015 if (eglGetError() != EGL_SUCCESS) { 1016 return 0; 1017 } 1018 1019 return reinterpret_cast<jlong>(eglContext); 1020 1021 } 1022 1023 extern "C" jlong Java_android_media_cts_NdkInputSurface_createEGLSurface( 1024 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig, jlong nativeWindow) { 1025 1026 int surfaceAttribs[] = {EGL_NONE}; 1027 EGLSurface eglSurface = eglCreateWindowSurface( 1028 reinterpret_cast<EGLDisplay>(eglDisplay), 1029 reinterpret_cast<EGLConfig>(eglConfig), 1030 reinterpret_cast<EGLNativeWindowType>(nativeWindow), 1031 surfaceAttribs); 1032 1033 if (eglGetError() != EGL_SUCCESS) { 1034 return 0; 1035 } 1036 1037 return reinterpret_cast<jlong>(eglSurface); 1038 1039 } 1040 1041 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglMakeCurrent( 1042 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext) { 1043 1044 return eglMakeCurrent( 1045 reinterpret_cast<EGLDisplay>(eglDisplay), 1046 reinterpret_cast<EGLSurface>(eglSurface), 1047 reinterpret_cast<EGLSurface>(eglSurface), 1048 reinterpret_cast<EGLContext>(eglContext)); 1049 1050 } 1051 1052 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglSwapBuffers( 1053 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) { 1054 1055 return eglSwapBuffers( 1056 reinterpret_cast<EGLDisplay>(eglDisplay), 1057 reinterpret_cast<EGLSurface>(eglSurface)); 1058 1059 } 1060 1061 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglPresentationTimeANDROID( 1062 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong nsecs) { 1063 1064 return eglPresentationTimeANDROID( 1065 reinterpret_cast<EGLDisplay>(eglDisplay), 1066 reinterpret_cast<EGLSurface>(eglSurface), 1067 reinterpret_cast<EGLnsecsANDROID>(nsecs)); 1068 1069 } 1070 1071 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetWidth( 1072 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) { 1073 1074 EGLint width; 1075 eglQuerySurface( 1076 reinterpret_cast<EGLDisplay>(eglDisplay), 1077 reinterpret_cast<EGLSurface>(eglSurface), 1078 EGL_WIDTH, 1079 &width); 1080 1081 return width; 1082 1083 } 1084 1085 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetHeight( 1086 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) { 1087 1088 EGLint height; 1089 eglQuerySurface( 1090 reinterpret_cast<EGLDisplay>(eglDisplay), 1091 reinterpret_cast<EGLSurface>(eglSurface), 1092 EGL_HEIGHT, 1093 &height); 1094 1095 return height; 1096 1097 } 1098 1099 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglDestroySurface( 1100 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) { 1101 1102 return eglDestroySurface( 1103 reinterpret_cast<EGLDisplay>(eglDisplay), 1104 reinterpret_cast<EGLSurface>(eglSurface)); 1105 1106 } 1107 1108 extern "C" void Java_android_media_cts_NdkInputSurface_nativeRelease( 1109 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext, jlong nativeWindow) { 1110 1111 if (eglDisplay != 0) { 1112 1113 EGLDisplay _eglDisplay = reinterpret_cast<EGLDisplay>(eglDisplay); 1114 EGLSurface _eglSurface = reinterpret_cast<EGLSurface>(eglSurface); 1115 EGLContext _eglContext = reinterpret_cast<EGLContext>(eglContext); 1116 1117 eglDestroySurface(_eglDisplay, _eglSurface); 1118 eglDestroyContext(_eglDisplay, _eglContext); 1119 eglReleaseThread(); 1120 eglTerminate(_eglDisplay); 1121 1122 } 1123 1124 ANativeWindow_release(reinterpret_cast<ANativeWindow *>(nativeWindow)); 1125 1126 } 1127