在Java中将字节数组转换为短整型数组,然后再转换回去

54

我遇到一些问题,需要将存储在字节数组中的音频数据转换为大端短整型数组、编码,然后再将它转换回字节数组。这是我的代码。原始音频数据存储在 audioBytes2 中。我使用相同的解码格式来进行解码,只是 cos 函数上带有一个负号。不幸的是,改变字节和短整型数据类型是不可避免的。

    short[] audioData = null;
    int nlengthInSamples = audioBytes2.length / 2;
    audioData = new short[nlengthInSamples];

    for (int i = 0; i < nlengthInSamples; i++) {
       short MSB = (short) audioBytes2[2*i+1];
       short LSB = (short) audioBytes2[2*i];
       audioData[i] = (short) (MSB << 8 | (255 & LSB));
    }

    int i = 0;
    while (i < audioData.length) {
        audioData[i] = (short)(audioData[i] + (short)5*Math.cos(2*Math.PI*i/(((Number)EncodeBox.getValue()).intValue())));
        i++;
    }

    short x = 0;
    i = 0;
    while (i < audioData.length) {
        x = audioData[i];
        audioBytes2[2*i+1] = (byte)(x >>> 0);
        audioBytes2[2*i] = (byte)(x >>> 8);
        i++;
    }

我已经尽我所能来使它工作,但最接近的情况是在每隔一个编码/解码时让它工作,我不知道为什么。谢谢任何帮助。


2
是大端序还是小端序?我认为你需要使用java.nio.ByteBuffer来处理这种转换。 - LiuYan 刘研
可能是如何将short数组转换为byte数组的重复问题。 - patryk.beza
6个回答

106

我也建议你尝试一下ByteBuffer。

byte[] bytes = {};
short[] shorts = new short[bytes.length/2];
// to turn bytes to shorts as either big endian or little endian. 
ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);

// to turn shorts back to bytes.
byte[] bytes2 = new byte[shortsA.length * 2];
ByteBuffer.wrap(bytes2).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(shortsA);

3
short[] audioData = ByteBuffer.wrap(audioBytes2).order(ByteOrder.BIG_ENDIAN).asShortBuffer().array(); 会抛出一个 UnsupportedOperationException 异常。 - Aaron
1
@Aaron - 是的,但是到底是什么引发了这个异常?(提示:ShortBuffer 作为底层 ByteBuffer视图,它的 get() 方法应该完全符合你的要求)。 - kdgregory
1
@kdgregory,直到你提出修复方法我才想起来,array()只有在底层存储是short[]或类似的原始数组以匹配XxxxxBuffer时才有效。 - Peter Lawrey
这只是将字节直接转换为短整型,还是像我需要的那样将两个字节组合成一个短整型? - Aaron
正如你所看到的,它创建的short数量是字节数的一半,而byte转换为short则需要两倍的字节。如果不进行转换,则ByteOrder毫无意义,因为仅将byte强制转换为short再转换回去并不需要ByteOrder。如果你有疑问,建议你尝试一下,看看是否符合你的需求。 - Peter Lawrey
显示剩余5条评论

13
public short bytesToShort(byte[] bytes) {
     return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
}
public byte[] shortToBytes(short value) {
    return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(value).array();
}

2
它不会将短数组转换为字节数组。 - Nikolay Shmyrev

6
如何使用ByteBuffer?
byte[] payload = new byte[]{0x7F,0x1B,0x10,0x11};
ByteBuffer bb = ByteBuffer.wrap(payload).order(ByteOrder.BIG_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
while(sb.hasRemaining()){
  System.out.println(sb.get());
}

5
byte[2] bytes;

int r = bytes[1] & 0xFF;
r = (r << 8) | (bytes[0] & 0xFF);

short s = (short)r;

2
你的代码在使用little-endian shorts,而不是big-endian shorts,MSB和LSB的索引已经交换了。
既然你正在使用big-endian shorts,你可以在另一端使用DataInputStream包装一个ByteArrayInputStream(和DataOutputStream/ByteArrayOutputStream),而不是自己进行解码。
如果你得到了其它反编码的工作,我猜测你有奇数个字节,或者在其它地方有一个偏移错误,导致每隔一次修复你的错误。
最后,我建议使用i+=2遍历数组,并使用MSB=arr[i]和LSB=arr[i+1],而不是乘以2,但这只是我的意见。

在音频输入流重新转换后,我实际上正在使用类似于那个的东西。 - Aaron

-1

看起来你在读取字节并写回时交换了字节顺序(不确定这是否是有意为之)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接