1

I am new to javacpp i know java have not much experience in c++. This might be one of very simple question but i am struggling with this. How to access any variable type value written in header of c++ into java code using javacpp. Let us consider example:

C++ Code example:

There is function written in C++ which return the frame of video below is the code for it and expects an Struct argument to be passed.

unsigned char *
Videodecode::getframe_data (void *ptr)
{
  GstSample *sample;
  GstBuffer *buffer;
  GstMapInfo map;
  GstCaps *caps;
  GstStructure *str;
  gint width, height;
  gstData *dataa = (gstData *) ptr;

  sample = gst_app_sink_pull_sample ((GstAppSink*)dataa->sink);

  if (sample != NULL) {

    buffer = gst_sample_get_buffer (sample);
    gst_buffer_map (buffer, &map, GST_MAP_READ);
    if (map.data != NULL) {
      caps = gst_sample_get_caps (sample);
      if (caps != NULL);
      str = gst_caps_get_structure (caps, 0);
      if (!gst_structure_get_int (str, "width", &width) ||
          !gst_structure_get_int (str, "height", &height)) {
        g_print ("No width/height available\n");
      }
      display_data = map.data;
      //displayImg = Mat (Size (width, height ), CV_8UC3, map.data);
 //   cvtColor (displayImg, displayImg, COLOR_YUV2BGR_YUY2);

      gst_buffer_unmap (buffer, &map);
      gst_buffer_unref (buffer);
    } else
      gst_sample_unref (sample);

  }
  else {

      //cout << "gstImageBuffer is NULL" << endl;
      return NULL;
  }
  //return displayImg.data;
  return display_data;
}

The structure which need to be passed as argument is below

typedef struct gstData_t
{
  GstElement *pipeline;
  GstElement *source;
  GstElement *demux;
  GstElement *parser;
  GstElement *decoder;
  GstElement *convert;
  GstElement *capsfilter;
  GstElement *sink;
  GstElement *typefind;

} gstData;

Corresponding java code written to access it is below:

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

import org.bytedeco.javacpp.FunctionPointer;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacpp.Pointer;
import org.bytedeco.javacpp.annotation.Name;
import org.bytedeco.javacpp.annotation.NoOffset;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.annotation.Raw;
import org.bytedeco.javacpp.tools.Builder;
import org.bytedeco.javacpp.tools.ParserException;



@Platform(include = {"Videodecode.h",
                    }, 
includepath = {"/usr/include/gstreamer-1.0/","/usr/include/glib-2.0/","/usr/lib/x86_64-linux-gnu/glib-2.0/include/"},
//linkpath = {"/home/ign/git/JavaCppExample/src/main/resources/de/oltzen/javacppexample/"},
link = {"Videodecode"})

public class Videodecode {
    NativeVideodecode nda;
    static {

        Class c = Videodecode.class;

            Builder builder = null;
            try {
                builder = new Builder().classesOrPackages(c.getName());
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoClassDefFoundError e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                File[] outputFiles = builder.build();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ParserException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Loader.load(c);


//      Loader.load(); 

    }

    public Videodecode() {
        nda = new NativeVideodecode();
    }

    public Videodecode(String filename) {
        nda = new NativeVideodecode(filename);
    }

    public boolean filePathCpp(String str){ 
        return nda.filePathCpp(str);
    }

    public boolean settingValCpp(String str){   
        return nda.settingValCpp(str);
    }

    public boolean process_event (int event) {
        return nda.process_event(event);
    }

    public java.nio.ByteBuffer test1122 (String buffer) {       
        return nda.test1122(buffer);
    }

    public java.nio.ByteBuffer test112233 (String buffer) {     
        return nda.test1122(buffer);
    }

    public java.nio.ByteBuffer getframe_data(java.nio.ByteBuffer buffer){
        return nda.getframe_data(buffer);
    }

    public Pointer gstData(){
        return nda.gstData();
    }

    @Name("Videodecode")    
    public static class NativeVideodecode extends Pointer {
        static { 
            Loader.load();
        }

        public NativeVideodecode() {
            allocate();
        }

        public NativeVideodecode(String filename) {
            System.out.println("filename "+filename);
            allocate(filename);
        }

        public NativeVideodecode(Pointer p) {
            super(p);
        }

        private native void allocate(String filename);
        private native void allocate();
        private native boolean filePathCpp(String str);
        private native boolean settingValCpp(String str);
        private native boolean process_event(int event);
        private native java.nio.ByteBuffer test1122(String buffer);
        private native java.nio.ByteBuffer test112233(String buffer);
//      private native boolean test1122(byte[] buffer);
        private native java.nio.ByteBuffer getframe_data (java.nio.ByteBuffer buffer);
        @NoOffset private native Pointer gstData();
    }


}

Problems being faced by me :

  1. How to access Struct from C++ and pass it as an argument using java.
  2. How to access frame data which is unsigned char*.

Approach which i tried to perform this.

  1. To access Struct, i tried using offsetof but not sure how to use it in javacpp.
  2. To access frame data i tried using java.nio.ByteBuffer but seems its not working properly.

While trying to compile code using mvn clean install below error is getting triggered.

[INFO] --- javacpp:1.3:build (javacpp.compiler) @ projecustom ---
[INFO] Detected platform "linux-x86_64"
[INFO] Building for platform "linux-x86_64"
[WARNING] Could not load platform properties for class com.proje.decoder.connectorJavaCpp
[WARNING] Could not load platform properties for class com.proje.decoder.test1234
[INFO] Generating /home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp
[INFO] Compiling /home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/linux-x86_64/libjniVideodecode.so
[INFO] g++ -I/usr/include/gstreamer-1.0/ -I/usr/include/glib-2.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux /home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp -march=x86-64 -m64 -O3 -s -Wl,-rpath,$ORIGIN/ -Wl,-z,noexecstack -Wl,-Bsymbolic -Wall -fPIC -shared -o libjniVideodecode.so -lVideodecode 
/home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp: In function ‘_jobject* Java_com_proje_decoder_Videodecode_00024NativeVideodecode_gstData(JNIEnv*, jobject)’:
/home/ign/eclipse-workspace/projecustom/target/classes/com/proje/decoder/jniVideodecode.cpp:1532:21: error: ‘class Videodecode’ has no member named ‘gstData’
         rptr = ptr->gstData();

edit:

let me try to take one simple example :

C++ Code:

#include <stdio.h>

struct test
{
int a;
std::string b;
};

class Foo {
public:
    int n;
    int m=70;
    test tst;
//    tst.a=10;
//    tst.b="hi";
    Foo(int n) : n(n) { }
    virtual ~Foo() { }
    virtual void bar() {
        printf("Callback in C++ (n == %d)\n", n);
    }
};

void callback(Foo *foo) {
    foo->bar();
}

is it possible to write modify java code below to access a and b variables of struct

package com.ign.examples;

import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;

@Platform(include="Foo.h")
public class VirtualFoo1 {
    static { Loader.load(); }

    public static class Foo extends Pointer {
        static { Loader.load(); }
        public Foo(int n) { allocate(n); }
        private native void allocate(int n);

        @NoOffset public native int n(); public native Foo n(int n);
        @Virtual  public native void bar();
        public native int m();   public native void m(int m);
//        public native @Cast("int") int a(); public native Foo a(int a);
        public native Pointer tst(); public native void tst(Pointer tst);
    }

    public static native void callback(Foo foo);

    public static void main(String[] args) {
        Foo foo = new Foo(13);

        System.out.println(foo.m());

    }
}
  • You'll need to include the header files from GST as well. JavaCPP doesn't do it by itself because it's hard to figure out a way to map everything both automatically and nicely. More information here: https://github.com/bytedeco/javacpp/wiki/Mapping-Recipes – Samuel Audet Jan 17 '20 at 05:34
  • Thanks for reply sir, i have already included all GST libraries the line "includepath = {"/usr/include/gstreamer-1.0/","/usr/include/glib-2.0/","/usr/lib/x86_64-linux-gnu/glib-2.0/include/"}, " and its working fine however i am struggling when trying to get the frame struct from header. gstData is the struct defined under C++ however when retrieving it its erroring out as mentioned in above screenshot of error. – Mohd Shariq Jan 17 '20 at 05:38
  • You need to include the header files themselves, not just the directories where they are. – Samuel Audet Jan 17 '20 at 08:25
  • @SamuelAudet i included all header files too, however issue is not yet resolved, I tried to simplify example for better understanding and took example from javacpp tutorial page : I have edited my question to include that example, how to access struct of c++ in java – Mohd Shariq Jan 17 '20 at 09:59
  • For the second example, it's not using the Parser, so we have to add the native method declarations by hand. – Samuel Audet Jan 17 '20 at 10:31
  • The way you did it for `int a` should work just fine. Please provide more details about what isn't working! Thanks – Samuel Audet Jan 21 '20 at 00:48
  • @SamuelAudet.. Thanks for looking into it , I will try to explain in sentences , What Am I trying to do ? I have a program in C++ which will return frame of video. the structure is getframe_data (void *ptr). I have to somehow accept this frame as bytebuffer in java. Is there any example for it to perform. Any simple program where c++ code is sending char * and java is accepting it and data could be displayed in java. – Mohd Shariq Jan 22 '20 at 03:17
  • If you only need to map something like `getframe_data (void *ptr)`, yes there are examples like this one: https://github.com/bytedeco/javacpp#optimizing-code-performance – Samuel Audet Jan 22 '20 at 21:22
  • The example returns void and i need c++ program to return char * and a java class to accept that frame like something for bytepointer or bytebuffer. like below c++ code class Foo { public: std::string ptr1 = "hello"; unsigned char * test1122 = (unsigned char*) ptr1.c_str(); }; corresponding java be like: public class VirtualFoo { static { Loader.load(); } public static class Foo extends Pointer { public Foo(int n) { allocate(n); } private native void allocate(int n); public native BytePointer test1122(); public native Foo test1122(BytePointer test1122); } } – Mohd Shariq Jan 23 '20 at 03:18
  • However above is not returning the proper result – Mohd Shariq Jan 23 '20 at 03:19
  • A function like `unsigned char *test1122()` would map to `@Cast("unsigned char*") BytePointer test1122()`, yes, and that works just fine. Please try it out and let me know if that fails for some reason. – Samuel Audet Jan 28 '20 at 00:15
  • That cast is working however when i am trying to modify the pointer location in c++ and then access again using java below error pops: A fatal error has been detected by the Java Runtime Environment SIGSEGV (0xb) at pc=0x00007f62f3dfdbbe, pid=3403, tid=0x00007f63459da700 Problematic frame: C [libVideodecode.so+0x3bbe] Videodecode::test2211(unsigned char*)+0x6e Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again – Mohd Shariq Jan 29 '20 at 03:48
  • That just means you're not returning a correct value for the pointer. You'll need to figure out where exactly the data is before you can use it... – Samuel Audet Jan 29 '20 at 07:07
  • 1
    @SamuelAudet thanks for help I was able to figure out the data location was not correct as you mentioned. – Mohd Shariq Jan 29 '20 at 08:24
  • In JNA pointer class there is below function, public ByteBuffer getByteBuffer(long offset, long length) { return Native.getDirectByteBuffer(this, this.peer, offset, length).order(ByteOrder.nativeOrder()); } Is there any alternative of this function in Javacpp pointer class ? – Mohd Shariq Jan 29 '20 at 12:01
  • Sure, it's [Pointer.asBuffer()](http://bytedeco.org/javacpp/apidocs/org/bytedeco/javacpp/Pointer.html#asBuffer--). – Samuel Audet Jan 30 '20 at 00:25
  • I already tried this however Its not returning the data present at pointer location, its simply returning the reference, not sure why is this happening... – Mohd Shariq Jan 30 '20 at 04:39
  • Did you make sure to set the `capacity` to something greater than 0? – Samuel Audet Jan 31 '20 at 02:32

0 Answers0