Skip to content

Commit

Permalink
Merge pull request #707 from equeim:ffmpeg-6.0
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 584893190
(cherry picked from commit 45b51d8)
  • Loading branch information
Copybara-Service authored and microkatz committed Jan 8, 2024
1 parent 5e86c4c commit 33484b0
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 46 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
* Decoder Extensions (FFmpeg, VP9, AV1, MIDI, etc.):
* MIDI: Fix issue where seeking forward skips the Program Change events
([#704](https://github.com/androidx/media/issues/704).
* Migrate to FFmpeg 6.0
([#707](https://github.com/androidx/media/pull/707)).
* Leanback extension:
* Cast Extension:
* Sanitize creation of a `Timeline` to not crash the app when loading
Expand Down
7 changes: 4 additions & 3 deletions libraries/decoder_ffmpeg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ NDK_PATH="<path to Android NDK>"
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:
* Fetch FFmpeg and checkout an appropriate branch. We cannot guarantee
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
92 changes: 56 additions & 36 deletions libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,16 @@ 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,
jboolean outputFloat, jint rawSampleRate,
jint rawChannelCount);
AVCodecContext *createContext(JNIEnv *env, const AVCodec *codec,
jbyteArray extraData, jboolean outputFloat,
jint rawSampleRate, jint rawChannelCount);

/**
* Decodes the packet into the output buffer, returning the number of bytes
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,38 @@ 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,
outputSize);
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,
GrowOutputBufferCallback{env, thiz, decoderOutputBuffer});
av_packet_free(&packet);
return ret;
}

uint8_t *GrowOutputBufferCallback::operator()(int requiredSize) const {
jobject newOutputData = env->CallObjectMethod(
thiz, growOutputBufferMethod, decoderOutputBuffer, requiredSize);
if (env->ExceptionCheck()) {
LOGE("growOutputBuffer() failed");
env->ExceptionDescribe();
return nullptr;
}
return static_cast<uint8_t *>(env->GetDirectBufferAddress(newOutputData));
>>>>>>> 45b51d8c97 (Merge pull request #707 from equeim:ffmpeg-6.0)
}

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 +210,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,19 +232,19 @@ 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,
jboolean outputFloat, jint rawSampleRate,
jint rawChannelCount) {
AVCodecContext *createContext(JNIEnv *env, const AVCodec *codec,
jbyteArray extraData, jboolean outputFloat,
jint rawSampleRate, jint rawChannelCount) {
AVCodecContext *context = avcodec_alloc_context3(codec);
if (!context) {
LOGE("Failed to allocate context.");
Expand All @@ -250,8 +267,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,25 +309,29 @@ 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,
sampleFormat, 1);
SwrContext *resampleContext;
if (context->opaque) {
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_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);
// The output format is always the requested format.
av_opt_set_int(resampleContext, "out_sample_fmt",
context->request_sample_fmt, 0);
SwrContext *resampleContext = static_cast<SwrContext *>(context->opaque);
if (!resampleContext) {
result =
swr_alloc_set_opts2(&resampleContext, // ps
&context->ch_layout, // out_ch_layout
context->request_sample_fmt, // out_sample_fmt
sampleRate, // out_sample_rate
&context->ch_layout, // in_ch_layout
sampleFormat, // in_sample_fmt
sampleRate, // in_sample_rate
0, // log_offset
NULL // log_ctx
);
if (result < 0) {
logError("swr_alloc_set_opts2", result);
av_frame_free(&frame);
return transformError(result);
}
result = swr_init(resampleContext);
if (result < 0) {
logError("swr_init", result);
Expand Down

0 comments on commit 33484b0

Please sign in to comment.