flac_jni.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * Copyright (C) 2016 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. #include <android/log.h>
  17. #include <jni.h>
  18. #include <array>
  19. #include <cstdlib>
  20. #include <cstring>
  21. #include "include/flac_parser.h"
  22. #define LOG_TAG "flac_jni"
  23. #define ALOGE(...) \
  24. ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
  25. #define ALOGV(...) \
  26. ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
  27. #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
  28. extern "C" { \
  29. JNIEXPORT RETURN_TYPE \
  30. Java_com_google_android_exoplayer2_ext_flac_FlacDecoderJni_##NAME( \
  31. JNIEnv *env, jobject thiz, ##__VA_ARGS__); \
  32. } \
  33. JNIEXPORT RETURN_TYPE \
  34. Java_com_google_android_exoplayer2_ext_flac_FlacDecoderJni_##NAME( \
  35. JNIEnv *env, jobject thiz, ##__VA_ARGS__)
  36. class JavaDataSource : public DataSource {
  37. public:
  38. void setFlacDecoderJni(JNIEnv *env, jobject flacDecoderJni) {
  39. this->env = env;
  40. this->flacDecoderJni = flacDecoderJni;
  41. if (mid == NULL) {
  42. jclass cls = env->GetObjectClass(flacDecoderJni);
  43. mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I");
  44. }
  45. }
  46. ssize_t readAt(off64_t offset, void *const data, size_t size) {
  47. jobject byteBuffer = env->NewDirectByteBuffer(data, size);
  48. int result = env->CallIntMethod(flacDecoderJni, mid, byteBuffer);
  49. if (env->ExceptionCheck()) {
  50. // Exception is thrown in Java when returning from the native call.
  51. result = -1;
  52. }
  53. return result;
  54. }
  55. private:
  56. JNIEnv *env;
  57. jobject flacDecoderJni;
  58. jmethodID mid;
  59. };
  60. struct Context {
  61. JavaDataSource *source;
  62. FLACParser *parser;
  63. Context() {
  64. source = new JavaDataSource();
  65. parser = new FLACParser(source);
  66. }
  67. ~Context() {
  68. delete parser;
  69. delete source;
  70. }
  71. };
  72. DECODER_FUNC(jlong, flacInit) {
  73. Context *context = new Context;
  74. if (!context->parser->init()) {
  75. delete context;
  76. return 0;
  77. }
  78. return reinterpret_cast<intptr_t>(context);
  79. }
  80. DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
  81. Context *context = reinterpret_cast<Context *>(jContext);
  82. context->source->setFlacDecoderJni(env, thiz);
  83. if (!context->parser->decodeMetadata()) {
  84. return NULL;
  85. }
  86. jclass arrayListClass = env->FindClass("java/util/ArrayList");
  87. jmethodID arrayListConstructor =
  88. env->GetMethodID(arrayListClass, "<init>", "()V");
  89. jobject commentList = env->NewObject(arrayListClass, arrayListConstructor);
  90. jmethodID arrayListAddMethod =
  91. env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
  92. if (context->parser->areVorbisCommentsValid()) {
  93. std::vector<std::string> vorbisComments =
  94. context->parser->getVorbisComments();
  95. for (std::vector<std::string>::const_iterator vorbisComment =
  96. vorbisComments.begin();
  97. vorbisComment != vorbisComments.end(); ++vorbisComment) {
  98. jstring commentString = env->NewStringUTF((*vorbisComment).c_str());
  99. env->CallBooleanMethod(commentList, arrayListAddMethod, commentString);
  100. env->DeleteLocalRef(commentString);
  101. }
  102. }
  103. jobject pictureFrames = env->NewObject(arrayListClass, arrayListConstructor);
  104. bool picturesValid = context->parser->arePicturesValid();
  105. if (picturesValid) {
  106. std::vector<FlacPicture> pictures = context->parser->getPictures();
  107. jclass pictureFrameClass = env->FindClass(
  108. "com/google/android/exoplayer2/metadata/flac/PictureFrame");
  109. jmethodID pictureFrameConstructor =
  110. env->GetMethodID(pictureFrameClass, "<init>",
  111. "(ILjava/lang/String;Ljava/lang/String;IIII[B)V");
  112. for (std::vector<FlacPicture>::const_iterator picture = pictures.begin();
  113. picture != pictures.end(); ++picture) {
  114. jstring mimeType = env->NewStringUTF(picture->mimeType.c_str());
  115. jstring description = env->NewStringUTF(picture->description.c_str());
  116. jbyteArray pictureData = env->NewByteArray(picture->data.size());
  117. env->SetByteArrayRegion(pictureData, 0, picture->data.size(),
  118. (signed char *)&picture->data[0]);
  119. jobject pictureFrame = env->NewObject(
  120. pictureFrameClass, pictureFrameConstructor, picture->type, mimeType,
  121. description, picture->width, picture->height, picture->depth,
  122. picture->colors, pictureData);
  123. env->CallBooleanMethod(pictureFrames, arrayListAddMethod, pictureFrame);
  124. env->DeleteLocalRef(mimeType);
  125. env->DeleteLocalRef(description);
  126. env->DeleteLocalRef(pictureData);
  127. }
  128. }
  129. const FLAC__StreamMetadata_StreamInfo &streamInfo =
  130. context->parser->getStreamInfo();
  131. jclass flacStreamMetadataClass = env->FindClass(
  132. "com/google/android/exoplayer2/util/"
  133. "FlacStreamMetadata");
  134. jmethodID flacStreamMetadataConstructor =
  135. env->GetMethodID(flacStreamMetadataClass, "<init>",
  136. "(IIIIIIIJLjava/util/ArrayList;Ljava/util/ArrayList;)V");
  137. return env->NewObject(flacStreamMetadataClass, flacStreamMetadataConstructor,
  138. streamInfo.min_blocksize, streamInfo.max_blocksize,
  139. streamInfo.min_framesize, streamInfo.max_framesize,
  140. streamInfo.sample_rate, streamInfo.channels,
  141. streamInfo.bits_per_sample, streamInfo.total_samples,
  142. commentList, pictureFrames);
  143. }
  144. DECODER_FUNC(jint, flacDecodeToBuffer, jlong jContext, jobject jOutputBuffer) {
  145. Context *context = reinterpret_cast<Context *>(jContext);
  146. context->source->setFlacDecoderJni(env, thiz);
  147. void *outputBuffer = env->GetDirectBufferAddress(jOutputBuffer);
  148. jint outputSize = env->GetDirectBufferCapacity(jOutputBuffer);
  149. return context->parser->readBuffer(outputBuffer, outputSize);
  150. }
  151. DECODER_FUNC(jint, flacDecodeToArray, jlong jContext, jbyteArray jOutputArray) {
  152. Context *context = reinterpret_cast<Context *>(jContext);
  153. context->source->setFlacDecoderJni(env, thiz);
  154. jbyte *outputBuffer = env->GetByteArrayElements(jOutputArray, NULL);
  155. jint outputSize = env->GetArrayLength(jOutputArray);
  156. int count = context->parser->readBuffer(outputBuffer, outputSize);
  157. env->ReleaseByteArrayElements(jOutputArray, outputBuffer, 0);
  158. return count;
  159. }
  160. DECODER_FUNC(jlong, flacGetDecodePosition, jlong jContext) {
  161. Context *context = reinterpret_cast<Context *>(jContext);
  162. return context->parser->getDecodePosition();
  163. }
  164. DECODER_FUNC(jlong, flacGetLastFrameTimestamp, jlong jContext) {
  165. Context *context = reinterpret_cast<Context *>(jContext);
  166. return context->parser->getLastFrameTimestamp();
  167. }
  168. DECODER_FUNC(jlong, flacGetLastFrameFirstSampleIndex, jlong jContext) {
  169. Context *context = reinterpret_cast<Context *>(jContext);
  170. return context->parser->getLastFrameFirstSampleIndex();
  171. }
  172. DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) {
  173. Context *context = reinterpret_cast<Context *>(jContext);
  174. return context->parser->getNextFrameFirstSampleIndex();
  175. }
  176. DECODER_FUNC(jboolean, flacGetSeekPoints, jlong jContext, jlong timeUs,
  177. jlongArray outSeekPoints) {
  178. Context *context = reinterpret_cast<Context *>(jContext);
  179. std::array<int64_t, 4> result;
  180. bool success = context->parser->getSeekPositions(timeUs, result);
  181. if (success) {
  182. env->SetLongArrayRegion(outSeekPoints, 0, result.size(), result.data());
  183. }
  184. return success;
  185. }
  186. DECODER_FUNC(jstring, flacGetStateString, jlong jContext) {
  187. Context *context = reinterpret_cast<Context *>(jContext);
  188. const char *str = context->parser->getDecoderStateString();
  189. return env->NewStringUTF(str);
  190. }
  191. DECODER_FUNC(jboolean, flacIsDecoderAtEndOfStream, jlong jContext) {
  192. Context *context = reinterpret_cast<Context *>(jContext);
  193. return context->parser->isDecoderAtEndOfStream();
  194. }
  195. DECODER_FUNC(void, flacFlush, jlong jContext) {
  196. Context *context = reinterpret_cast<Context *>(jContext);
  197. context->parser->flush();
  198. }
  199. DECODER_FUNC(void, flacReset, jlong jContext, jlong newPosition) {
  200. Context *context = reinterpret_cast<Context *>(jContext);
  201. context->parser->reset(newPosition);
  202. }
  203. DECODER_FUNC(void, flacRelease, jlong jContext) {
  204. Context *context = reinterpret_cast<Context *>(jContext);
  205. delete context;
  206. }