Как преобразовать короткий массив в байтовый массив
Я нашел преобразование короткого байтового массива и байтового массива в короткий массив, но не короткого массива в байтовый массив.
Вот код, приводящий к преобразованию
while(!stopped)
{
Log.i("Map", "Writing new data to buffer");
short[] buffer = buffers[ix++ % buffers.length];
N = recorder.read(buffer,0,buffer.length);
track.write(buffer, 0, buffer.length);
byte[] bytes2 = new byte[N];
я пытался
int i = 0;
ByteBuffer byteBuf = ByteBuffer.allocate(N);
while (buffer.length >= i) {
byteBuf.putShort(buffer[i]);
i++;
}
bytes2 = byteBuf.array();
а также
ByteBuffer.wrap(bytes2).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(buffer);
Однако я получаю эту ошибку на обоих (ошибка, если не совсем то же самое, но очень похожая для обоих):
05-29 13:41:12.021: W/AudioTrack (9758): отслеживание 0B30efa0 receiveBuffer () отключено, перезапуск
05-29 13:41:12.857: W/AudioWorker (9758): Ошибка чтения голоса AudioWorker
05-29 13:41:12.857: W/AudioWorker (9758): java.nio.BufferOverflowException
05-29 13:41:12.857: W/AudioWorker (9758): в java.nio.ShortBuffer.put (ShortBuffer.java:422)
05-29 13:41:12.857: W/AudioWorker (9758): по адресу java.nio.ShortToByteBufferAdapter.put (ShortToByteBufferAdapter.java:210)
05-29 13:41:12.857: W/AudioWorker (9758): по адресу java.nio.ShortBuffer.put (ShortBuffer.java:391)
05-29 13:41:12.857: W/AudioWorker (9758): на com.avispl.nicu.audio.AudioWorker.run(AudioWorker.java:126)
И просто для того, чтобы дать как можно больше информации, вот код, который использует байтовый массив.
Log.i("Map", "test");
//convert to ulaw
read(bytes2, 0, N);
//send to server
os.write(bytes2,0,bytes2.length);
System.out.println("bytesRead "+buffer.length);
System.out.println("data "+Arrays.toString(buffer));
}
3 ответа
Джава short
это 16-битный тип, и byte
это 8-битный тип. У вас есть цикл, который пытается вставить N
шорты в буфер это N
длиной в байт; это должно быть 2*N
байт, чтобы соответствовать всем вашим данным.
ByteBuffer byteBuf = ByteBuffer.allocate(2*N);
while (N >= i) {
byteBuf.putShort(buffer[i]);
i++;
}
Я обнаружил, что ByteBuffer - самый медленный метод преобразования из трех, которые я профилировал. Увидеть ниже...
Платформа: Nexus S, Android 4.1.1, без SIM-карты
Метод № 1: Используйте ByteBuffer
byte [] ShortToByte_ByteBuffer_Method(short [] input)
{
int index;
int iterations = input.length;
ByteBuffer bb = ByteBuffer.allocate(input.length * 2);
for(index = 0; index != iterations; ++index)
{
bb.putShort(input[index]);
}
return bb.array();
}
Метод № 2: Тиддл биты напрямую
byte [] ShortToByte_Twiddle_Method(short [] input)
{
int short_index, byte_index;
int iterations = input.length;
byte [] buffer = new byte[input.length * 2];
short_index = byte_index = 0;
for(/*NOP*/; short_index != iterations; /*NOP*/)
{
buffer[byte_index] = (byte) (input[short_index] & 0x00FF);
buffer[byte_index + 1] = (byte) ((input[short_index] & 0xFF00) >> 8);
++short_index; byte_index += 2;
}
return buffer;
}
Способ № 3: Используйте C через JNI
TypeCast.java
package mynamespace.util;
public class TypeCast
{
public static native byte [] shortToByte(short [] input);
static
{
System.loadLibrary("type_conversion");
}
}
native.c
#include <jni.h>
#include <string.h>
jbyteArray Java_mynamespace_util_TypeCast_shortToByte(JNIEnv *env, jobject obj, jshortArray input)
{
jshort *input_array_elements;
int input_length;
jbyte *output_array_elements;
jbyteArray output;
input_array_elements = (*env)->GetShortArrayElements(env, input, 0);
input_length = (*env)->GetArrayLength(env, input);
output = (jbyteArray) ((*env)->NewByteArray(env, input_length * 2));
output_array_elements = (*env)->GetByteArrayElements(env, output, 0);
memcpy(output_array_elements, input_array_elements, input_length * 2);
(*env)->ReleaseShortArrayElements(env, input, input_array_elements, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, output, output_array_elements, 0);
return output;
}
Результаты:
Для входного массива в миллион элементов время выполнения выглядит следующим образом:
Метод #1 ByteBuffer: 865 мс
Метод № 2: Twiddle: 299 мс
Метод № 3 C: 39 мс
Вот как конвертируется из короткого массива в массив байтов.
Примечание: чтобы изменить порядок следования байтов, поменяйте местамиresultData[c++]
линии. В настоящее время Little Endian.
public byte[] getBytes(short[] data) {
byte[] resultData = new byte[data.length * 2];
int c = 0;
for (int i = 0; i < data.length; i++) {
resultData[c++] = (byte) (((data[i])) & 0xFF);
resultData[c++] = (byte) (((data[i]) >>> 8) & 0xFF);
}
return resultData;
}