Opened 2 years ago
Last modified 12 days ago
#10140 new defect
swscale() crash in Android on x86_64 only (starting from API31)
Reported by: | fabienst | Owned by: | |
---|---|---|---|
Priority: | important | Component: | undetermined |
Version: | git-master | Keywords: | swscale |
Cc: | Blocked By: | ||
Blocking: | Reproduced by developer: | no | |
Analyzed by developer: | no |
Description (last modified by )
I have a crash in my call to sw_scale since Android API 31. I doesn't crash for all inputs, but for now only on the same given picture. It works fine with API 30.
I couldn't reproduce the crash on a device with arm8 + API31. So for now only on x86_64.
I'm calling sw_scale from a native function through JNI which is calling from java.
The input picture is a "Bitmap" object.
The problem still exists in the present snapshot of ffmpeg (2023-01-15). BTW, this LDFLAGS is missing to build for Android: -lnativewindow
If I run the same command from ffmpeg but with directly the jpeg file as input, I don't have a crash, but the input is then a jpeg, while programatically it's a bitmap object.
LD_LIBRARY_PATH=. ./ffmpeg -i /storage/emulated/0/DCIM/test_pics/invalid/image01088.jpg -vf scale=160x45 -sws_flags print_info -sws_flags lanczos -loglevel trace a.jpg
I enabled logging in my program as much as I could. Attached crash_api31.zip
you have also a sample programme that will reveal the error/crash. It can be run from the command line inside an adb shell.
You will find attached the log for the run on a device running android 11 (=API30) and the log for the run on a device with Android 12 (API31). These were made within the Android emulator.
Crash is reported as:
A/libc: Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x7e936e915000 in tid 9755 (ServiceStartArg), pid 9722 (adder.app.debug)
Crash is at this line inside swscale() function:
desc[i].process(c, &desc[i], firstCPosY, lastCPosY - firstCPosY + 1);
I attached the input jpeg but also the file that should contain the input of swscale code (if the way I produced them is correct, I'm not so sure of this).
I also attached the material that the android emulator collects to produce bug reports.
For information, the java code: Algo is LANCZOS, but it fails also with others IIRC
public static Bitmap rescale(Bitmap src, int dstWidth, int dstHeight, AlgoParametrized1 algo, double p0) { int final_algo = algo.flag; if (MainApplication.enableLog) final_algo |= Algo.SWS_PRINT_INFO.flag; return native_rescale(src, Bitmap.createBitmap(dstWidth, dstHeight, src.getConfig()), final_algo | Algo.SWS_PRINT_INFO.flag, p0, 0.0); }
The C code (but you may look at attached test.c) which goes straight to the reproduction of the issue.
/* SPDX-License-Identifier: (BSD-2-Clause or GPL-2.0-only) */ // Adapted for Exif Thumbnail Adder // From: https://raw.githubusercontent.com/ser-gik/smoothrescale/master/smoothrescale/src/main/jni/on_load.c #include <stddef.h> #include <stdint.h> #include <jni.h> #include <android/log.h> #include <android/bitmap.h> #include <libswscale/swscale.h> #include <libavutil/pixfmt.h> #include <libavutil/log.h> #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "schokoladenbrown", __VA_ARGS__) struct bitmap { jobject jbitmap; AndroidBitmapInfo info; uint8_t *buffer; }; static int lock_bitmap(JNIEnv *env, struct bitmap *bm) { int res = AndroidBitmap_getInfo(env, bm->jbitmap, &bm->info); if(ANDROID_BITMAP_RESULT_SUCCESS != res) return res; else return AndroidBitmap_lockPixels(env, bm->jbitmap, (void **)&bm->buffer); } static int unlock_bitmap(JNIEnv *env, struct bitmap *bm) { const static struct bitmap null_bm; int res = AndroidBitmap_unlockPixels(env, bm->jbitmap); *bm = null_bm; return res; } static inline enum AVPixelFormat pix_fmt(enum AndroidBitmapFormat fmt) { /* bitmap formats directly correspond to SkColorType values */ switch (fmt) { case ANDROID_BITMAP_FORMAT_RGBA_8888: /* * kN32_SkColorType * Actually it may be one of kBGRA_8888_SkColorType or kRGBA_8888_SkColorType * and may be configured at build time. Seems like Android uses RGBA order. */ return AV_PIX_FMT_RGBA;; case ANDROID_BITMAP_FORMAT_RGB_565: /* * kRGB_565_SkColorType * This one is packed in native endianness */ return AV_PIX_FMT_RGB565; case ANDROID_BITMAP_FORMAT_A_8: /* * kAlpha_8_SkColorType * There is no appropriate AV_PIX_FMT_* */ /* fall through */ default: return AV_PIX_FMT_NONE; } } static jobject JNICALL native_rescale_impl(JNIEnv *env, jclass clazz, jobject srcBitmap, jobject dstBitmap, jint sws_algo, jdouble p0, jdouble p1) { struct bitmap src = { .jbitmap = srcBitmap }; struct bitmap dst = { .jbitmap = dstBitmap }; jobject ret = NULL; // LOGI("algo %x %lf %lf", sws_algo, p0, p1); if(ANDROID_BITMAP_RESULT_SUCCESS == lock_bitmap(env, &src) && ANDROID_BITMAP_RESULT_SUCCESS == lock_bitmap(env, &dst)) { const uint8_t *src_planes[] = { src.buffer }; const int src_strides[] = { src.info.stride }; uint8_t *dst_planes[] = { dst.buffer }; const int dst_strides[] = { dst.info.stride }; const double params[] = { p0, p1 }; struct SwsContext *ctx; LOGI("%i", __LINE__); LOGI("src %i", src.info.format); LOGI("srcwidth %i", src.info.width); LOGI("srcheight %i", src.info.height); LOGI("dst %i", dst.info.format); LOGI("dst width %i", dst.info.width); LOGI("dst height %i", dst.info.height); LOGI("sws_algo %i", sws_algo); // Set loglevel (uncomment to debug ffmpeg issues) av_log_set_flags(AV_LOG_PRINT_LEVEL | AV_LOG_SKIP_REPEATED); av_log_set_level(AV_LOG_TRACE); ctx = sws_getContext(src.info.width, src.info.height, pix_fmt(src.info.format), dst.info.width, dst.info.height, pix_fmt(dst.info.format), sws_algo, NULL, NULL, params); LOGI("%i", __LINE__); if(ctx) { LOGI("%i", __LINE__); int res = sws_scale(ctx, src_planes, src_strides, 0, src.info.height, dst_planes, dst_strides); LOGI("%i", __LINE__); sws_freeContext(ctx); LOGI("%i", __LINE__); if(res > 0) { ret = dstBitmap; } } } LOGI("%i", __LINE__); unlock_bitmap(env, &src); LOGI("%i", __LINE__); unlock_bitmap(env, &dst); return ret; } static const char *g_rescaler_java_class = "com/schokoladenbrown/Smooth"; static const JNINativeMethod g_native_methods[] = { {"native_rescale", "(Landroid/graphics/Bitmap;Landroid/graphics/Bitmap;IDD)Landroid/graphics/Bitmap;", native_rescale_impl}, }; jint JNI_OnLoad(JavaVM *jvm, void *reserved) { JNIEnv *env = NULL; jclass cls; (*jvm)->AttachCurrentThread(jvm, &env, NULL); cls = (*env)->FindClass(env, g_rescaler_java_class); (*env)->RegisterNatives(env, cls, g_native_methods, sizeof g_native_methods / sizeof g_native_methods[0]); return JNI_VERSION_1_2; }
Attachments (9)
Change History (19)
by , 2 years ago
Attachment: | log-api30C.txt added |
---|
by , 2 years ago
Attachment: | log-api31C.txt added |
---|
by , 2 years ago
Attachment: | image01088.jpg added |
---|
by , 2 years ago
Attachment: | android_dump.tar.gz-aa added |
---|
by , 2 years ago
Attachment: | android_dump.tar.gz-ab added |
---|
by , 2 years ago
Attachment: | android_dump.tar.gz-ac added |
---|
comment:2 by , 2 years ago
Summary: | swscale crash in Android starting from API31 → swscale() crash in Android starting from API31 |
---|
comment:3 by , 2 years ago
Priority: | normal → important |
---|---|
Version: | unspecified → git-master |
comment:4 by , 2 years ago
Additional information:
- Crash happens on other pictures too.
- Crash happens on x86_64 (emulated device with api31) but not on arm8 (real device with api 31)
- Input to swscale() is the same in both cases.
- To reproduce simply with a call to swscale() I managed to produce the file containg the src & dst arrays. You can find them attached.
- API30-dst
- API30-src
- API31-dst
- API31-src
- Other parameter values are:
- For input: format: AV_PIX_FMT_RGBA, height: 120, stride: 1700, width: 425
- For output: format: AV_PIX_FMT_RGBA, height: 45, stride: 640, width: 160
- Algorithm: Lanczos
- Parameter p0: 3.0
- Code to produce these files was (for usage in the function
native_rescale_impl
above):
FILE* pFile; char* yourFilePath = "/storage/emulated/0/DCIM/test_pics/input"; // Reserve memory for your readed buffer char* readedBuffer = malloc(4); if (readedBuffer==0){ LOGI("Can't reserve memory for Test!"); } // Write your buffer to disk. pFile = fopen(yourFilePath,"wb"); if (pFile){ fwrite(*src_planes, 4, src.info.width * src.info.height, pFile); LOGI("Wrote to file!"); } else{ LOGI("Something wrong writing to File."); } fclose(pFile); char* outFilePath = "/storage/emulated/0/DCIM/test_pics/output"; // Reserve memory for your readed buffer int readedBuffer2 = malloc(4); if (readedBuffer2==0){ LOGI("Can't reserve memory for Test!"); } // Write your buffer to disk. pFile = fopen(outFilePath,"wb"); if (pFile){ fwrite(*dst_planes, 4, dst.info.width * dst.info.height, pFile); LOGI("Wrote to file!"); } else { LOGI("Something wrong writing to File."); } fclose(pFile);
comment:5 by , 2 years ago
Description: | modified (diff) |
---|
comment:6 by , 2 years ago
Attached also a sample code that you can build yourself for android: test.c
Building for x86_64
$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android26-clang \ test.c -I./libs.prebuilt/ffmpeg-4.4/include/ -L$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/26/ -llog -L./libs.prebuilt/ffmpeg-4.4/lib/x86_64 -lswscale -lavutil -o x86_64.out
Running on x86_64 does crash
adb ./libs.prebuilt/ffmpeg-4.4/lib/x86_64/libavutil.so ./libs.prebuilt/ffmpeg-4.4/lib/x86_64/libswscale.so input output x86_64.out /data/local/tmp adb shell cd /data/local/tmp LD_LIBRARY_PATH=. ./x86_64.out
Building for arm64
$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android26-clang \ test.c -I./libs.prebuilt/ffmpeg-4.4/include/ -L$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/ -llog -L./libs.prebuilt/ffmpeg-4.4/lib/arm64-v8a -lswscale -lavutil -o arm64.out
Running on arm64 doesn't crash
adb ./libs.prebuilt/ffmpeg-4.4/lib/arm64-v8a/libavutil.so ./libs.prebuilt/ffmpeg-4.4/lib/arm64-v8a/libswscale.so input output arm64.out /data/local/tmp adb shell cd /data/local/tmp LD_LIBRARY_PATH=. ./arm64.out
Prebuilt libs can be found at https://github.com/tenzap/exif-thumbnail-adder/tree/master/libs.prebuilt
comment:7 by , 2 years ago
Description: | modified (diff) |
---|
comment:8 by , 2 years ago
Summary: | swscale() crash in Android starting from API31 → swscale() crash in Android on x86_64 only (starting from API31) |
---|
comment:9 by , 2 years ago
Description: | modified (diff) |
---|
comment:10 by , 12 days ago
Hi,
Can you still reproduce this crash with the current version of FFmpeg? I tried running your code sample but it worked successfully for me, although I was not testing on a real Android device.
The attached android_dump.tar.gz* files have to concatenated (with cat on linux for example) prior to uncompressing.
Maybe this can be of interest: https://stackoverflow.com/a/63148558/15401262
Alternative to reproduce is to use Exif Thumbnail Adder App https://github.com/tenzap/exif-thumbnail-adder/ and make it run on the attached picture (provided the device is API >= 31)