From 68e32eab45202941588d33f15898721f93b30ec9 Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Sun, 26 Jan 2025 22:27:19 +0100 Subject: [PATCH] MediaCodec: add mp3 and opus codecs --- .../media/android_media_MediaCodec.c | 32 +++++++++++++------ src/api-impl/android/media/MediaCodec.java | 8 +++-- .../android/media/MediaCodecList.java | 6 +++- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/api-impl-jni/media/android_media_MediaCodec.c b/src/api-impl-jni/media/android_media_MediaCodec.c index e9a483af..04e3064c 100644 --- a/src/api-impl-jni/media/android_media_MediaCodec.c +++ b/src/api-impl-jni/media/android_media_MediaCodec.c @@ -33,6 +33,7 @@ struct ATL_codec_context { union { struct { SwrContext *swr; + int sample_rate; } audio; struct { struct SwsContext *sws; // for software decoding @@ -45,6 +46,10 @@ JNIEXPORT jlong JNICALL Java_android_media_MediaCodec_native_1constructor(JNIEnv { const char *name = (*env)->GetStringUTFChars(env, codec_name, NULL); const AVCodec *codec = avcodec_find_decoder_by_name(name); + if (!codec) { + printf("Codec %s not found\n", name); + exit(0); + } (*env)->ReleaseStringUTFChars(env, codec_name, name); if (!codec) return 0; @@ -65,15 +70,24 @@ JNIEXPORT void JNICALL Java_android_media_MediaCodec_native_1configure_1audio(JN printf("Java_android_media_MediaCodec_native_1configure_1audio(%s, %d, %d)\n", codec_ctx->codec->name, sample_rate, nb_channels); + ctx->audio.sample_rate = sample_rate; codec_ctx->sample_rate = sample_rate; - codec_ctx->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO; - codec_ctx->ch_layout.nb_channels = nb_channels; + if (nb_channels == 1) + codec_ctx->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_MONO; + else if (nb_channels == 2) + codec_ctx->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO; + else { + printf("MediaCodec: Unsupported number of channels %d\n", nb_channels); + exit(0); + } - codec_ctx->extradata_size = get_nio_buffer_size(env, extradata); - data = get_nio_buffer(env, extradata, &array_ref, &array); - codec_ctx->extradata = av_mallocz(codec_ctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - memcpy(codec_ctx->extradata, data, codec_ctx->extradata_size); - release_nio_buffer(env, array_ref, array); + if (extradata) { + codec_ctx->extradata_size = get_nio_buffer_size(env, extradata); + data = get_nio_buffer(env, extradata, &array_ref, &array); + codec_ctx->extradata = av_mallocz(codec_ctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + memcpy(codec_ctx->extradata, data, codec_ctx->extradata_size); + release_nio_buffer(env, array_ref, array); + } for (int i = 0; i < codec_ctx->extradata_size; i++) { printf("params->extradata[%d] = %x\n", i, codec_ctx->extradata[i]); @@ -270,7 +284,7 @@ JNIEXPORT void JNICALL Java_android_media_MediaCodec_native_1start(JNIEnv *env, int ret = swr_alloc_set_opts2(&ctx->audio.swr, &codec_ctx->ch_layout, AV_SAMPLE_FMT_S16, - codec_ctx->sample_rate, + ctx->audio.sample_rate, &codec_ctx->ch_layout, codec_ctx->sample_fmt, codec_ctx->sample_rate, @@ -348,7 +362,7 @@ JNIEXPORT jint JNICALL Java_android_media_MediaCodec_native_1dequeueOutputBuffer int outSamples = swr_convert(ctx->audio.swr, &raw_buffer, frame->nb_samples, (uint8_t const **) (frame->data), frame->nb_samples); release_nio_buffer(env, array_ref, array); _SET_INT_FIELD(buffer_info, "offset", 0); - _SET_INT_FIELD(buffer_info, "size", outSamples * 2 * 2); + _SET_INT_FIELD(buffer_info, "size", outSamples * 2 * codec_ctx->ch_layout.nb_channels); av_frame_free(&frame); } else if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { diff --git a/src/api-impl/android/media/MediaCodec.java b/src/api-impl/android/media/MediaCodec.java index 7c185775..7fb19d58 100644 --- a/src/api-impl/android/media/MediaCodec.java +++ b/src/api-impl/android/media/MediaCodec.java @@ -54,14 +54,18 @@ public class MediaCodec { outputBuffers = new ByteBuffer[2]; freeOutputBuffers = new ArrayDeque<>(outputBuffers.length); for (int i = 0; i < outputBuffers.length; i++) { - outputBuffers[i] = ByteBuffer.allocate(4096).order(ByteOrder.LITTLE_ENDIAN); + outputBuffers[i] = ByteBuffer.allocate(8192).order(ByteOrder.LITTLE_ENDIAN); freeOutputBuffers.add(i); } - if ("aac".equals(codecName)) { + if ("aac".equals(codecName) || "mp3".equals(codecName) || "opus".equals(codecName)) { native_configure_audio(native_codec, format.getByteBuffer("csd-0"), format.getInteger("sample-rate"), format.getInteger("channel-count")); } else if ("h264".equals(codecName)) { native_configure_video(native_codec, format.getByteBuffer("csd-0"), format.getByteBuffer("csd-1"), surface); + } else { + System.out.println("configure: format " + format + " not implemented"); + Thread.dumpStack(); + System.exit(1); } } diff --git a/src/api-impl/android/media/MediaCodecList.java b/src/api-impl/android/media/MediaCodecList.java index d2a19bc9..9bc938a9 100644 --- a/src/api-impl/android/media/MediaCodecList.java +++ b/src/api-impl/android/media/MediaCodecList.java @@ -3,7 +3,7 @@ package android.media; public class MediaCodecList { public static int getCodecCount() { - return 2; + return 4; } public static MediaCodecInfo getCodecInfoAt(int index) { @@ -12,6 +12,10 @@ public class MediaCodecList { return new MediaCodecInfo("aac", "audio/mp4a-latm"); case 1: return new MediaCodecInfo("h264", "video/avc"); + case 2: + return new MediaCodecInfo("mp3", "audio/mpeg"); + case 3: + return new MediaCodecInfo("opus", "audio/opus"); default: return null; }