0

In this opencv example, the Mat object has a nativeObj field, returning a long that represents the address of the object (i.e 140398889556640). Because the size of the data within the object is known, I wish to access the contents of the Mat object directly, returning a byte buffer.

What is the best way to do so?

zcaudate
  • 13,998
  • 7
  • 64
  • 124
  • You can't access memory without knowing how much you can safety access. – Peter Lawrey Oct 03 '18 at 10:06
  • Size of the data is not unknown, it is mat.total() * mat.channels() – Dmitrii Z. Oct 03 '18 at 11:29
  • Rather than `nativeObj` (which would point to the `cv::Mat` instance, not the pixels), it would seem you want `dataAddr`. Looking at the source code, it gives you value `cv::Mat::data`, which points to the pixel data. Keep in mind that you also have to account for situations where the data is not continuous (usually if the `Mat` represents of ROI of a bigger image). – Dan Mašek Oct 03 '18 at 13:13
  • @DanMašek. thanks for that. – zcaudate Oct 03 '18 at 14:46

3 Answers3

4

You can wrap the address with a DirectByteBuffer or use Unsafe.

While you can do this, you probably shouldn't. I would explore all other options first.

// Warning: only do this if there is no better option

public static void main(String[] args) {
    ByteBuffer bb = ByteBuffer.allocateDirect(128);
    long addr = ((DirectBuffer) bb).address();

    ByteBuffer bb2 = wrapAddress(addr, bb.capacity());

    bb.putLong(0, 0x12345678);
    System.out.println(Long.toHexString(bb2.getLong(0)));
}

static final Field address, capacity;
static {
    try {
        address = Buffer.class.getDeclaredField("address");
        address.setAccessible(true);
        capacity = Buffer.class.getDeclaredField("capacity");
        capacity.setAccessible(true);

    } catch (NoSuchFieldException e) {
        throw new AssertionError(e);
    }
}

public static ByteBuffer wrapAddress(long addr, int length) {
    ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder());
    try {
        address.setLong(bb, addr);
        capacity.setInt(bb, length);
        bb.clear();
    } catch (IllegalAccessException e) {
        throw new AssertionError(e);
    }
    return bb;
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

If you don't want to use Unsafe and want something that works without warnings in Java 9 and is actually portable across JVMs you can use JNIs NewDirectByteBuffer. This is API and guaranteed to work.

You will need to write some C (or C++) code however and ship a native library with your code.

Philippe Marschall
  • 4,452
  • 1
  • 34
  • 52
0

There is a tiny framework called "nalloc" which is designed to help developer with memory/pointers manipulations, it could be useful for whatever purposes you are looking for direct memory address accessing.

Also it brings you ability to write your Java program in a C-style, doing memory stuff manually.

Check it out: https://github.com/alaisi/nalloc

Beastmaster
  • 376
  • 2
  • 10