How to extract chunks of information from a ByteBuffer? - java

I've a ByteBuffer that is populated via socketChannel.read(buffer).
I want to extract information as byte[] or ByteBuffer that's located at specific position in this buffer.
It's being done like this at the moment:
byte[] data = new byte[length];
int oldPos = buffer.position();
buffer.position(offset);
buffer.get(data, 0, length);
buffer.position(oldPos);
I'd like to not create copies every time I want to extract information from the buffer. I've come up with the following approach. Please advise if there's a better way to accomplish this.
ByteBuffer readOnlyuplicate = orig.asReadOnlyBuffer();
readOnlyuplicate.position(start);
readOnlyuplicate.limit(start + length - 1);

Related

How to save 16bit depth Image to file in Arcore (java)

I want to save the depth info from the arcore to the storage.
Here is the example from the developer guide.
public int getMillimetersDepth(Image depthImage, int x, int y) {
// The depth image has a single plane, which stores depth for each
// pixel as 16-bit unsigned integers.
Image.Plane plane = depthImage.getPlanes()[0];
int byteIndex = x * plane.getPixelStride() + y * plane.getRowStride();
ByteBuffer buffer = plane.getBuffer().order(ByteOrder.nativeOrder());
short depthSample = buffer.getShort(byteIndex);
return depthSample;
}
So I want to save this bytebuffer into a local file, but my output txt file is not readable. How could I fix this?
Here is what I have
Image depthImage = frame.acquireDepthImage();
Image.Plane plane = depthImage.getPlanes()[0];
int format = depthImage.getFormat();
ByteBuffer buffer = plane.getBuffer().order(ByteOrder.nativeOrder());
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
File mypath=new File(super.getExternalFilesDir("depDir"),Long.toString(lastPointCloudTimestamp)+".txt");
FileChannel fc = new FileOutputStream(mypath).getChannel();
fc.write(buffer);
fc.close();
depthImage.close();
I tried to decode them with
String s = new String(data, "UTF-8");
System.out.println(StandardCharsets.UTF-8.decode(buffer).toString());
but the output is still strange like this
.03579:<=>#ABCDFGHJKMNOPRQSUWY]_b
In order to obtain the depth data provided by the ARCore session, you need to write bytes into your local file. A Buffer object is a container, it countains a finite sequence of elements of a specific primitive type (here bytes for a ByteBuffer). So what you need to write inside your file is your data variable that corresponds to the information previously stored in the buffer (according to buffer.get(data)).
It works fine for me, I managed to draw the provided depth map within a python code (but the idea behind the following code can be easily adapted to a java code):
depthData = np.fromfile('depthdata.txt', dtype = np.uint16)
H = 120
W = 160
def extractDepth(x):
depthConfidence = (x >> 13) & 0x7
if (depthConfidence > 6): return 0
return x & 0x1FFF
depthMap = np.array([extractDepth(x) for x in depthData]).reshape(H,W)
depthMap = cv.rotate(depthMap, cv.ROTATE_90_CLOCKWISE)
For further details, read the information concerning the format of the depthmap (DEPTH16) here: https://developer.android.com/reference/android/graphics/ImageFormat#DEPTH16
You must also be aware that the depthmap resolution is set to 160x120 pixels and is oriented according to a landscape format.
Make also sure to surround your code by a try/catch code bloc in case of a IOException error.

Optimization of rewriting from AudioInputStream to ByteArrayOutputStream

There were few similar topics on stackoverflow but none of them seemed good enough for me. The problem is i have such a snippet of code:
// AudioInputStream in;
final int BUFFER_SIZE = 8192;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] byteBuffer = new byte[BUFFER_SIZE];
int bytesRead = 0;
while ((bytesRead = in.read(byteBuffer, 0, BUFFER_SIZE)) != -1) {
byteStream.write(byteBuffer, 0, bytesRead);
}
byte[] audioData = byteStream.toByteArray();
This code reads data of mp3 file and saves it to byte array, but takes about 10 seconds. Is there any possibility to store whole mp3 data into buffer in shorter time?
I've tried to avoid passing the size of buffer or extend it but that caused additional problems (e.g. file was not read correctly).
Thanks in advance
You are copying data 3 times, you can avoid that by first checking the file size, allocating a byte array big enough, and reading into that directly.
It also helps a little bit to pre-allocate space in the ByteArrayOutputStream so it doesn't have to be increased in size many times.
If you can't get the file size up front, you can allocate a new byte[] for every block, and put them in a list, until you got them all. Then allocate the final array and copy all of them into the last array. IF you need a byte[] in the end. If you don't, there may be more efficient ways to proceed.

Convert ByteArrayOutputStream to int values

I am constantly trying to convert a ByteArrayOutputStream to int values.
I am recording an Audio with microphone and writing it to out = new ByteArrayOutputStream() like so:
out.write(buffer, 0, count);
byte audio[] = out.toByteArray();
When I print this I get these : [B#3456337e
How do I convert these to integer numbers.
Please Help, Thanks
There is no standard way to do it because actually it depends on what kind of bytes you have but, as it is an audio source, I think you can do it like that :
IntBuffer intBuf =
ByteBuffer.wrap(byteArray)
.order(ByteOrder.BIG_ENDIAN) //or try ByteOrder.LITTLE_ENDIAN
.asIntBuffer();
int[] array = new int[intBuf.remaining()];
intBuf.get(array);
//The result you want is "array"
I hope it will help you.
Convert it to an array, wrap the array in a ByteArrayInputStream, wrap that in a DataInputStream, and use readInt().
Try the following -
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataInputStream dataIs = new DataInputStream
(new ByteArrayInputStream(out.toByteArray());
// available stream to be read
while(dataIs.available()>0)
{
int k = dataIs.readInt();
// print int
System.out.print(k+" ");
}

ByteArrayOutputStream.toString() generating extra characters

I have the following code:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int size = 4096;
byte[] bytes = new byte[size];
while (is.read(bytes, 0, size) != -1)
{
baos.write(bytes);
baos.flush();
}
When I do:
String s = baos.toString();
I get \u0000-s appended to my string. So, if my character data is only X bytes out of Y, the Y-Z will get prefilled with \u0000 making it impossible to check for equals. What am I doing wrong here? How should I be converting the bytes to a String in this case?
The entire array (all 4096 bytes) is be written to the output - arrays have no idea of how much "useful data" they contain!
Store how much was read into a variable (InputStream.read returns a useful number) and specify that to the appropriate OutputStream.write overload to only write a portion (that which contains the useful data) of the array.
While the above change should "fix" the problem, it is generally recommended to use the string<->byte[] conversion forms that take in an explicit character set.
You should only be writing as much data as you are reading in each time through the loop:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int size;
byte[] bytes = new byte[4096];
while (size = is.read(bytes, 0, bytes.length) != -1)
{
baos.write(bytes, 0, size);
}
baos.flush();
String s = baos.toString();
You might consider specifying a specific character set for converting the bytes to a String. The no-arg toString() method uses the platform default encoding.
new String(baos.toByteArray(), 0, strLen, encoding)

Android byte array batches

I am sending image through Bluetooth pro-grammatically. When i send image as Byte array at the sending side the byte array length is = 83402 and at the receiving side i am getting byte bacthes of 1024.
I want to combine these 1024 batches into single byte array so that i again convert it as an image.
Here in the msg.obj i get 1024 bacth of byte array.
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
Bitmap bmp=BitmapFactory.decodeByteArray(readBuf,0,readBuf.length);
After that i am also getting this warning..
"Default buffer size used in BufferedOutputStream constructor. It would be better to be explicit if an 8k buffer is required"
any help would be appreciated.
Thanks
Should be roughly something like this:
byte[] readBuf = new byte[83402]; // this array will hold the bytes for the image, this value better be not hardcoded in your code
int start = 0;
while(/*read 1024 byte packets...*/) {
readBuf.copyOfRange((byte[]) msg.obj, start, start + 1024); // copy received 1024 bytes
start += 1024; //increment so that we don't overwrite previous bytes
}
/*After everything is read...*/
Bitmap bmp=BitmapFactory.decodeByteArray(readBuf,0,readBuf.length);
I'm going to go out on a limb here and assume you're using the BluetoothChat example from the sdk to build your image sender (all your examples match it). Here's a quick conversion I threw together - may not be the best but it works.
You're getting them in batches of 1024 because in the BluetoothChatService.java run function it creates a buffer array size 1024 that goes and gets info from the input stream. If you create another buffer that will fit the image there (I set a max 1mb) then your run function would have:
byte[] buffer = new byte[1024];
byte[] imgBuffer = new byte[1024*1024];
int pos = 0;
with your pos variable keeping track of where you are in your imgBuffer.
Then you just copy it over while you're getting chunks in the while(true) loop of the image like this (mmInStream is an InputStream):
int bytes = mmInStream.read(buffer);
System.arraycopy(buffer,0,imgBuffer,pos,bytes);
pos += bytes;
I send a message to let it know that the image is done sending and at that point shuttle the imgBuff over to the other thread (pos has the size of the imgBuffer at this point):
mHandler.obtainMessage(BluetoothChat.IMAGE_READ, pos, -1, imgBuffer)
.sendToTarget();
I had defined IMAGE_READ to decode the array like you did in your MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
BitmapFactory.decodeByteArray(readBuf, 0, msg.arg1);

Categories