[FFmpeg-trac] #10140(undetermined:new): swscale() crash in Android starting from API31
FFmpeg
trac at avcodec.org
Tue Jan 17 15:44:44 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 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;
> }
> }}}
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 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 {{{test.c}}}
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;
}
}}}
--
--
Ticket URL: <https://trac.ffmpeg.org/ticket/10140#comment:7>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker
More information about the FFmpeg-trac
mailing list