how to get a direct byte buffer from an address location
Asked Answered
R

3

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?

Romine answered 3/10, 2018 at 9:55 Comment(4)
You can't access memory without knowing how much you can safety access.Natal
Size of the data is not unknown, it is mat.total() * mat.channels()Nicety
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).Trephine
@DanMašek. thanks for that.Romine
N
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;
}
Natal answered 3/10, 2018 at 10:8 Comment(5)
can you give an example of how to wrap the address?Romine
@Romine I have added a simple example. BTW This won't compile on Java 9+, but you can do something similar.Natal
Exactly what bad thing will happen to me if I do this?Laicize
@Laicize The use of DirectBuffer won't compile on Java 9+. However, there are work arounds. e.g. compile it on Java 8.Natal
Ah. How I despise Java 9. I think Project Jigsaw is universally loathed except by the folks at Oracle.Laicize
B
2

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.

Beene answered 4/10, 2018 at 5:27 Comment(0)
R
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

Reilly answered 4/10, 2018 at 5:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.