Telegram-Android/TMessagesProj/jni/exoplayer/flac_jni.cc

240 lines
9 KiB
C++
Raw Normal View History

2018-07-30 04:07:02 +02:00
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2019-01-23 18:03:33 +01:00
#include <android/log.h>
2019-12-31 14:08:08 +01:00
#include <jni.h>
#include <array>
2018-07-30 04:07:02 +02:00
#include <cstdlib>
2019-12-31 14:08:08 +01:00
#include <cstring>
2018-07-30 04:07:02 +02:00
#include "include/flac_parser.h"
2019-01-23 18:03:33 +01:00
#define LOG_TAG "flac_jni"
#define ALOGE(...) \
((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#define ALOGV(...) \
((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
2023-04-03 15:15:52 +02:00
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
extern "C" { \
JNIEXPORT RETURN_TYPE \
2019-01-23 18:03:33 +01:00
Java_com_google_android_exoplayer2_ext_flac_FlacDecoderJni_##NAME( \
2023-04-03 15:15:52 +02:00
JNIEnv *env, jobject thiz, ##__VA_ARGS__); \
} \
JNIEXPORT RETURN_TYPE \
2019-01-23 18:03:33 +01:00
Java_com_google_android_exoplayer2_ext_flac_FlacDecoderJni_##NAME( \
JNIEnv *env, jobject thiz, ##__VA_ARGS__)
2018-07-30 04:07:02 +02:00
class JavaDataSource : public DataSource {
2020-07-26 10:03:38 +02:00
public:
void setFlacDecoderJni(JNIEnv *env, jobject flacDecoderJni) {
this->env = env;
this->flacDecoderJni = flacDecoderJni;
if (mid == NULL) {
jclass cls = env->GetObjectClass(flacDecoderJni);
mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I");
2023-04-03 15:15:52 +02:00
env->DeleteLocalRef(cls);
2020-07-26 10:03:38 +02:00
}
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
2020-07-26 10:03:38 +02:00
ssize_t readAt(off64_t offset, void *const data, size_t size) {
jobject byteBuffer = env->NewDirectByteBuffer(data, size);
int result = env->CallIntMethod(flacDecoderJni, mid, byteBuffer);
if (env->ExceptionCheck()) {
// Exception is thrown in Java when returning from the native call.
result = -1;
}
2023-04-03 15:15:52 +02:00
env->DeleteLocalRef(byteBuffer);
2020-07-26 10:03:38 +02:00
return result;
2018-07-30 04:07:02 +02:00
}
2019-01-23 18:03:33 +01:00
2020-07-26 10:03:38 +02:00
private:
JNIEnv *env;
jobject flacDecoderJni;
jmethodID mid;
2018-07-30 04:07:02 +02:00
};
struct Context {
2020-07-26 10:03:38 +02:00
JavaDataSource *source;
FLACParser *parser;
2019-01-23 18:03:33 +01:00
2020-07-26 10:03:38 +02:00
Context() {
source = new JavaDataSource();
parser = new FLACParser(source);
}
2019-01-23 18:03:33 +01:00
2020-07-26 10:03:38 +02:00
~Context() {
delete parser;
delete source;
}
2018-07-30 04:07:02 +02:00
};
DECODER_FUNC(jlong, flacInit) {
2019-01-23 18:03:33 +01:00
Context *context = new Context;
if (!context->parser->init()) {
delete context;
return 0;
}
return reinterpret_cast<intptr_t>(context);
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
context->source->setFlacDecoderJni(env, thiz);
if (!context->parser->decodeMetadata()) {
return NULL;
}
2019-12-31 14:08:08 +01:00
jclass arrayListClass = env->FindClass("java/util/ArrayList");
jmethodID arrayListConstructor =
2020-07-26 10:03:38 +02:00
env->GetMethodID(arrayListClass, "<init>", "()V");
2019-12-31 14:08:08 +01:00
jobject commentList = env->NewObject(arrayListClass, arrayListConstructor);
jmethodID arrayListAddMethod =
2020-07-26 10:03:38 +02:00
env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
2019-12-31 14:08:08 +01:00
if (context->parser->areVorbisCommentsValid()) {
std::vector<std::string> vorbisComments =
2020-07-26 10:03:38 +02:00
context->parser->getVorbisComments();
2019-12-31 14:08:08 +01:00
for (std::vector<std::string>::const_iterator vorbisComment =
2020-07-26 10:03:38 +02:00
vorbisComments.begin();
2019-12-31 14:08:08 +01:00
vorbisComment != vorbisComments.end(); ++vorbisComment) {
jstring commentString = env->NewStringUTF((*vorbisComment).c_str());
env->CallBooleanMethod(commentList, arrayListAddMethod, commentString);
env->DeleteLocalRef(commentString);
}
}
jobject pictureFrames = env->NewObject(arrayListClass, arrayListConstructor);
bool picturesValid = context->parser->arePicturesValid();
if (picturesValid) {
std::vector<FlacPicture> pictures = context->parser->getPictures();
jclass pictureFrameClass = env->FindClass(
2020-07-26 10:03:38 +02:00
"com/google/android/exoplayer2/metadata/flac/PictureFrame");
2019-12-31 14:08:08 +01:00
jmethodID pictureFrameConstructor =
2020-07-26 10:03:38 +02:00
env->GetMethodID(pictureFrameClass, "<init>",
"(ILjava/lang/String;Ljava/lang/String;IIII[B)V");
2019-12-31 14:08:08 +01:00
for (std::vector<FlacPicture>::const_iterator picture = pictures.begin();
picture != pictures.end(); ++picture) {
jstring mimeType = env->NewStringUTF(picture->mimeType.c_str());
jstring description = env->NewStringUTF(picture->description.c_str());
jbyteArray pictureData = env->NewByteArray(picture->data.size());
env->SetByteArrayRegion(pictureData, 0, picture->data.size(),
(signed char *)&picture->data[0]);
jobject pictureFrame = env->NewObject(
2020-07-26 10:03:38 +02:00
pictureFrameClass, pictureFrameConstructor, picture->type, mimeType,
description, picture->width, picture->height, picture->depth,
picture->colors, pictureData);
2019-12-31 14:08:08 +01:00
env->CallBooleanMethod(pictureFrames, arrayListAddMethod, pictureFrame);
env->DeleteLocalRef(mimeType);
env->DeleteLocalRef(description);
env->DeleteLocalRef(pictureData);
}
}
2019-01-23 18:03:33 +01:00
const FLAC__StreamMetadata_StreamInfo &streamInfo =
2020-07-26 10:03:38 +02:00
context->parser->getStreamInfo();
2019-01-23 18:03:33 +01:00
2019-12-31 14:08:08 +01:00
jclass flacStreamMetadataClass = env->FindClass(
2023-04-03 15:15:52 +02:00
"com/google/android/exoplayer2/extractor/"
2020-07-26 10:03:38 +02:00
"FlacStreamMetadata");
2019-12-31 14:08:08 +01:00
jmethodID flacStreamMetadataConstructor =
2020-07-26 10:03:38 +02:00
env->GetMethodID(flacStreamMetadataClass, "<init>",
"(IIIIIIIJLjava/util/ArrayList;Ljava/util/ArrayList;)V");
2019-12-31 14:08:08 +01:00
return env->NewObject(flacStreamMetadataClass, flacStreamMetadataConstructor,
streamInfo.min_blocksize, streamInfo.max_blocksize,
streamInfo.min_framesize, streamInfo.max_framesize,
streamInfo.sample_rate, streamInfo.channels,
streamInfo.bits_per_sample, streamInfo.total_samples,
commentList, pictureFrames);
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jint, flacDecodeToBuffer, jlong jContext, jobject jOutputBuffer) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
context->source->setFlacDecoderJni(env, thiz);
void *outputBuffer = env->GetDirectBufferAddress(jOutputBuffer);
jint outputSize = env->GetDirectBufferCapacity(jOutputBuffer);
return context->parser->readBuffer(outputBuffer, outputSize);
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jint, flacDecodeToArray, jlong jContext, jbyteArray jOutputArray) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
context->source->setFlacDecoderJni(env, thiz);
jbyte *outputBuffer = env->GetByteArrayElements(jOutputArray, NULL);
jint outputSize = env->GetArrayLength(jOutputArray);
int count = context->parser->readBuffer(outputBuffer, outputSize);
env->ReleaseByteArrayElements(jOutputArray, outputBuffer, 0);
return count;
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jlong, flacGetDecodePosition, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getDecodePosition();
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jlong, flacGetLastFrameTimestamp, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getLastFrameTimestamp();
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jlong, flacGetLastFrameFirstSampleIndex, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getLastFrameFirstSampleIndex();
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->getNextFrameFirstSampleIndex();
2018-07-30 04:07:02 +02:00
}
2019-12-31 14:08:08 +01:00
DECODER_FUNC(jboolean, flacGetSeekPoints, jlong jContext, jlong timeUs,
jlongArray outSeekPoints) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
2019-12-31 14:08:08 +01:00
std::array<int64_t, 4> result;
bool success = context->parser->getSeekPositions(timeUs, result);
if (success) {
env->SetLongArrayRegion(outSeekPoints, 0, result.size(), result.data());
}
return success;
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jstring, flacGetStateString, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
const char *str = context->parser->getDecoderStateString();
return env->NewStringUTF(str);
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(jboolean, flacIsDecoderAtEndOfStream, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
return context->parser->isDecoderAtEndOfStream();
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(void, flacFlush, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
context->parser->flush();
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(void, flacReset, jlong jContext, jlong newPosition) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
context->parser->reset(newPosition);
2018-07-30 04:07:02 +02:00
}
DECODER_FUNC(void, flacRelease, jlong jContext) {
2019-01-23 18:03:33 +01:00
Context *context = reinterpret_cast<Context *>(jContext);
delete context;
2018-07-30 04:07:02 +02:00
}