Skip to content

Commit

Permalink
Migrate class MediaCodecBridge$GetOutputFormatResult to jni_generator (
Browse files Browse the repository at this point in the history
…#4759)

This PR demonstrates jni_generator/jni_zero migration in cobalt/media.

This PR primarily migrates the subclass GetOutputFormatResult in class
MediaCodecBridge.

I also have to migrate every native function in class MediaCodecBridge
in this same PR because the old native implementations conflict with
jni_generator; The jni header generated by jni_generator
cobalt/android/jni_headers/MediaCodecBridge_jni.h would generate
duplicated native function signatures as the old native implementations.

Local tests:
Call Native functions in Java:
https://paste.googleplex.com/6062051978641408
Call Java functions in Native:
https://paste.googleplex.com/6124614082887680

b/390481510
  • Loading branch information
haozheng-cobalt authored Jan 25, 2025
1 parent 9968b06 commit 7299dad
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 73 deletions.
5 changes: 4 additions & 1 deletion cobalt/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ jinja_template("cobalt_manifest") {
}

generate_jni("jni_headers") {
sources = [ "apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java" ]
sources = [
"apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java",
"apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java",
]
}

generate_jni("content_shell_jni_headers") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,14 @@
import java.nio.ByteOrder;
import java.util.Locale;
import java.util.Optional;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;

/** A wrapper of the MediaCodec class. */

@JNINamespace("starboard::android::shared")

@SuppressWarnings("unused")
@UsedByNative
class MediaCodecBridge {
Expand Down Expand Up @@ -261,7 +267,7 @@ private static class GetOutputFormatResult {
private Optional<Boolean> mFormatHasCropValues = Optional.empty();

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private GetOutputFormatResult() {
mStatus = MediaCodecStatus.ERROR;
mFormat = null;
Expand All @@ -280,59 +286,59 @@ private boolean formatHasCropValues() {
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int status() {
return mStatus;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int textureWidth() {
return (mFormat != null && mFormat.containsKey(MediaFormat.KEY_WIDTH))
? mFormat.getInteger(MediaFormat.KEY_WIDTH)
: 0;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int textureHeight() {
return (mFormat != null && mFormat.containsKey(MediaFormat.KEY_HEIGHT))
? mFormat.getInteger(MediaFormat.KEY_HEIGHT)
: 0;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int cropLeft() {
return formatHasCropValues() ? mFormat.getInteger(KEY_CROP_LEFT) : -1;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int cropTop() {
return formatHasCropValues() ? mFormat.getInteger(KEY_CROP_TOP) : -1;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int cropRight() {
return formatHasCropValues() ? mFormat.getInteger(KEY_CROP_RIGHT) : -1;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int cropBottom() {
return formatHasCropValues() ? mFormat.getInteger(KEY_CROP_BOTTOM) : -1;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int sampleRate() {
return mFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative("GetOutputFormatResult")
private int channelCount() {
return mFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
}
Expand Down Expand Up @@ -458,7 +464,7 @@ public void onError(MediaCodec codec, MediaCodec.CodecException e) {
if (mNativeMediaCodecBridge == 0) {
return;
}
nativeOnMediaCodecError(
MediaCodecBridgeJni.get().onMediaCodecError(
mNativeMediaCodecBridge,
e.isRecoverable(),
e.isTransient(),
Expand All @@ -472,7 +478,7 @@ public void onInputBufferAvailable(MediaCodec codec, int index) {
if (mNativeMediaCodecBridge == 0) {
return;
}
nativeOnMediaCodecInputBufferAvailable(mNativeMediaCodecBridge, index);
MediaCodecBridgeJni.get().onMediaCodecInputBufferAvailable(mNativeMediaCodecBridge, index);
}
}

Expand All @@ -483,7 +489,7 @@ public void onOutputBufferAvailable(
if (mNativeMediaCodecBridge == 0) {
return;
}
nativeOnMediaCodecOutputBufferAvailable(
MediaCodecBridgeJni.get().onMediaCodecOutputBufferAvailable(
mNativeMediaCodecBridge,
index,
info.flags,
Expand All @@ -507,7 +513,7 @@ public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
if (mNativeMediaCodecBridge == 0) {
return;
}
nativeOnMediaCodecOutputFormatChanged(mNativeMediaCodecBridge);
MediaCodecBridgeJni.get().onMediaCodecOutputFormatChanged(mNativeMediaCodecBridge);
if (mFrameRateEstimator != null) {
mFrameRateEstimator.reset();
}
Expand All @@ -525,7 +531,7 @@ public void onFrameRendered(MediaCodec codec, long presentationTimeUs, long nano
if (mNativeMediaCodecBridge == 0) {
return;
}
nativeOnMediaCodecFrameRendered(
MediaCodecBridgeJni.get().onMediaCodecFrameRendered(
mNativeMediaCodecBridge, presentationTimeUs, nanoTime);
}
}
Expand Down Expand Up @@ -1204,25 +1210,29 @@ private int getAudioFormat(int channelCount) {
}
}

private native void nativeOnMediaCodecError(
long nativeMediaCodecBridge,
@NativeMethods
interface Natives {
void onMediaCodecError(
long mediaCodecBridge,
boolean isRecoverable,
boolean isTransient,
String diagnosticInfo);
String diagnosticInfo
);

private native void nativeOnMediaCodecInputBufferAvailable(
long nativeMediaCodecBridge, int bufferIndex);
void onMediaCodecInputBufferAvailable(
long mediaCodecBridge, int bufferIndex);

private native void nativeOnMediaCodecOutputBufferAvailable(
long nativeMediaCodecBridge,
void onMediaCodecOutputBufferAvailable(
long mediaCodecBridge,
int bufferIndex,
int flags,
int offset,
long presentationTimeUs,
int size);

private native void nativeOnMediaCodecOutputFormatChanged(long nativeMediaCodecBridge);
void onMediaCodecOutputFormatChanged(long mediaCodecBridge);

private native void nativeOnMediaCodecFrameRendered(
long nativeMediaCodecBridge, long presentationTimeUs, long renderAtSystemTimeNs);
void onMediaCodecFrameRendered(
long mediaCodecBridge, long presentationTimeUs, long renderAtSystemTimeNs);
}
}
106 changes: 60 additions & 46 deletions starboard/android/shared/media_codec_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,23 @@

#include "starboard/android/shared/media_codec_bridge.h"

#include "base/android/jni_string.h"
#include "starboard/android/shared/media_capabilities_cache.h"
#include "starboard/android/shared/media_codec_bridge_eradicator.h"
#include "starboard/common/string.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "cobalt/android/jni_headers/MediaCodecBridge_jni.h"

namespace starboard {
namespace android {
namespace shared {

// TODO: (cobalt b/372559388) Update namespace to jni_zero.
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::JavaParamRef;

namespace {

// See
Expand Down Expand Up @@ -86,39 +95,34 @@ jint SbMediaRangeIdToColorRange(SbMediaRangeId range_id) {
} // namespace

extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecFrameRendered(
JNIEnv* env,
jobject unused_this,
jlong native_media_codec_bridge,
jlong presentation_time_us,
jlong render_at_system_time_ns) {
JNI_MediaCodecBridge_OnMediaCodecFrameRendered(JNIEnv* env,
jlong native_media_codec_bridge,
jlong presentation_time_us,
jlong render_at_system_time_ns) {
MediaCodecBridge* media_codec_bridge =
reinterpret_cast<MediaCodecBridge*>(native_media_codec_bridge);
SB_DCHECK(media_codec_bridge);
media_codec_bridge->OnMediaCodecFrameRendered(presentation_time_us);
}

extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecError(
JniEnvExt* env,
jobject unused_this,
extern "C" SB_EXPORT_PLATFORM void JNI_MediaCodecBridge_OnMediaCodecError(
JNIEnv* env,
jlong native_media_codec_bridge,
jboolean is_recoverable,
jboolean is_transient,
jstring diagnostic_info) {
const JavaParamRef<jstring>& diagnostic_info) {
MediaCodecBridge* media_codec_bridge =
reinterpret_cast<MediaCodecBridge*>(native_media_codec_bridge);
SB_DCHECK(media_codec_bridge);
std::string diagnostic_info_in_str =
env->GetStringStandardUTFOrAbort(diagnostic_info);
ConvertJavaStringToUTF8(env, diagnostic_info);
media_codec_bridge->OnMediaCodecError(is_recoverable, is_transient,
diagnostic_info_in_str);
}

extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecInputBufferAvailable(
JNI_MediaCodecBridge_OnMediaCodecInputBufferAvailable(
JNIEnv* env,
jobject unused_this,
jlong native_media_codec_bridge,
jint buffer_index) {
MediaCodecBridge* media_codec_bridge =
Expand All @@ -128,9 +132,8 @@ Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecInputBufferAvailable(
}

extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecOutputBufferAvailable(
JNI_MediaCodecBridge_OnMediaCodecOutputBufferAvailable(
JNIEnv* env,
jobject unused_this,
jlong native_media_codec_bridge,
jint buffer_index,
jint flags,
Expand All @@ -145,9 +148,8 @@ Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecOutputBufferAvailable(
}

extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecOutputFormatChanged(
JNI_MediaCodecBridge_OnMediaCodecOutputFormatChanged(
JNIEnv* env,
jobject unused_this,
jlong native_media_codec_bridge) {
MediaCodecBridge* media_codec_bridge =
reinterpret_cast<MediaCodecBridge*>(native_media_codec_bridge);
Expand Down Expand Up @@ -390,7 +392,7 @@ MediaCodecBridge::~MediaCodecBridge() {

if (MediaCodecBridgeEradicator::GetInstance()->IsEnabled()) {
if (MediaCodecBridgeEradicator::GetInstance()->Destroy(
j_media_codec_bridge_, j_reused_get_output_format_result_)) {
j_media_codec_bridge_, j_reused_get_output_format_result_.obj())) {
return;
}
SB_LOG(WARNING)
Expand All @@ -403,10 +405,6 @@ MediaCodecBridge::~MediaCodecBridge() {
env->CallVoidMethodOrAbort(j_media_codec_bridge_, "release", "()V");
env->DeleteGlobalRef(j_media_codec_bridge_);
j_media_codec_bridge_ = NULL;

SB_DCHECK(j_reused_get_output_format_result_);
env->DeleteGlobalRef(j_reused_get_output_format_result_);
j_reused_get_output_format_result_ = NULL;
}

jobject MediaCodecBridge::GetInputBuffer(jint index) {
Expand Down Expand Up @@ -510,17 +508,25 @@ FrameSize MediaCodecBridge::GetOutputSize() {
env->CallVoidMethodOrAbort(
j_media_codec_bridge_, "getOutputFormat",
"(Ldev/cobalt/media/MediaCodecBridge$GetOutputFormatResult;)V",
j_reused_get_output_format_result_);

auto call_int_method = [env, this](const char* name) {
return env->CallIntMethodOrAbort(j_reused_get_output_format_result_, name,
"()I");
};

FrameSize size = {
call_int_method("textureWidth"), call_int_method("textureHeight"),
call_int_method("cropLeft"), call_int_method("cropTop"),
call_int_method("cropRight"), call_int_method("cropBottom")};
j_reused_get_output_format_result_.obj());

JNIEnv* env_jni = AttachCurrentThread();

jint textureWidth = Java_GetOutputFormatResult_textureWidth(
env_jni, j_reused_get_output_format_result_);
jint textureHeight = Java_GetOutputFormatResult_textureHeight(
env_jni, j_reused_get_output_format_result_);
jint cropLeft = Java_GetOutputFormatResult_cropLeft(
env_jni, j_reused_get_output_format_result_);
jint cropTop = Java_GetOutputFormatResult_cropTop(
env_jni, j_reused_get_output_format_result_);
jint cropRight = Java_GetOutputFormatResult_cropRight(
env_jni, j_reused_get_output_format_result_);
jint cropBottom = Java_GetOutputFormatResult_cropBottom(
env_jni, j_reused_get_output_format_result_);

FrameSize size = {textureWidth, textureHeight, cropLeft,
cropTop, cropRight, cropBottom};

size.DCheckValid();
return size;
Expand All @@ -531,19 +537,23 @@ AudioOutputFormatResult MediaCodecBridge::GetAudioOutputFormat() {
env->CallVoidMethodOrAbort(
j_media_codec_bridge_, "getOutputFormat",
"(Ldev/cobalt/media/MediaCodecBridge$GetOutputFormatResult;)V",
j_reused_get_output_format_result_);
j_reused_get_output_format_result_.obj());

JNIEnv* env_jni = AttachCurrentThread();

jint status = Java_GetOutputFormatResult_status(
env_jni, j_reused_get_output_format_result_);

jint status = env->CallIntMethodOrAbort(j_reused_get_output_format_result_,
"status", "()I");
if (status == MEDIA_CODEC_ERROR) {
return {status, 0, 0};
}

return {status,
env->CallIntMethodOrAbort(j_reused_get_output_format_result_,
"sampleRate", "()I"),
env->CallIntMethodOrAbort(j_reused_get_output_format_result_,
"channelCount", "()I")};
jint sample_rate = Java_GetOutputFormatResult_sampleRate(
env_jni, j_reused_get_output_format_result_);
jint channel_count = Java_GetOutputFormatResult_channelCount(
env_jni, j_reused_get_output_format_result_);

return {status, sample_rate, channel_count};
}

void MediaCodecBridge::OnMediaCodecError(bool is_recoverable,
Expand Down Expand Up @@ -583,14 +593,18 @@ void MediaCodecBridge::Initialize(jobject j_media_codec_bridge) {

j_media_codec_bridge_ = j_media_codec_bridge;

// TODO: (cobalt b/390481510) Consolidate env variables when the rest of
// MediaCodecBridge is migrated.
JniEnvExt* env = JniEnvExt::Get();
SB_DCHECK(env->GetObjectRefType(j_media_codec_bridge_) == JNIGlobalRefType);

j_reused_get_output_format_result_ = env->NewObjectOrAbort(
jobject j_reused_get_output_format_result_raw = env->NewObjectOrAbort(
"dev/cobalt/media/MediaCodecBridge$GetOutputFormatResult", "()V");
SB_DCHECK(j_reused_get_output_format_result_);
j_reused_get_output_format_result_ =
env->ConvertLocalRefToGlobalRef(j_reused_get_output_format_result_);
SB_DCHECK(j_reused_get_output_format_result_raw);

JNIEnv* env_jni = AttachCurrentThread();
j_reused_get_output_format_result_.Reset(
env_jni, j_reused_get_output_format_result_raw);
}

} // namespace shared
Expand Down
Loading

0 comments on commit 7299dad

Please sign in to comment.