Mapping a Structure containing an array of pointers

393 views
Skip to first unread message

ac

unread,
Feb 1, 2016, 11:47:23 PM2/1/16
to Java Native Access
Hi there,

I'm struggling to map to Java the following structure (from GStreamer):

struct GstVideoFrame {
  GstVideoInfo info;
  GstVideoFrameFlags flags;

  GstBuffer *buffer;
  gpointer   meta;
  gint       id;

  gpointer   data[GST_VIDEO_MAX_PLANES];
  GstMapInfo map[GST_VIDEO_MAX_PLANES];
};

(full docs here). From reading various online examples, I got to the following:

public static class VideoFrameStruct extends com.sun.jna.Structure {

      public static class ByReference extends VideoFrameStruct implements com.sun.jna.Structure.ByReference {}

      

      public volatile VideoInfoStruct.ByReference info;

      public volatile int /*VideoFrameFlags*/ flags; // maybe just int?


      public volatile Buffer buffer;

      public volatile Pointer meta;

      public volatile int id;


      public volatile Pointer[] data = new Pointer[GST_VIDEO_MAX_PLANES];

      public volatile GstBufferAPI.MapInfoStruct[] map = new GstBufferAPI.MapInfoStruct[GST_VIDEO_MAX_PLANES];

      

      @Override

      protected List<String> getFieldOrder() {

        return Arrays.asList(new String[]{

          "info", "flags", "buffer", "meta", "id", "data", "map"

        });

      }

}


But I get either sefgaults or "Array fields must be initialized" errors (if I don't explicitly create the arrays as shown above). 


Any pointers will be appreciated :-)


Andres

Timothy Wall

unread,
Feb 3, 2016, 6:16:52 AM2/3/16
to jna-...@googlegroups.com
Structure reference/by value usage is mapped according to the most common use cases in C.

If you see a field that is `struct`, use `Structure`. Structure.ByValue is implied.
If you see a field that is `struct*`, use `Structure.ByReference`. That field is a pointer.

If you see a parameter that is `struct*`, use `Structure`. Structure.ByReference is implied. That parameter is a pointer.
If you see a parameter that is `struct`, use `Structure.ByValue`.
> --
> You received this message because you are subscribed to the Google Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

ac

unread,
Feb 3, 2016, 11:44:19 AM2/3/16
to Java Native Access
Thanks for your answer, it helped me to identify at least one error in my Java Structure: the field info should be VideoInfoStruct instead of VideoInfoStruct.ByReference since the original C code is "GstVideoInfo info". So I don't get any more segfaults with the following:

public static class VideoFrameStruct extends com.sun.jna.Structure {
    public static class ByReference extends VideoFrameStruct implements com.sun.jna.Structure.ByReference { }
      
    public volatile VideoInfoStruct info;
    public volatile int flags;

    public volatile Buffer buffer;
    public volatile Pointer meta;
    public volatile int id;

    public volatile Pointer[] data = new Pointer[GST_VIDEO_MAX_PLANES];
    public volatile GstBufferAPI.MapInfoStruct[] map = new GstBufferAPI.MapInfoStruct[GST_VIDEO_MAX_PLANES];
      
    @Override
    protected List<String> getFieldOrder() {
      return Arrays.asList(new String[]{
        "info", "flags", "buffer", "meta", "id", "data", "map"
      });
    }
}

However, I'm still not sure how to obtain a valid reference to a VideoFrameStruct structure. The C code using GstVideoFrame looks like:

GstVideoFrame v_frame;
if (!gst_video_frame_map (&v_frame, &v_info, buf, flags)) {
  g_warning ("Failed to map the video buffer");
}

which I'm mapping as:

VideoFrameStruct.ByReference frame = new VideoFrameStruct.ByReference();

boolean res = GSTVIDEO_API.gst_video_frame_map(frame, info, buffer, flags);


Although my gst_video_frame_map() call from Java does not generate more segfaults, the frame structure is essentially empty, i.e.:  the buffer and meta fields are null, as well as all the entries in data.

I'm wondering if instead of creating a reference to VideoFrameStruct in Java, should I create it with same native call?

Thanks!

Andres

Timothy Wall

unread,
Feb 4, 2016, 5:52:24 AM2/4/16
to jna-...@googlegroups.com
>

You can use VideoFrameStruct, there’s no need for the .ByReference when passing a parameter, “struct *” is inferred as the default.

Are these new mappings for gstreamer? There were some created a long time ago...

> However, I'm still not sure how to obtain a valid reference to a VideoFrameStruct structure. The C code using GstVideoFrame looks like:
>
> GstVideoFrame v_frame;
> if (!gst_video_frame_map (&v_frame, &v_info, buf, flags)) {
> g_warning ("Failed to map the video buffer");
> }
>
> which I'm mapping as:
>
> VideoFrameStruct.ByReference frame = new VideoFrameStruct.ByReference();
>
> boolean res = GSTVIDEO_API.gst_video_frame_map(frame, info, buffer, flags);
>
>
> Although my gst_video_frame_map() call from Java does not generate more segfaults, the frame structure is essentially empty, i.e.: the buffer and meta fields are null, as well as all the entries in data.

You can manually call Structure.read() after the call; while that is not the final solution, it _will_ indicate whether the native code is actually populating your native memory. Normally JNA will do this for you automatically.

Neil C Smith

unread,
Feb 4, 2016, 5:56:38 AM2/4/16
to jna-users
On 4 February 2016 at 10:52, Timothy Wall <twal...@java.net> wrote:
> Are these new mappings for gstreamer? There were some created a long time ago...

This is all part of a fork of the original GStreamer 0.10 bindings to
support GStreamer 1.x And (slowly) update them with newer JNA
features.

https://github.com/gstreamer-java/gst1-java-core

Best wishes,

Neil

--
Neil C Smith
Artist : Technologist : Adviser
http://neilcsmith.net

Praxis LIVE - hybrid visual IDE for creative coding - www.praxislive.org
Digital Prisoners - interactive spaces and projections -
www.digitalprisoners.co.uk

ac

unread,
Feb 5, 2016, 7:49:55 AM2/5/16
to Java Native Access
> However, I'm still not sure how to obtain a valid reference to a VideoFrameStruct structure. The C code using GstVideoFrame looks like:
>
> GstVideoFrame v_frame;
> if (!gst_video_frame_map (&v_frame, &v_info, buf, flags)) {
>   g_warning ("Failed to map the video buffer");
> }
>
> which I'm mapping as:
>
> VideoFrameStruct.ByReference frame = new VideoFrameStruct.ByReference();
>
> boolean res = GSTVIDEO_API.gst_video_frame_map(frame, info, buffer, flags);
>
>
> Although my gst_video_frame_map() call from Java does not generate more segfaults, the frame structure is essentially empty, i.e.:  the buffer and meta fields are null, as well as all the entries in data.

You can manually call Structure.read() after the call; while that is not the final solution, it _will_ indicate whether the native code is actually populating your native memory.  Normally JNA will do this for you automatically.

Ok, I added a frame.read() call right after the native function gst_video_frame_map(), but the struct is still empty. 

Based on some examples I found online, I tried defining constructors with the Pointer p argument that call read():

public static class VideoFrameStruct extends com.sun.jna.Structure {
   public static class ByReference extends VideoFrameStruct implements com.sun.jna.Structure.ByReference { 
        
   public ByReference() { }
     public ByReference(Pointer p) { 
         super(p);
         read();
     }        
   }
   public VideoFrameStruct() { }
   public VideoFrameStruct(Pointer p) { 
       super(p);
       read();
   }
  ...
}

but these constructors don't get invoked. Is there anything else I should consider on the Java side? 

Timothy Wall

unread,
Feb 5, 2016, 8:22:08 AM2/5/16
to jna-...@googlegroups.com

> On Feb 5, 2016, at 7:49 AM, ac <andres....@gmail.com> wrote:
>
> > However, I'm still not sure how to obtain a valid reference to a VideoFrameStruct structure. The C code using GstVideoFrame looks like:
> >
> > GstVideoFrame v_frame;
> > if (!gst_video_frame_map (&v_frame, &v_info, buf, flags)) {
> > g_warning ("Failed to map the video buffer");
> > }
> >
> > which I'm mapping as:
> >
> > VideoFrameStruct.ByReference frame = new VideoFrameStruct.ByReference();
> >
> > boolean res = GSTVIDEO_API.gst_video_frame_map(frame, info, buffer, flags);
> >
> >
> > Although my gst_video_frame_map() call from Java does not generate more segfaults, the frame structure is essentially empty, i.e.: the buffer and meta fields are null, as well as all the entries in data.
>
> You can manually call Structure.read() after the call; while that is not the final solution, it _will_ indicate whether the native code is actually populating your native memory. Normally JNA will do this for you automatically.
>
> Ok, I added a frame.read() call right after the native function gst_video_frame_map(), but the struct is still empty.

Calling Structure.read() within the Pointer-based constructor is correct. You almost always want to synch the Java fields when initializing based on a native pointer.

However, if the native memory is never modified (also visible with -Djna.dump_memory=true on Structure.toString()), then it means your native code is not seeing the pointer that’s being passed in or not writing to it.

The former may mean you’ve got a mismatch between “struct” and “struct *” somewhere.

The latter may mean you’re using the function(s) incorrectly.

What’s the native signature for gst_video_frame_map()? Maybe it’s expecting “struct**” and it’s trying to “return” a “struct*” to you?


ac

unread,
Feb 5, 2016, 11:55:55 AM2/5/16
to Java Native Access
Yes, there must be something wrong with my mappings, these structs are tricky because they point to other structures, sometimes by value, sometimes by reference ... I will look into it.
 

ac

unread,
Feb 7, 2016, 11:08:32 PM2/7/16
to Java Native Access
I found the problem, the mappings were correct, but I was freeing a structure in the wrong spot :-)

One last question. This line of C:

guint id = *(guint *) cframe.data[0];


would translate as:


int id = jframe.data[0].getPointer(0).getInt(0)


, right? The types are as I posted earlier (cframe.data is an gpointer array, and jframe.data the corresponding JNA mapping, a Pointer array).

Timothy Wall

unread,
Feb 8, 2016, 7:32:17 AM2/8/16
to jna-...@googlegroups.com
I realize that by this point you’re probably intimately familiar with the different types in question, but no one else is :)

Always include full C and Java declarations.

If data[0] is a Pointer, then you can just call getInt(0) on it.
If data[0] is a PointerType, then you call getPointer().getInt(0) on it.

getPointer(0) is going to pull a pointer value from the original pointer’s destination, which is most likely _not_ what you want.
Reply all
Reply to author
Forward
0 new messages