I am trying to read a file in c using NDK. When i debug the code, i see that i get a NULL pointer in f(file reading pointer). Also, my file which i need to read is in the same folder under cpp including all other header files. I have the read and write permissions for external storage in my app. Any help is appreciated.
C Code:
#ifndef client_h
#define client_h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "utility.h"
#define SENDBUFSIZE 1399
#define RECVBUFSIZE 1399
void pingServer(char *hostname, int portno)
{
//Some other functionality which works correctly
// File Read operations
FILE *f = fopen("somefile.csv", "r"); //Get the null pointer here
if (f == NULL)
perror("Could not open input file");
char *currentRow[3];
char *nextRow[3];
int rows = 3;
for (int i=0; i<rows; i++)
{
currentRow[i] = (char*)malloc(20 * sizeof(char));
nextRow[i] = (char*)malloc(20 * sizeof(char));
}
double current, next;
double elapsed;
int isNextRow, isCurentRow;
readCsvLine(f,currentRow,rows); //Get the headers
int counter = 2;
isCurentRow = readCsvLine(f,currentRow,rows);
//sends the data
//Free the memory
for (int i=0; i<rows; i++)
{
free(currentRow[i]);
free(nextRow[i]);
}
free(buf);
return;
}
char* printName(){
char* ptr = "hello From C";
return ptr;
}
#endif
Java code for calling the c methods:
#include <jni.h>
#include <string>
#include "client.h"
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_habbas_mobiledifferentiation_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
char *hostname = "127.0.0.1";
int portno = 1254;
pingServer(hostname, portno);
std::string hello = printName();
return env->NewStringUTF(hello.c_str());
}
Related
I don't know if I'm wrong but I found this solution to bypass Android restriction on private shared library like OpenCL. It copies required libs from /system/vendor/lib64 to /data/data/package.name/ and then loads them by calling dlopen.
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
#include <unistd.h>
#define LOG_TAG "JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
void copy_file(const char* in_path, const char* out_path) {
FILE* fin = fopen(in_path, "rb");
check(fin, "fopen()");
FILE* fout = fopen(out_path, "wb");
check(fout, "fopen()");
unsigned char buffer[255];
size_t ret;
while ((ret = fread(buffer, sizeof(*buffer), ARRAY_SIZE(buffer), fin)) == ARRAY_SIZE(buffer)) {
fwrite(buffer, sizeof(*buffer), ret, fout);
}
if (ferror(fin) != 0) {
LOGE("Error on read");
exit(1);
}
fwrite(buffer, sizeof(*buffer), ret, fout);
fclose(fin);
fclose(fout);
}
void* sdlopen(const char* path){
void *handle;
handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!handle) {
LOGE("#1 %s", dlerror());
exit(1);
}
return handle;
}
void load(){
void *handle, *handle1, *handle2, *handle3, *handle4, *handle5, *handle6;
cl_int (*_clGetPlatformIDs)(cl_uint, cl_platform_id*, cl_uint*);
char *error;
copy_file("/system/vendor/lib64/libOpenCL.so", "/data/data/com.app.opencl/libOpenCL.so");
copy_file("/system/lib64/libcutils.so", "/data/data/com.app.opencl/libcutils.so");
copy_file("/system/lib64/libbase.so", "/data/data/com.app.opencl/libbase.so");
copy_file("/system/lib64/libc++.so", "/data/data/com.app.opencl/libc++.so");
copy_file("/system/lib64/libvndksupport.so", "/data/data/com.app.opencl/libvndksupport.so");
copy_file("/system/lib64/libdl_android.so", "/data/data/com.app.opencl/libdl_android.so");
copy_file("/system/lib64/ld-android.so", "/data/data/com.app.opencl/ld-android.so");
handle1 = sdlopen("/data/data/com.app.opencl/libc++.so");
handle2 = sdlopen("/data/data/com.app.opencl/ld-android.so");
handle3 = sdlopen("/data/data/com.app.opencl/libdl_android.so");
handle4 = sdlopen("/data/data/com.app.opencl/libvndksupport.so");
handle5 = sdlopen("/data/data/com.app.opencl/libbase.so");
handle6 = sdlopen("/data/data/com.app.opencl/libcutils.so");
handle = sdlopen("/data/data/com.app.opencl/libOpenCL.so");
_clGetPlatformIDs = dlsym(handle, "clGetPlatformIDs");
if ((error = dlerror()) != NULL) {
LOGE("#2 %s", error);
exit(1);
}
dlclose(handle);
dlclose(handle1);
dlclose(handle2);
dlclose(handle3);
dlclose(handle4);
dlclose(handle5);
dlclose(handle6);
}
With the code above I can dlopen libOpenCL.so but
dlsym(handle, "clGetPlatformIDs");
returns undefined symbol: JNI_OnLoad. I think it shouldn't look for JNI_OnLoad function. What is wrong?
I'm trying to integrate OpenCV in Android Java native interface using C++ language. I have placed the OpenCV inside the jni folder, where I'm writing my C++ code. I have included the Opencv header files in my HelloNative.c file. But I'm still getting this error while trying to access Mat object.
"Can't resolve variable Mat".
I have tried using namespace cv, but it gives an error to predeclare using and namespace; which is not a solution. I'm posting my code below, please somebody have a look at it and let me know what I'm doing wrong.
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <OpenCV/include/opencv2/opencv.hpp>
#include <OpenCV/include/opencv/cv.h>
#include <OpenCV/modules/core/include/opencv2/core.hpp>
#include <OpenCV/modules/core/include/opencv2/core/core_c.h>
#include <OpenCV/modules/core/include/opencv2/core/mat.hpp>
#include <OpenCV/modules/imgproc/include/opencv2/imgproc/imgproc.hpp>
#include <OpenCV/modules/imgproc/include/opencv2/imgproc/imgproc_c.h>
#include <OpenCV/modules/legacy/include/opencv2/legacy/legacy.hpp>
#include <OpenCV/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp>
#include <OpenCV/modules/videostab/include/opencv2/videostab/global_motion.hpp>
JNIEXPORT jint JNICALL
Java_com_example_soimporttest_MainActivity_getStringFromJNI(JNIEnv *env, jobject thisObj,
jstring imagepath) {
const char *jnamestr = (*env)->GetStringUTFChars(env, imagepath, 0);
int width, height, gray;
FILE *fp = fopen(jnamestr, "rb");
if (fp) {
//Read .pgm file
int scan = fscanf(fp, "P5%d%d%d", &width, &height, &gray);
if (scan != 3 || &gray > 256 || &width > 0xfffff || &height > 0xfffff || &gray <= 1 ||
&width < 32 || &height < 32) {
fclose(fp);
return 9;
} else {
return 0;
}
} else {
return -1;
}
}
JNIEXPORT void JNICALL
Java_com_example_soimporttest_MainActivity_displayImage(JNIEnv *env, jobject thisObj, jclass type, jlong inpAddr, jlong outAddr) {
::Mat &src = *(Mat*)inpAddr;
Mat &dst = *(Mat*)outAddr;
applyFilter(src , dst);
}
There are two functions in this file, the first function getStringFromJNI is working perfectly fine.
Thank you.
After a lot of research, I finally managed to find out a good solution for my question. Please follow below mentioned tutorial:
https://github.com/leadrien/opencv_native_androidstudio
You'll be facing some issues while integrating it. You can post those solutions in the comments and I will guide you through each.
Thanks.
I have compiled ffmpeg code and generated .so files,
Then I put these .so files in jniLibs/armeabi/ folder.
To use it below code :
Controller.java
public class Controller {
static {
System.loadLibrary("avutil");
System.loadLibrary("swresample");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
System.loadLibrary("swscale");
System.loadLibrary("avfilter");
System.loadLibrary("avdevice");
}
public static native void runffmpegCommand(String[] argv);
public static void testFFMPEG(String[] strings) {
runffmpegCommand(new String[]);
}
}
ffmpeg_controller.c
#include <android/log.h>
#include "ffmpeg_Controller.h"
#include <stdlib.h>
#include <stdbool.h>
int main(int argc, char **argv);
JavaVM *sVm = NULL;
jint JNI_OnLoad( JavaVM* vm, void* reserved )
{
sVm = vm;
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL Java_com_test_Controller_runffmpegCommand(JNIEnv *env, jobject obj, jobjectArray args)
{
int i = 0;
int argc = 0;
char **argv = NULL;
jstring *strr = NULL;
if (args != NULL) {
argc = (*env)->GetArrayLength(env, args);
argv = (char **) malloc(sizeof(char *) * argc);
strr = (jstring *) malloc(sizeof(jstring) * argc);
for(i=0;i<argc;i++) { strr[i] = (jstring)(*env)->GetObjectArrayElement(env, args, i);
argv[i] = (char *)(*env)->GetStringUTFChars(env, strr[i], 0);
}
}
main(argc, argv);
for(i=0;i<argc;i++) {
(*env)->ReleaseStringUTFChars(env, strr[i], argv[i]);
}
free(argv);
free(strr);
}
ffmpeg_controller.h
#include <jni.h>
#ifndef _Included_com_test_Controller
#define _Included_com_test_Controller
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_android_com_test_Controller_runffmpegCommand(JNIEnv *, jobject, jobjectArray);
#ifdef __cplusplus
}
#endif
#endif
When I run this code it through error as below:
Logs:
2018-12-17 14:11:17.850 25598-25598/com.android.test E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.test, PID: 25598
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/com.android.test-1/lib/arm/libavutil.so" is 64-bit instead of 32-bit
at java.lang.Runtime.loadLibrary0(Runtime.java:989)
at java.lang.System.loadLibrary(System.java:1530)
I think the problem her because you run application with targetSdkVersion 26 or more so the solution i think it's her look:
https://stackoverflow.com/a/52951886/7055487
The Exception is self-explain: "libavutil.so is 64-bit instead of 32-bit": you have copied a 64 bit library in a "jniLibs" subfolder that expects 32 bit libraries.
"jniLibs/armeabi" subfolder is for 32bit ONLY devices
I am trying out Parcel with native code:
#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
using namespace android;
int main()
{
int32_t i = 123, j = 456;
Parcel data;
status_t t = data.writeInt32(j);
if(t == NO_ERROR)
printf("Status: %d\n", t);
else if(t == BAD_VALUE)
printf("Bad Value\n");
int32_t jj = 0;
t = data.readInt32(&jj);
printf("t: %d\n", t);
printf("ParcelTest: %d\n", jj);
return 0;
}
To compile this code, Android's source tree is needed. Put it under external/ParcelTest. And the Android.mk is here. Run mmma external/ParcelTest to compile.
Output of the program is:
generic_x86:/ # /system/bin/ParcelTest
Status: 0
t: -61
ParcelTest: 0
The Status: 0 indicates that writing value into the Parcel works out. But reading doesn't. So Parcel is the thing that if I read data as the order I write, I would get correct result. Any idea why this code sample fails?
The correct usage is below:
#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
using namespace android;
int main()
{
int32_t i = 123, j = 456;
Parcel data;
status_t t = data.writeInt32(j);
if(t == NO_ERROR)
printf("Status: %d\n", t);
else if(t == BAD_VALUE)
printf("Bad Value\n");
int32_t jj = 0;
data.setDataPosition(0);
t = data.readInt32(&jj);
printf("t: %d\n", t);
printf("ParcelTest: %d\n", jj);
return 0;
}
The read position has to be set manually.
I'm trying to write an app that gets all the frames of a video and manipulating them, I found oout that the best way to extract frames on Android is using OpenCv lib.
I saw in the sample code that uses VideoCapture object that receives the video path and can grab frames out of it, so I wrote the following code but the capture.open() doen't really open the video file, the capture.isOpen() is always false.
Source code:
#include <jni.h>
//opencv
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/background_segm.hpp>
#include <opencv2/core/mat.hpp>
//C
#include <stdio.h>
#include <string.h>
//C++
#include <iostream>
#include <sstream>
//Android
#include <android/log.h>
//#define LOGI(TAG,INFO) __android_log_print(ANDROID_LOG_INFO,INFO,__VA_ARGS__)
using namespace cv;
extern "C" {
JNIEXPORT void JNICALL Java_com_example_nativeopencvcheck_MainActivity_processVideo(JNIEnv* env,
jobject thsObj,jstring fileName) {
const char * fileNameNative;
jboolean isCopy;
fileNameNative = env->GetStringUTFChars(fileName, &isCopy);
//create the capture object
__android_log_print(ANDROID_LOG_ERROR, "From_Native",
"trying to open file: %s", fileNameNative);
VideoCapture capture(fileNameNative);
capture.open(fileNameNative);
if (!capture.isOpened()) { //!!!!!! ALWAYS CLOSED !!!!!
__android_log_write(ANDROID_LOG_ERROR, "From_Native",
"capture isn't open. closing..");
exit( EXIT_FAILURE);
}
Mat iplimage;
capture.retrieve(iplimage,0);
if (iplimage.size > 0) {
jclass cls = env->FindClass( "com/example/opencvframesext/MainActivity");
if (cls == 0) {
return;
}
jmethodID javamethod = env->GetMethodID(cls, "getCurrentFrameFromNative", "()V");
if (javamethod == 0) {
// LOGI("From_Native","GetMethodID error");
return;
}
jobject obj; // TODO
env->CallVoidMethod(obj, javamethod);
return;
}
/*bool gotFrame = capture.read(mat);
while (gotFrame) {
mats.addref(mat);
capture.read(mat);
}*/
//delete capture object
capture.release();
}
}
yea, that wont work, unfortunately.
there's no ffmpeg backend for VideoCapture on android.