JNI-Android中的分配和释放问题
我一直在尝试使用C库在Android下对两个wav文件进行卷积。 我总是得到空输出。我试图找出问题所在,但我注意到阵列分配不正确。 代码如下:JNI-Android中的分配和释放问题,android,c,java-native-interface,Android,C,Java Native Interface,我一直在尝试使用C库在Android下对两个wav文件进行卷积。 我总是得到空输出。我试图找出问题所在,但我注意到阵列分配不正确。 代码如下: int transform(double real[], double imag[], size_t n) { if (n == 0) return 1; else // More complicated algorithm for arbitrary sizes { return trans
int transform(double real[], double imag[], size_t n) {
if (n == 0)
return 1;
else // More complicated algorithm for arbitrary sizes
{
return transform_bluestein(real, imag, n);
__android_log_print(ANDROID_LOG_VERBOSE, "log", "inside transform ", 1);
}
}
int inverse_transform(double real[], double imag[], size_t n) {
__android_log_print(ANDROID_LOG_VERBOSE, "log", "inside ifft ", 1);
return transform(imag, real, n);
}
int transform_bluestein(double real[], double imag[], size_t n) {
// Variables
int status = 0;
double *cos_table, *sin_table;
double *areal, *aimag;
double *breal, *bimag;
double *creal, *cimag;
size_t m;
size_t size_n, size_m;
size_t i;
JNIEnv *env;
jobject obj;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "start bluestein ", 1);
// Find a power-of-2 convolution length m such that m >= n * 2 + 1
{
size_t target;
if (n > (SIZE_MAX - 1) / 2)
{
__android_log_print(ANDROID_LOG_VERBOSE, "log", "return zero ", 1);
return 0;
}
target = n * 2 + 1;
for (m = 1; m < target; m *= 2) {
if (SIZE_MAX / 2 < m)
{
__android_log_print(ANDROID_LOG_VERBOSE, "log", "return 0", 1);
return 0;
}
}
}
// Allocate memory
if (SIZE_MAX / sizeof(double) < n || SIZE_MAX / sizeof(double) < m)
return 0;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "allocate ", 1);
size_n = n * sizeof(double);
size_m = m * sizeof(double);
cos_table = malloc(size_n);
sin_table = malloc(size_n);
__android_log_print(ANDROID_LOG_VERBOSE, "log", "inside allocate ", 1);
areal = calloc(m, sizeof(double));
aimag = calloc(m, sizeof(double));
breal = calloc(m, sizeof(double));
bimag = calloc(m, sizeof(double));
creal = malloc(size_m);
cimag = malloc(size_m);
if (cos_table == NULL || sin_table == NULL
|| areal == NULL || aimag == NULL
|| breal == NULL || bimag == NULL
|| creal == NULL || cimag == NULL)
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "finished allocation", 1);
// Trignometric tables
for (i = 0; i < n; i++) {
double temp = M_PI * (size_t)((unsigned long long)i * i % ((unsigned long long)n * 2)) / n;
// Less accurate version if long long is unavailable: double temp = M_PI * i * i / n;
cos_table[i] = cos(temp);
sin_table[i] = sin(temp);
// __android_log_print(ANDROID_LOG_VERBOSE, "log", "inside for %d ", i);
}
// Temporary vectors and preprocessing
for (i = 0; i < n; i++) {
areal[i] = real[i] * cos_table[i] + imag[i] * sin_table[i];
aimag[i] = -real[i] * sin_table[i] + imag[i] * cos_table[i];
// __android_log_print(ANDROID_LOG_VERBOSE, "log", "inside for %d ", i);
}
breal[0] = cos_table[0];
bimag[0] = sin_table[0];
for (i = 1; i < n; i++) {
breal[i] = breal[m - i] = cos_table[i];
bimag[i] = bimag[m - i] = sin_table[i];
// __android_log_print(ANDROID_LOG_VERBOSE, "log", "inside for %d ", i);
}
__android_log_print(ANDROID_LOG_VERBOSE, "log", "before postprocessing ", i);
// // Convolution
// if (!Java_com_example_convolution_MainActivity_convolution(env, obj, areal, aimag, breal, bimag, creal, cimag, m))
// goto cleanup;
// Postprocessing
for (i = 0; i < n; i++) {
real[i] = creal[i] * cos_table[i] + cimag[i] * sin_table[i];//------------------- (problem starts here)
imag[i] = -creal[i] * sin_table[i] + cimag[i] * cos_table[i];
// __android_log_print(ANDROID_LOG_VERBOSE, "log", "inside for %d ", i);
}
status = 1;
// Deallocation
cleanup:
free(cimag);
free(creal);
free(bimag);
free(breal);
free(aimag);
free(areal);
free(sin_table);
free(cos_table);
return status;
}
JNIEXPORT jint JNICALL Java_com_example_convolution_MainActivity_convolution (JNIEnv *env, jobject obj, jdoubleArray xreal, jdoubleArray ximag, jdoubleArray yreal, jdoubleArray yimag, jdoubleArray outreal, jdoubleArray outimag, jsize n)
{
jint status = 0;
size_t size;
size_t i;
jdouble *xr, *xi, *yr, *yi;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "start of convolution ", 1);
if (SIZE_MAX / sizeof(double) < n)
return 0;
size = n * sizeof(double);
xr = (*env)->GetDoubleArrayElements(env, xreal, 0);
xi = (*env)->GetDoubleArrayElements(env, ximag, 0);
yr = (*env)->GetDoubleArrayElements(env, yreal, 0);
yi = (*env)->GetDoubleArrayElements(env, yimag, 0);
if (xr == NULL || xi == NULL || yr == NULL || yi == NULL)
{
goto cleanup;
}
__android_log_print(ANDROID_LOG_VERBOSE, "log", "after allocation ", 1);
transform(xr,xi,n);
transform(yr,yi,n);
if (!transform(xr, xi, n))
{
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "transform(xr,xi,n) not performed ", 1);
}
if (!transform(yr, yi, n))
{
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "transform(yr,yi,n) not performed ", 1);
}
__android_log_print(ANDROID_LOG_VERBOSE, "log", "after fft ", 1);//------------------------not showing
for (i = 0; i < n; i++) {
double temp = xr[i] * yr[i] - xi[i] * yi[i];
xi[i] = xi[i] * yr[i] + xr[i] * yi[i];
xr[i] = temp;
//__android_log_print(ANDROID_LOG_VERBOSE, "log", "inside for convolution", 1);//---------------------not showing
}
inverse_transform(xr,xi,n);
if (!inverse_transform(xr, xi, n))
{
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "inverse_transform(xr,xi,n) not performed ", 1);
}
// for (i = 0; i < n; i++) { // Scaling (because this FFT implementation omits it)
// outreal[i] = xr[i] / n;
// outimag[i] = xi[i] / n;
// }
status = 1;
cleanup:
//free(yi);
(*env)->ReleaseDoubleArrayElements(env, yimag, yi, 0);
//free(yr);
(*env)->ReleaseDoubleArrayElements(env, yreal, yr, 0);
//free(xi);
(*env)->ReleaseDoubleArrayElements(env, ximag, xi, 0);
//free(xr);
(*env)->ReleaseDoubleArrayElements(env, xreal, xr, 0);
return status;
}
在
Java\u com\u example\u convolution\u main activity\u convolution
函数中,您从不访问outreal
和outimag
参数
你把它注释掉了。没有任何输出是正常的
更新:
您必须首先获得outreal
和outimag
上的指针,就像您对输入图像所做的那样
jdouble *xr, *xi, *yr, *yi;
jdouble *or, *oi; // <-- add this declaration
...
xr = (*env)->GetDoubleArrayElements(env, xreal, 0);
xi = (*env)->GetDoubleArrayElements(env, ximag, 0);
// add the two lines below
or = (*env)->GetDoubleArrayElements(env, outreal, 0);
oi = (*env)->GetDoubleArrayElements(env, outimag, 0);
...
// for (i = 0; i < n; i++) { // Scaling (because this FFT implementation omits it)
// outreal[i] = xr[i] / n;
// outimag[i] = xi[i] / n;
// }
// This now copies the result in or and oi
for (i = 0; i < n; i++) { // Scaling (because this FFT implementation omits it)
or[i] = xr[i] / n;
oi[i] = xi[i] / n;
}
...
//free(xi);
(*env)->ReleaseDoubleArrayElements(env, ximag, xi, 0);
//free(xr);
(*env)->ReleaseDoubleArrayElements(env, xreal, xr, 0);
// Add the two lines below
//free(oi);
(*env)->ReleaseDoubleArrayElements(env, outimag, oi, 0);
//free(or);
(*env)->ReleaseDoubleArrayElements(env, outreal, or, 0);
jdouble*xr,*xi,*yr,*yi;
jdouble*或,*oi;//GetDoubleArrayElements(环境、xreal、0);
席=(*Env)-> GeDouthRayRayes(Env,Ximag,0);
//添加下面的两行
或者=(*env)->GetDoubleArrayElements(env,outreal,0);
oi=(*env)->GetDoubleArrayElements(env,outimag,0);
...
//对于(i=0;i释放的脲分子(Env,XimAg,席,0);
//免费(xr);
(*env)->释放双数组元素(env、xreal、xr、0);
//添加下面的两行
//免费(oi);
(*env)->发布双数组元素(env、outimag、oi,0);
//免费(或免费);
(*env)->ReleaseDoubleArrayElements(env、outreal或0);
JNIEXPORT jint JNICALL Java\u com\u示例\u卷积\u主要活动\u卷积(JNIEnv*env、jobject obj、jdoubleArray xreal、jdoubleArray ximag、jdoubleArray yreal、jdoubleArray yimag、jdoubleArray outreal、jdoubleArray outimag、jsizen)
{
jint状态=0;
大小;
尺寸i;
jdouble*xr,*xi,*yr,*yi,*或,*oi;
__安卓日志打印(安卓日志详细,“日志”,“卷积开始”,1);
如果(最大尺寸/尺寸(双)GetDoubleArrayElements(env,xreal,0);
席=(*Env)-> GeDouthRayRayes(Env,Ximag,0);
yr=(*env)->GetDoubleArrayElements(env,yreal,0);
yi=(*env)->GetDoubleArrayElements(env,yimag,0);
或者=(*env)->GetDoubleArrayElements(env,outreal,0);
oi=(*env)->GetDoubleArrayElements(env,outimag,0);
如果(XR)!席!!!!!!!
去清理;
__安卓日志打印(安卓日志详细,“日志”,“分配后”,1);
//这是要消除的两个重复变换
//变换(XR,席,N);
//变换(yr,yi,n);
如果(…变换(XR,席席,N))/ /释放的UBB(Env,Ximag,Xi,0);
(*env)->释放双数组元素(env、xreal、xr、0);
(*env)->发布双数组元素(env、outimag、oi,0);
(*env)->ReleaseDoubleArrayElements(env、outreal或0);
返回状态;
}
您的意思是输出用零填充?也许这是因为XR和席是N。您是否尝试在or和oi中写入常量值以测试写入是否有效?你肯定需要我给你的代码,这是你的代码中缺少的。从Java调用函数时,还必须传递两个输出缓冲区。另一个问题是,每个转换调用两次。这将取消转换!所以你不需要计算数据的卷积。我将更新我的答案,向您展示如何解决这个问题。请注意,优化代码是可能的。在transform\u bluestein
中,您计算存储在分配块中的数据,这些数据对于所有三种变换都是相同的。你可以计算它们一次,然后在每次转换中重复使用。这很奇怪。。我完全照你说的做了我还是得到零。你的意思是我应该去掉副本,改用数组吗?上面的代码现在应该可以了。首先尝试注释掉卷积,看看是否在输出中返回x。这将允许您测试分配和转换是否按预期工作。
jdouble *xr, *xi, *yr, *yi;
jdouble *or, *oi; // <-- add this declaration
...
xr = (*env)->GetDoubleArrayElements(env, xreal, 0);
xi = (*env)->GetDoubleArrayElements(env, ximag, 0);
// add the two lines below
or = (*env)->GetDoubleArrayElements(env, outreal, 0);
oi = (*env)->GetDoubleArrayElements(env, outimag, 0);
...
// for (i = 0; i < n; i++) { // Scaling (because this FFT implementation omits it)
// outreal[i] = xr[i] / n;
// outimag[i] = xi[i] / n;
// }
// This now copies the result in or and oi
for (i = 0; i < n; i++) { // Scaling (because this FFT implementation omits it)
or[i] = xr[i] / n;
oi[i] = xi[i] / n;
}
...
//free(xi);
(*env)->ReleaseDoubleArrayElements(env, ximag, xi, 0);
//free(xr);
(*env)->ReleaseDoubleArrayElements(env, xreal, xr, 0);
// Add the two lines below
//free(oi);
(*env)->ReleaseDoubleArrayElements(env, outimag, oi, 0);
//free(or);
(*env)->ReleaseDoubleArrayElements(env, outreal, or, 0);
JNIEXPORT jint JNICALL Java_com_example_convolution_MainActivity_convolution (JNIEnv *env, jobject obj, jdoubleArray xreal, jdoubleArray ximag, jdoubleArray yreal, jdoubleArray yimag, jdoubleArray outreal, jdoubleArray outimag, jsize n)
{
jint status = 0;
size_t size;
size_t i;
jdouble *xr, *xi, *yr, *yi, *or, *oi;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "start of convolution ", 1);
if (SIZE_MAX / sizeof(double) < n)
return 0;
size = n * sizeof(double);
xr = (*env)->GetDoubleArrayElements(env, xreal, 0);
xi = (*env)->GetDoubleArrayElements(env, ximag, 0);
yr = (*env)->GetDoubleArrayElements(env, yreal, 0);
yi = (*env)->GetDoubleArrayElements(env, yimag, 0);
or = (*env)->GetDoubleArrayElements(env, outreal, 0);
oi = (*env)->GetDoubleArrayElements(env, outimag, 0);
if (!xr || !xi || !yr || !yi || !or || !oi)
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "after allocation ", 1);
// These are two duplicate transforms to get rid of
// transform(xr,xi,n);
// transform(yr,yi,n);
if (!transform(xr, xi, n)) // <- this performs the transform on x
{
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "transform(xr,xi,n) not performed ", 1);
}
if (!transform(yr, yi, n)) // <- this performs the transform on y
{
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "transform(yr,yi,n) not performed ", 1);
}
__android_log_print(ANDROID_LOG_VERBOSE, "log", "after fft ", 1);//------------------------not showing
for (i = 0; i < n; i++)
{
double temp = xr[i] * yr[i] - xi[i] * yi[i];
xi[i] = xi[i] * yr[i] + xr[i] * yi[i];
xr[i] = temp;
//__android_log_print(ANDROID_LOG_VERBOSE, "log", "inside for convolution", 1);//---------------------not showing
}
// This inverse transform is also a duplicate
// inverse_transform(xr,xi,n);
if (!inverse_transform(xr, xi, n)) // <-- this performs the inverse transform
{
goto cleanup;
__android_log_print(ANDROID_LOG_VERBOSE, "log", "inverse_transform(xr,xi,n) not performed ", 1);
}
// This now copies the result in or and oi
for (i = 0; i < n; i++) { // Scaling (because this FFT implementation omits it)
or[i] = xr[i] / n;
oi[i] = xi[i] / n;
}
status = 1;
cleanup:
(*env)->ReleaseDoubleArrayElements(env, yimag, yi, 0);
(*env)->ReleaseDoubleArrayElements(env, yreal, yr, 0);
(*env)->ReleaseDoubleArrayElements(env, ximag, xi, 0);
(*env)->ReleaseDoubleArrayElements(env, xreal, xr, 0);
(*env)->ReleaseDoubleArrayElements(env, outimag, oi, 0);
(*env)->ReleaseDoubleArrayElements(env, outreal, or, 0);
return status;
}