[FFmpeg-trac] #10140(undetermined:new): swscale() crash in Android starting from API31

FFmpeg trac at avcodec.org
Tue Jan 17 14:20:25 EET 2023


#10140: swscale() crash in Android starting from API31
-------------------------------------+-------------------------------------
             Reporter:  fabienst     |                    Owner:  (none)
                 Type:  defect       |                   Status:  new
             Priority:  important    |                Component:
                                     |  undetermined
              Version:  git-master   |               Resolution:
             Keywords:  swscale      |               Blocked By:
             Blocking:               |  Reproduced by developer:  0
Analyzed by developer:  0            |
-------------------------------------+-------------------------------------
Description changed by fabienst:

Old description:

> 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'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 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.
>
> 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 would like to provide the input picture but I don't know how to make a
> file out of this bitmap object. However, I attached the jpeg just in
> case.
>
> I also attached the material that the android emulator collects to
> produce bug reports.
>
> 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:
> {{{
> /* 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;
> }
> }}}

New description:

 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 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.

 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.

 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:
 {{{
 /* 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;
 }
 }}}

--
-- 
Ticket URL: <https://trac.ffmpeg.org/ticket/10140#comment:5>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list