Skip to content

Commit

Permalink
Migrate to FFmpeg 6.0
Browse files Browse the repository at this point in the history
These changes are also compatible with FFmpeg 5.1, which is now minimum supported version.

Also set -Wl,-Bsymbolic flag via target_link_options command which is more correct.
  • Loading branch information
equeim committed Oct 9, 2023
1 parent 3ed7e56 commit 1ce13f6
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 30 deletions.
6 changes: 3 additions & 3 deletions libraries/decoder_ffmpeg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ FFMPEG_MODULE_PATH="$(pwd)/libraries/decoder_ffmpeg/src/main"
```

* Download the [Android NDK][] and set its location in a shell variable.
This build configuration has been tested on NDK r21.
This build configuration has been tested on NDK r26.

```
NDK_PATH="<path to Android NDK>"
Expand All @@ -42,13 +42,13 @@ HOST_PLATFORM="linux-x86_64"
```

* Fetch FFmpeg and checkout an appropriate branch. We cannot guarantee
compatibility with all versions of FFmpeg. We currently recommend version 4.2:
compatibility with all versions of FFmpeg. We currently recommend version 6.0:

```
cd "<preferred location for ffmpeg>" && \
git clone git://source.ffmpeg.org/ffmpeg && \
cd ffmpeg && \
git checkout release/4.2 && \
git checkout release/6.0 && \
FFMPEG_PATH="$(pwd)"
```

Expand Down
12 changes: 6 additions & 6 deletions libraries/decoder_ffmpeg/src/main/jni/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ set(CMAKE_CXX_STANDARD 11)

project(libffmpegJNI C CXX)

# Additional flags needed for "arm64-v8a" from NDK 23.1.7779620 and above.
# See https://github.com/google/ExoPlayer/issues/9933#issuecomment-1029775358.
if(${ANDROID_ABI} MATCHES "arm64-v8a")
set(CMAKE_CXX_FLAGS "-Wl,-Bsymbolic")
endif()

set(ffmpeg_location "${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg")
set(ffmpeg_binaries "${ffmpeg_location}/android-libs/${ANDROID_ABI}")

Expand Down Expand Up @@ -56,3 +50,9 @@ target_link_libraries(ffmpegJNI
PRIVATE avcodec
PRIVATE avutil
PRIVATE ${android_log_lib})

# Additional flags needed for "arm64-v8a" from NDK 23.1.7779620 and above.
# See https://github.com/google/ExoPlayer/issues/9933#issuecomment-1029775358.
if(ANDROID_ABI STREQUAL "arm64-v8a")
target_link_options(ffmpegJNI PRIVATE "-Wl,-Bsymbolic")
endif()
3 changes: 2 additions & 1 deletion libraries/decoder_ffmpeg/src/main/jni/build_ffmpeg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ COMMON_OPTIONS="
--disable-postproc
--disable-avfilter
--disable-symver
--disable-avresample
--enable-swresample
--extra-ldexeflags=-pie
--disable-v4l2-m2m
--disable-vulkan
"
TOOLCHAIN_PREFIX="${NDK_PATH}/toolchains/llvm/prebuilt/${HOST_PLATFORM}/bin"
for decoder in "${ENABLED_DECODERS[@]}"
Expand Down
42 changes: 22 additions & 20 deletions libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ static const int AUDIO_DECODER_ERROR_OTHER = -2;
/**
* Returns the AVCodec with the specified name, or NULL if it is not available.
*/
AVCodec *getCodecByName(JNIEnv *env, jstring codecName);
const AVCodec *getCodecByName(JNIEnv *env, jstring codecName);

/**
* Allocates and opens a new AVCodecContext for the specified codec, passing the
* provided extraData as initialization data for the decoder if it is non-NULL.
* Returns the created context.
*/
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
AVCodecContext *createContext(JNIEnv *env, const AVCodec *codec, jbyteArray extraData,
jboolean outputFloat, jint rawSampleRate,
jint rawChannelCount);

Expand Down Expand Up @@ -109,7 +109,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
avcodec_register_all();
return JNI_VERSION_1_6;
}

Expand All @@ -128,7 +127,7 @@ LIBRARY_FUNC(jboolean, ffmpegHasDecoder, jstring codecName) {
AUDIO_DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName,
jbyteArray extraData, jboolean outputFloat,
jint rawSampleRate, jint rawChannelCount) {
AVCodec *codec = getCodecByName(env, codecName);
const AVCodec *codec = getCodecByName(env, codecName);
if (!codec) {
LOGE("Codec not found.");
return 0L;
Expand Down Expand Up @@ -157,20 +156,25 @@ AUDIO_DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData,
}
uint8_t *inputBuffer = (uint8_t *)env->GetDirectBufferAddress(inputData);
uint8_t *outputBuffer = (uint8_t *)env->GetDirectBufferAddress(outputData);
AVPacket packet;
av_init_packet(&packet);
packet.data = inputBuffer;
packet.size = inputSize;
return decodePacket((AVCodecContext *)context, &packet, outputBuffer,
AVPacket* packet = av_packet_alloc();
if (!packet) {
LOGE("Failed to allocate packet.");
return -1;
}
packet->data = inputBuffer;
packet->size = inputSize;
const int ret = decodePacket((AVCodecContext *)context, packet, outputBuffer,
outputSize);
av_packet_free(&packet);
return ret;
}

AUDIO_DECODER_FUNC(jint, ffmpegGetChannelCount, jlong context) {
if (!context) {
LOGE("Context must be non-NULL.");
return -1;
}
return ((AVCodecContext *)context)->channels;
return ((AVCodecContext *)context)->ch_layout.nb_channels;
}

AUDIO_DECODER_FUNC(jint, ffmpegGetSampleRate, jlong context) {
Expand All @@ -193,7 +197,7 @@ AUDIO_DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) {
// Release and recreate the context if the codec is TrueHD.
// TODO: Figure out why flushing doesn't work for this codec.
releaseContext(context);
AVCodec *codec = avcodec_find_decoder(codecId);
const AVCodec *codec = avcodec_find_decoder(codecId);
if (!codec) {
LOGE("Unexpected error finding codec %d.", codecId);
return 0L;
Expand All @@ -215,17 +219,17 @@ AUDIO_DECODER_FUNC(void, ffmpegRelease, jlong context) {
}
}

AVCodec *getCodecByName(JNIEnv *env, jstring codecName) {
const AVCodec *getCodecByName(JNIEnv *env, jstring codecName) {
if (!codecName) {
return NULL;
}
const char *codecNameChars = env->GetStringUTFChars(codecName, NULL);
AVCodec *codec = avcodec_find_decoder_by_name(codecNameChars);
const AVCodec *codec = avcodec_find_decoder_by_name(codecNameChars);
env->ReleaseStringUTFChars(codecName, codecNameChars);
return codec;
}

AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
AVCodecContext *createContext(JNIEnv *env, const AVCodec *codec, jbyteArray extraData,
jboolean outputFloat, jint rawSampleRate,
jint rawChannelCount) {
AVCodecContext *context = avcodec_alloc_context3(codec);
Expand All @@ -250,8 +254,7 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
if (context->codec_id == AV_CODEC_ID_PCM_MULAW ||
context->codec_id == AV_CODEC_ID_PCM_ALAW) {
context->sample_rate = rawSampleRate;
context->channels = rawChannelCount;
context->channel_layout = av_get_default_channel_layout(rawChannelCount);
av_channel_layout_default(&context->ch_layout, rawChannelCount);
}
context->err_recognition = AV_EF_IGNORE_ERR;
int result = avcodec_open2(context, codec, NULL);
Expand Down Expand Up @@ -293,8 +296,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,

// Resample output.
AVSampleFormat sampleFormat = context->sample_fmt;
int channelCount = context->channels;
int channelLayout = context->channel_layout;
int channelCount = context->ch_layout.nb_channels;
int sampleRate = context->sample_rate;
int sampleCount = frame->nb_samples;
int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount,
Expand All @@ -304,8 +306,8 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
resampleContext = (SwrContext *)context->opaque;
} else {
resampleContext = swr_alloc();
av_opt_set_int(resampleContext, "in_channel_layout", channelLayout, 0);
av_opt_set_int(resampleContext, "out_channel_layout", channelLayout, 0);
av_opt_set_chlayout(resampleContext, "in_channel_layout", &context->ch_layout, 0);
av_opt_set_chlayout(resampleContext, "out_channel_layout", &context->ch_layout, 0);
av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0);
av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0);
av_opt_set_int(resampleContext, "in_sample_fmt", sampleFormat, 0);
Expand Down

0 comments on commit 1ce13f6

Please sign in to comment.