Skip to content

Commit 06214f7

Browse files
pymumuCarlosLeeGit
authored andcommitted
java: add direct buffer API
1 parent 8bff21d commit 06214f7

File tree

5 files changed

+268
-12
lines changed

5 files changed

+268
-12
lines changed

src/java/jni/jni_export/buffer.cc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,61 @@ Java_com_modelbox_Buffer_BufferGetData(JNIEnv *env, jobject j_this) {
123123
return j_data_array;
124124
}
125125

126+
/*
127+
* Class: com_modelbox_Buffer
128+
* Method: BufferGetDirectData
129+
* Signature: ()Ljava/nio/ByteBuffer;
130+
*/
131+
JNIEXPORT jobject JNICALL
132+
Java_com_modelbox_Buffer_BufferGetDirectData(JNIEnv *env, jobject j_this) {
133+
bool is_const = false;
134+
auto n_buffer =
135+
modelbox::JNINativeObject::GetNativeSharedPtr<modelbox::Buffer>(env,
136+
j_this);
137+
if (n_buffer == nullptr) {
138+
modelbox::ModelBoxJNIThrow(env, modelbox::StatusError);
139+
return nullptr;
140+
}
141+
142+
void *n_buffer_ptr = n_buffer->MutableData();
143+
if (n_buffer_ptr == nullptr) {
144+
n_buffer_ptr = (void *)n_buffer->ConstData();
145+
if (n_buffer_ptr == nullptr) {
146+
modelbox::ModelBoxJNIThrow(env, modelbox::STATUS_NOBUFS,
147+
"Buffer data is null");
148+
return nullptr;
149+
}
150+
151+
is_const = true;
152+
}
153+
154+
//TODO The reference to n_bufferlist should be added to avoid dangling pointers of j_byte_buffer
155+
//https://stackoverflow.com/questions/46844275/freeing-memory-wrapped-with-newdirectbytebuffer
156+
jobject j_byte_buffer =
157+
env->NewDirectByteBuffer((void *)n_buffer_ptr, n_buffer->GetBytes());
158+
if (j_byte_buffer == nullptr) {
159+
modelbox::ModelBoxJNIThrow(env, modelbox::STATUS_NOMEM,
160+
"alloc memory for Buffer byte failed.");
161+
return nullptr;
162+
}
163+
164+
if (is_const == false) {
165+
return j_byte_buffer;
166+
}
167+
168+
jmethodID asreadonly_method =
169+
env->GetMethodID(env->GetObjectClass(j_byte_buffer), "asReadOnlyBuffer",
170+
"()Ljava/nio/ByteBuffer;");
171+
if (asreadonly_method == nullptr) {
172+
MBLOG_ERROR << "get asreadonly method failed.";
173+
return nullptr;
174+
}
175+
176+
jobject j_readonly_byte_buffer =
177+
env->CallObjectMethod(j_byte_buffer, asreadonly_method);
178+
return j_readonly_byte_buffer;
179+
}
180+
126181
/*
127182
* Class: com_modelbox_Buffer
128183
* Method: BufferHasError

src/java/jni/jni_export/bufferlist.cc

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,126 @@ Java_com_modelbox_BufferList_BufferListGetData(JNIEnv *env, jobject j_this) {
241241
return j_data;
242242
}
243243

244+
/*
245+
* Class: com_modelbox_BufferList
246+
* Method: BufferListGetDirectData
247+
* Signature: ()Ljava/nio/ByteBuffer;
248+
*/
249+
JNIEXPORT jobject JNICALL
250+
Java_com_modelbox_BufferList_BufferListGetDirectData__(JNIEnv *env,
251+
jobject j_this) {
252+
bool is_const = false;
253+
auto n_bufferlist =
254+
modelbox::JNINativeObject::GetNativeSharedPtr<modelbox::BufferList>(
255+
env, j_this);
256+
if (n_bufferlist == nullptr) {
257+
modelbox::ModelBoxJNIThrow(env, modelbox::StatusError);
258+
return nullptr;
259+
}
260+
261+
void *n_buffer_ptr = n_bufferlist->MutableData();
262+
if (n_buffer_ptr == nullptr) {
263+
n_buffer_ptr = (void *)n_bufferlist->ConstData();
264+
if (n_buffer_ptr == nullptr) {
265+
modelbox::ModelBoxJNIThrow(env, modelbox::STATUS_INVALID,
266+
"buffer list data is null");
267+
return nullptr;
268+
}
269+
is_const = true;
270+
}
271+
272+
auto *j_byte_buffer =
273+
env->NewDirectByteBuffer(n_buffer_ptr, n_bufferlist->GetBytes());
274+
if (j_byte_buffer == nullptr) {
275+
modelbox::Status ret = {modelbox::STATUS_NOMEM,
276+
"alloc memory for buffer list data failed."};
277+
modelbox::ModelBoxJNIThrow(env, ret);
278+
return nullptr;
279+
}
280+
281+
if (is_const == false) {
282+
return j_byte_buffer;
283+
}
284+
285+
jmethodID asreadonly_method =
286+
env->GetMethodID(env->GetObjectClass(j_byte_buffer), "asReadOnlyBuffer",
287+
"()Ljava/nio/ByteBuffer;");
288+
if (asreadonly_method == nullptr) {
289+
modelbox::Status ret = {modelbox::STATUS_NOMEM,
290+
"get asreadonly method failed."};
291+
modelbox::ModelBoxJNIThrow(env, ret);
292+
return nullptr;
293+
}
294+
295+
jobject j_readonly_byte_buffer =
296+
env->CallObjectMethod(j_byte_buffer, asreadonly_method);
297+
return j_readonly_byte_buffer;
298+
}
299+
300+
/*
301+
* Class: com_modelbox_BufferList
302+
* Method: BufferListGetDirectData
303+
* Signature: (J)Ljava/nio/ByteBuffer;
304+
*/
305+
JNIEXPORT jobject JNICALL
306+
Java_com_modelbox_BufferList_BufferListGetDirectData__J(JNIEnv *env,
307+
jobject j_this,
308+
jlong j_index) {
309+
bool is_const = false;
310+
auto n_bufferlist =
311+
modelbox::JNINativeObject::GetNativeSharedPtr<modelbox::BufferList>(
312+
env, j_this);
313+
if (n_bufferlist == nullptr) {
314+
modelbox::ModelBoxJNIThrow(env, modelbox::StatusError);
315+
return nullptr;
316+
}
317+
318+
void *n_buffer_ptr = n_bufferlist->MutableBufferData(j_index);
319+
if (n_buffer_ptr == nullptr) {
320+
n_buffer_ptr = (void *)n_bufferlist->ConstBufferData(j_index);
321+
if (n_buffer_ptr == nullptr) {
322+
if (n_bufferlist->GetBytes() != 0) {
323+
modelbox::ModelBoxJNIThrow(env, modelbox::STATUS_INVALID,
324+
"buffer is not continuous.");
325+
return nullptr;
326+
}
327+
328+
modelbox::ModelBoxJNIThrow(env, modelbox::STATUS_INVALID,
329+
"buffer list data is null");
330+
return nullptr;
331+
}
332+
is_const = true;
333+
}
334+
335+
//TODO The reference to n_bufferlist should be added to avoid dangling pointers of j_byte_buffer
336+
//https://stackoverflow.com/questions/46844275/freeing-memory-wrapped-with-newdirectbytebuffer
337+
auto *j_byte_buffer =
338+
env->NewDirectByteBuffer(n_buffer_ptr, n_bufferlist->GetBytes());
339+
if (j_byte_buffer == nullptr) {
340+
modelbox::Status ret = {modelbox::STATUS_NOMEM,
341+
"alloc memory for buffer list data failed."};
342+
modelbox::ModelBoxJNIThrow(env, ret);
343+
return nullptr;
344+
}
345+
346+
if (is_const == false) {
347+
return j_byte_buffer;
348+
}
349+
350+
jmethodID asreadonly_method =
351+
env->GetMethodID(env->GetObjectClass(j_byte_buffer), "asReadOnlyBuffer",
352+
"()Ljava/nio/ByteBuffer;");
353+
if (asreadonly_method == nullptr) {
354+
modelbox::Status ret = {modelbox::STATUS_NOMEM,
355+
"get asreadonly method failed."};
356+
modelbox::ModelBoxJNIThrow(env, ret);
357+
return nullptr;
358+
}
359+
360+
jobject j_readonly_byte_buffer =
361+
env->CallObjectMethod(j_byte_buffer, asreadonly_method);
362+
return j_readonly_byte_buffer;
363+
}
244364
/*
245365
* Class: com_modelbox_BufferList
246366
* Method: BufferListGetDevice

src/java/src/main/java/com/modelbox/Buffer.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.modelbox;
1818

19+
import java.nio.ByteBuffer;
20+
1921
/**
2022
* Modelbox Buffer
2123
*/
@@ -48,6 +50,15 @@ public byte[] getData() throws ModelBoxException {
4850
return BufferGetData();
4951
}
5052

53+
/**
54+
* get direct buffer.
55+
* <p>WARNING: Do not hold ByteBuffer beyond the scope, otherwise it will cause dangling pointers and trigger coredump
56+
* @return direct buffer
57+
*/
58+
public ByteBuffer getDirectData() throws ModelBoxException {
59+
return BufferGetDirectData();
60+
}
61+
5162
/*
5263
* Any error on buffer
5364
*/
@@ -312,6 +323,8 @@ public Device getDevice() {
312323

313324
private native byte[] BufferGetData();
314325

326+
private native ByteBuffer BufferGetDirectData();
327+
315328
private native boolean BufferHasError();
316329

317330
private native void BufferSetError(String code, String message);

src/java/src/main/java/com/modelbox/BufferList.java

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.modelbox;
1818

1919

20+
import java.nio.ByteBuffer;
2021
import java.util.Iterator;
2122

2223
/**
@@ -65,15 +66,15 @@ private BufferList() {
6566
}
6667

6768
/**
68-
* @brief Builder buffer, create memory
69+
* Builder buffer, create memory
6970
* @param sizeList buffer size list
7071
*/
7172
public void build(int[] sizeList) {
7273
BufferListBuild(sizeList);
7374
}
7475

7576
/**
76-
* @brief Get buffer at index
77+
* Get buffer at index
7778
* @param index position of buffer
7879
* @return buffer
7980
*/
@@ -82,55 +83,74 @@ public Buffer at(long index) {
8283
}
8384

8485
/**
85-
* @brief Get number of buffer in bufferlist
86+
* Get number of buffer in bufferlist
8687
* @return number of buffer
8788
*/
8889
public long size() {
8990
return BufferListSize();
9091
}
9192

9293
/**
93-
* @brief Push new buffer to buffer list
94+
* Push new buffer to buffer list
9495
* @param buffer pointer to buffer
9596
*/
9697
public void pushBack(Buffer buffer) {
9798
BufferListPushBack(buffer);
9899
}
99100

100101
/**
101-
* @brief Push new data to buffer list
102+
* Push new data to buffer list
102103
* @param data pointer to data
103104
*/
104105
public void pushBack(byte[] data) {
105106
BufferListPushBack(data);
106107
}
107108

108109
/**
109-
* @brief Assign buffer list
110+
* Assign buffer list
110111
* @param buffers buffer list to assign
111112
*/
112113
public void assign(Buffer[] buffers) {
113114
BufferListAssign(buffers);
114115
}
115116

116117
/**
117-
* @brief Get buffer data pointer from begining
118+
* Get buffer data pointer from begining
118119
* @return buffer data pointer from begining
119120
*/
120121
public byte[] getData() {
121122
return BufferListGetData();
122123
}
123124

124125
/**
125-
* @brief Get device of buffer list
126+
* Get buffer data pointer from begining
127+
* <p>WARNING: Do not hold ByteBuffer beyond the scope, otherwise it will cause dangling pointers and trigger coredump
128+
* @return buffer data pointer from begining
129+
*/
130+
public ByteBuffer getDirectData() {
131+
return BufferListGetDirectData();
132+
}
133+
134+
/**
135+
* Get buffer data pointer from begining
136+
* WARNING: Do not hold ByteBuffer beyond the scope, otherwise it will cause dangling pointers and trigger coredump
137+
* @param index position of buffer
138+
* @return buffer data pointer from begining
139+
*/
140+
public ByteBuffer getDirectData(int index) {
141+
return BufferListGetDirectData(index);
142+
}
143+
144+
/**
145+
* Get device of buffer list
126146
* @return pointer to device
127147
*/
128148
public Device getDevice() {
129149
return BufferListGetDevice();
130150
}
131151

132152
/**
133-
* @brief Reset buffer list
153+
* Reset buffer list
134154
* @return reset result
135155
*/
136156
public void reset() {
@@ -151,6 +171,10 @@ public void reset() {
151171

152172
private native byte[] BufferListGetData();
153173

174+
private native ByteBuffer BufferListGetDirectData();
175+
176+
private native ByteBuffer BufferListGetDirectData(int index);
177+
154178
private native Device BufferListGetDevice();
155179

156180
private native void BufferListReset();

0 commit comments

Comments
 (0)