| Index: media/base/android/media_codec_bridge.cc
|
| diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..585a54ce19ebee44ad2a1cb10b175c0e4726d718
|
| --- /dev/null
|
| +++ b/media/base/android/media_codec_bridge.cc
|
| @@ -0,0 +1,365 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "media/base/android/media_codec_bridge.h"
|
| +
|
| +#include <jni.h>
|
| +
|
| +#include "base/android/jni_android.h"
|
| +#include "base/android/jni_array.h"
|
| +#include "base/android/jni_string.h"
|
| +#include "base/basictypes.h"
|
| +#include "base/logging.h"
|
| +#include "base/stringprintf.h"
|
| +
|
| +#include "jni/Buffer_jni.h"
|
| +#include "jni/ByteBuffer_jni.h"
|
| +#include "jni/MediaFormat_jni.h"
|
| +#include "MediaCodec_jni.h"
|
| +#include "MediaCodec$BufferInfo_jni.h"
|
| +
|
| +using base::android::AttachCurrentThread;
|
| +using base::android::ConvertUTF8ToJavaString;
|
| +using base::android::GetClass;
|
| +using base::android::GetFieldID;
|
| +using base::android::ScopedJavaLocalRef;
|
| +using base::android::ToJavaByteArray;
|
| +
|
| +
|
| +namespace {
|
| +struct FieldIds {
|
| + FieldIds(JNIEnv* env) {
|
| + ScopedJavaLocalRef<jclass> clazz(
|
| + GetClass(env, "android/media/MediaCodec$BufferInfo"));
|
| + offset = GetFieldID(env, clazz, "offset", "I");
|
| + size = GetFieldID(env, clazz, "size", "I");
|
| + presentation_time_us = GetFieldID(env, clazz, "presentationTimeUs", "J");
|
| + flags = GetFieldID(env, clazz, "flags", "I");
|
| + }
|
| + jfieldID offset;
|
| + jfieldID size;
|
| + jfieldID presentation_time_us;
|
| + jfieldID flags;
|
| +};
|
| +
|
| +FieldIds* g_field_ids;
|
| +
|
| +void RegisterNativesIfNeeded(JNIEnv* env) {
|
| + static bool jni_initialized = false;
|
| + if (!jni_initialized) {
|
| + JNI_Buffer::RegisterNativesImpl(env);
|
| + JNI_ByteBuffer::RegisterNativesImpl(env);
|
| + JNI_MediaCodec::RegisterNativesImpl(env);
|
| + JNI_MediaCodec$BufferInfo::RegisterNativesImpl(env);
|
| + JNI_MediaFormat::RegisterNativesImpl(env);
|
| + g_field_ids = new FieldIds(env);
|
| + jni_initialized = true;
|
| + }
|
| +}
|
| +} // namespace
|
| +
|
| +namespace media {
|
| +
|
| +MediaCodecBridge::MediaCodecBridge(const std::string& type)
|
| + : j_byte_array_size_(0) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| + RegisterNativesIfNeeded(env);
|
| +
|
| + ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type);
|
| +
|
| + ScopedJavaLocalRef<jobject> tmp(
|
| + JNI_MediaCodec::Java_MediaCodec_createDecoderByType(env, j_type.obj()));
|
| + DCHECK(!tmp.is_null());
|
| + j_media_codec_.Reset(tmp);
|
| +}
|
| +
|
| +MediaCodecBridge::~MediaCodecBridge() {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + // Release graphics memory.
|
| + JNI_MediaCodec::Java_MediaCodec_release(env, j_media_codec_.obj());
|
| +}
|
| +
|
| +void MediaCodecBridge::ConfigureAudio(
|
| + const std::string& mime, int sample_rate, int channel_count,
|
| + const uint8* csd0, int csd0_size, const uint8* csd1, int csd1_size,
|
| + int encoder_delay, int encoder_padding, int max_input_size) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
|
| + ScopedJavaLocalRef<jobject> j_format(
|
| + JNI_MediaFormat::Java_MediaFormat_createAudioFormat(
|
| + env, j_mime.obj(), static_cast<jint>(sample_rate),
|
| + static_cast<jint>(channel_count)));
|
| + DCHECK(!j_format.is_null());
|
| +
|
| + if (csd0 != NULL && csd0_size > 0) {
|
| + ScopedJavaLocalRef<jstring> j_csd_string =
|
| + ConvertUTF8ToJavaString(env, "csd-0");
|
| + ScopedJavaLocalRef<jbyteArray> j_csd_array =
|
| + ToJavaByteArray(env, csd0, csd0_size);
|
| + ScopedJavaLocalRef<jobject> j_bytebuffer =
|
| + JNI_ByteBuffer::Java_ByteBuffer_wrapJNBB_AB(env, j_csd_array.obj());
|
| + JNI_MediaFormat::Java_MediaFormat_setByteBuffer(
|
| + env, j_format.obj(), j_csd_string.obj(), j_bytebuffer.obj());
|
| + }
|
| +
|
| + if (csd1 != NULL && csd1_size > 0) {
|
| + ScopedJavaLocalRef<jstring> j_csd_string =
|
| + ConvertUTF8ToJavaString(env, "csd-1");
|
| + ScopedJavaLocalRef<jbyteArray> j_csd_array =
|
| + ToJavaByteArray(env, csd1, csd1_size);
|
| + ScopedJavaLocalRef<jobject> j_bytebuffer =
|
| + JNI_ByteBuffer::Java_ByteBuffer_wrapJNBB_AB(env, j_csd_array.obj());
|
| + JNI_MediaFormat::Java_MediaFormat_setByteBuffer(
|
| + env, j_format.obj(), j_csd_string.obj(), j_bytebuffer.obj());
|
| + }
|
| +
|
| + if (encoder_delay > 0) {
|
| + ScopedJavaLocalRef<jstring> j_encoder_delay_string =
|
| + ConvertUTF8ToJavaString(env, "encoder-delay");
|
| + JNI_MediaFormat::Java_MediaFormat_setInteger(
|
| + env, j_format.obj(), j_encoder_delay_string.obj(),
|
| + static_cast<jint>(encoder_delay));
|
| + }
|
| +
|
| + if (encoder_padding > 0) {
|
| + ScopedJavaLocalRef<jstring> j_encoder_padding_string =
|
| + ConvertUTF8ToJavaString(env, "encoder-padding");
|
| + JNI_MediaFormat::Java_MediaFormat_setInteger(
|
| + env, j_format.obj(), j_encoder_padding_string.obj(),
|
| + static_cast<jint>(encoder_padding));
|
| + }
|
| +
|
| + if (max_input_size > 0) {
|
| + ScopedJavaLocalRef<jstring> j_max_input_size_string =
|
| + ConvertUTF8ToJavaString(env, "max-input-size");
|
| + JNI_MediaFormat::Java_MediaFormat_setInteger(
|
| + env, j_format.obj(), j_max_input_size_string.obj(),
|
| + static_cast<jint>(max_input_size));
|
| + }
|
| +
|
| + ScopedJavaLocalRef<jstring> j_is_adts_string =
|
| + ConvertUTF8ToJavaString(env, "is-adts");
|
| + JNI_MediaFormat::Java_MediaFormat_setInteger(
|
| + env, j_format.obj(), j_is_adts_string.obj(), static_cast<jint>(1));
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_configure(
|
| + env, j_media_codec_.obj(), j_format.obj(), NULL, NULL, 0);
|
| +}
|
| +
|
| +void MediaCodecBridge::ConfigureVideo(
|
| + const std::string& mime, int width, int height,
|
| + const uint8* csd0, int csd0_size, const uint8* csd1, int csd1_size,
|
| + jobject surface) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime);
|
| + ScopedJavaLocalRef<jobject> j_format(
|
| + JNI_MediaFormat::Java_MediaFormat_createVideoFormat(
|
| + env, j_mime.obj(), static_cast<jint>(width), static_cast<jint>(height)));
|
| + DCHECK(!j_format.is_null());
|
| +
|
| + if (csd0 != NULL && csd0_size > 0) {
|
| + ScopedJavaLocalRef<jstring> j_csd_string =
|
| + ConvertUTF8ToJavaString(env, "csd-0");
|
| + ScopedJavaLocalRef<jbyteArray> j_csd_array =
|
| + ToJavaByteArray(env, csd0, csd0_size);
|
| + ScopedJavaLocalRef<jobject> j_bytebuffer =
|
| + JNI_ByteBuffer::Java_ByteBuffer_wrapJNBB_AB(env, j_csd_array.obj());
|
| + JNI_MediaFormat::Java_MediaFormat_setByteBuffer(
|
| + env, j_format.obj(), j_csd_string.obj(), j_bytebuffer.obj());
|
| + }
|
| +
|
| + if (csd1 != NULL && csd1_size > 0) {
|
| + ScopedJavaLocalRef<jstring> j_csd_string =
|
| + ConvertUTF8ToJavaString(env, "csd-1");
|
| + ScopedJavaLocalRef<jbyteArray> j_csd_array =
|
| + ToJavaByteArray(env, csd1, csd1_size);
|
| + ScopedJavaLocalRef<jobject> j_bytebuffer =
|
| + JNI_ByteBuffer::Java_ByteBuffer_wrapJNBB_AB(env, j_csd_array.obj());
|
| + JNI_MediaFormat::Java_MediaFormat_setByteBuffer(
|
| + env, j_format.obj(), j_csd_string.obj(), j_bytebuffer.obj());
|
| + }
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_configure(
|
| + env, j_media_codec_.obj(), j_format.obj(), surface, NULL, 0);
|
| +}
|
| +
|
| +void MediaCodecBridge::Start() {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_start(env, j_media_codec_.obj());
|
| +}
|
| +
|
| +void MediaCodecBridge::Flush() {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_flush(env, j_media_codec_.obj());
|
| +}
|
| +
|
| +void MediaCodecBridge::Stop() {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_stop(env, j_media_codec_.obj());
|
| +}
|
| +
|
| +void MediaCodecBridge::Release() {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_release(env, j_media_codec_.obj());
|
| +}
|
| +
|
| +void MediaCodecBridge::GetOutputFormat(int* format, int* width, int* height) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + ScopedJavaLocalRef<jobject> j_format(
|
| + JNI_MediaCodec::Java_MediaCodec_getOutputFormat(
|
| + env, j_media_codec_.obj()));
|
| + if (!j_format.is_null()) {
|
| + ScopedJavaLocalRef<jstring> j_key_format =
|
| + ConvertUTF8ToJavaString(env, "color-format");
|
| + *format = static_cast<int>(JNI_MediaFormat::Java_MediaFormat_getInteger(
|
| + env, j_format.obj(), j_key_format.obj()));
|
| +
|
| + ScopedJavaLocalRef<jstring> j_key_width =
|
| + ConvertUTF8ToJavaString(env, "width");
|
| + *width = static_cast<int>(JNI_MediaFormat::Java_MediaFormat_getInteger(
|
| + env, j_format.obj(), j_key_width.obj()));
|
| +
|
| + ScopedJavaLocalRef<jstring> j_key_height =
|
| + ConvertUTF8ToJavaString(env, "height");
|
| + *height = static_cast<int>(JNI_MediaFormat::Java_MediaFormat_getInteger(
|
| + env, j_format.obj(), j_key_height.obj()));
|
| + }
|
| +}
|
| +
|
| +void MediaCodecBridge::QueueInputBuffer(
|
| + int index, int offset, int size, int64 presentation_time_us, int flags) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_queueInputBuffer(
|
| + env, j_media_codec_.obj(),
|
| + static_cast<jint>(index), static_cast<jint>(offset),
|
| + static_cast<jint>(size), static_cast<jlong>(presentation_time_us),
|
| + static_cast<jint>(flags));
|
| +}
|
| +
|
| +int MediaCodecBridge::DequeueInputBuffer(int64 timeout_us) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + return JNI_MediaCodec::Java_MediaCodec_dequeueInputBuffer(
|
| + env, j_media_codec_.obj(), static_cast<jlong>(timeout_us));
|
| +}
|
| +
|
| +int MediaCodecBridge::DequeueOutputBuffer(
|
| + int64 timeout_us, int* offset, int* size, int64* presentation_time_us,
|
| + int* flags) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + ScopedJavaLocalRef<jobject> j_info(
|
| + JNI_MediaCodec$BufferInfo::Java_MediaCodec$BufferInfo_Constructor(env));
|
| + jint j_buffer = JNI_MediaCodec::Java_MediaCodec_dequeueOutputBuffer(
|
| + env, j_media_codec_.obj(), j_info.obj(), static_cast<jlong>(timeout_us));
|
| +
|
| + if (j_buffer >= 0) {
|
| + *offset =
|
| + static_cast<int>(env->GetIntField(j_info.obj(), g_field_ids->offset));
|
| + *size = static_cast<int>(env->GetIntField(j_info.obj(), g_field_ids->size));
|
| + *presentation_time_us = static_cast<int64>(env->GetLongField(
|
| + j_info.obj(), g_field_ids->presentation_time_us));
|
| + *flags =
|
| + static_cast<int>(env->GetIntField(j_info.obj(), g_field_ids->flags));
|
| + }
|
| + return static_cast<int>(j_buffer);
|
| +}
|
| +
|
| +void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + JNI_MediaCodec::Java_MediaCodec_releaseOutputBuffer(
|
| + env, j_media_codec_.obj(), static_cast<jint>(index),
|
| + static_cast<jboolean>(render));
|
| +}
|
| +
|
| +int MediaCodecBridge::GetInputBuffers() {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + j_input_buffers_.Reset(
|
| + JNI_MediaCodec::Java_MediaCodec_getInputBuffers(
|
| + env, j_media_codec_.obj()));
|
| + if (j_input_buffers_.is_null()) return -1;
|
| +
|
| + return static_cast<int>(env->GetArrayLength(j_input_buffers_.obj()));
|
| +}
|
| +
|
| +int MediaCodecBridge::GetOutputBuffers() {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + j_output_buffers_.Reset(
|
| + JNI_MediaCodec::Java_MediaCodec_getOutputBuffers(
|
| + env, j_media_codec_.obj()));
|
| + if (j_output_buffers_.is_null()) return -1;
|
| +
|
| + return static_cast<int>(env->GetArrayLength(j_output_buffers_.obj()));
|
| +}
|
| +
|
| +void MediaCodecBridge::PutToInputBuffer(
|
| + int index, const uint8* data, int size) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + ScopedJavaLocalRef<jobject> j_buffer(
|
| + env, env->GetObjectArrayElement(j_input_buffers_.obj(), index));
|
| +
|
| + uint8* direct_buffer =
|
| + static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
|
| + memcpy(direct_buffer, data, size);
|
| +}
|
| +
|
| +void MediaCodecBridge::GetFromOutputBuffer(
|
| + int index, int offset, uint8* data, int size) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + ScopedJavaLocalRef<jobject> j_buffer(
|
| + env, env->GetObjectArrayElement(j_output_buffers_.obj(), index));
|
| +
|
| + uint8* direct_buffer =
|
| + static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
|
| + memcpy(data, direct_buffer + offset, size);
|
| +}
|
| +
|
| +void MediaCodecBridge::GetFromOutputBuffer(int index,
|
| + uint8* data0, int size0, uint8* data1, int size1, uint8* data2, int size2) {
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + ScopedJavaLocalRef<jobject> j_buffer(
|
| + env, env->GetObjectArrayElement(j_output_buffers_.obj(), index));
|
| +
|
| + uint8* direct_buffer =
|
| + static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
|
| + memcpy(data0, direct_buffer, size0);
|
| + memcpy(data1, direct_buffer + size0, size1);
|
| + memcpy(data2, direct_buffer + size0 + size1, size2);
|
| +}
|
| +
|
| +} // namespace media
|
| +
|
|
|