Xuggler中的大端小端混淆问题

4
之前我提出了一个问题,关于将byte[]转换为short[],我遇到的新问题是将数据从byte[]转换/不转换为BigEndian。
以下是正在发生的事情:
  • 我正在使用TargetDataLine将数据读入byte[10000]中。
  • AudioFormat对象将BigEndian设置为true,任意设置。
  • 这个byte[]需要转换为short[],以便可以使用Xuggler进行编码。
  • 我不知道AudioFormat BigEndian应该设置为true还是false。
    我尝试了这两种情况,但在两种情况下都会出现异常。
    要将byte[]转换为short[],我这样做:

    fromMic.read(tempBufferByte, 0, tempBufferByte.length);
    for(int i=0;i<tempBufferShort.length;i++){
    tempBufferShort[i] = (short) tempBufferByte[i];
    }  
    

    其中:
    fromMicTargetDataLine
    tempBufferbytebyte[10000]
    tempBufferShortshort[10000]
    我收到了异常:

       java.lang.RuntimeException: failed to write packet: com.xuggle.xuggler.IPacket@90098448[complete:true;dts:12;pts:12;size:72;key:true;flags:1;stream index:1;duration:1;position:-1;time base:9/125;]
    

    可能需要的其他信息:

  • Xuggler中如何设置用于添加音频的流:
  • writer.addAudioStream(0,1,fmt.getChannels(),(int)fmt.getSampleRate());
    

    我如何执行编码
    writer.encodeAudio(1,tempBufferShort,timeStamp,TimeUnit.NANOSECONDS);
    

    AudioFormat中的Java Doc

    除了编码之外,音频格式还包括其他属性,进一步指定数据的确切排列方式。这些属性包括通道数、采样率、采样大小、字节顺序、帧速率和帧大小。

    以及

    对于16位样本(或任何比一个字节更大的样本大小),字节顺序非常重要;每个样本中的字节都按“小端”或“大端”样式排列。

    问题:

  • javax.sound.sampled.AudioFormat对象中,我需要将BigEndian保留为true吗?

  • 是什么导致了错误? 是格式吗?



  • 我猜AudioFormat对象预先格式化了BigEndian数据。


    2
    你确定转换是合适的吗?如果你的短整型是无符号的,你会得到很多噪音。顺便说一下,“Failed to write packet”只是一条消息,而不是异常。你能给我们实际的异常吗?因为它可能与编码无关。 - Peter Lawrey
    1
    这是我得到的异常。我使用了 System.out.println(e) 来获取它包含的内容。我得到了 java.lang.RuntimeException: failed to write packet: com.xuggle.xuggler.IPacket@90098448[complete:true;dts:12;pts:12;size:72;key:true;flags:1;stream index:1;duration:1;position:-1;time base:9/125;] - An SO User
    3个回答

    3
    如果您的数据确实是大端序,您可以直接按照以下方式将其转换为(大端序)short数组:
    ByteBuffer buf = ByteBuffer.wrap(originalByteArray);
    short[] shortArray = buf.asShortBuffer().array();
    

    如果您的数据是大端序,那么生成的short数组将直接且正确地映射所有原始的byte数组。因此,一个原始的数组可能如下所示:

    // bytes
    [00], [ae], [00], [7f]
    

    将被转换为:

    // shorts
    [00ae], [007f]
    

    short[] shortArray = buf.asShortBuffer().array; 被标记为不支持的操作。 - An SO User
    问题在于无法联系到Xuggler的人。否则,我会向他们提出这个问题。 - An SO User
    @LittleChild 你必须记住的一件事是,在JVM级别,所有原始数值数据类型(包括byteshortintlong,以及floatdouble)都是按照大端方式处理的,也称为MSB方式,即最高有效字节优先方式。我不知道API的确切情况,但我猜它会安排如果你指定以MSB方式读取,它将与Java对于原始类型的“本地”期望相匹配--而我看不出为什么它会提供另一种选择...此时,你最好的选择是尝试并查看会发生什么:/ - fge
    Xuggler的开发人员需要更加亲近用户。现在,只有一些曾经使用过Xuggler的老手才能提供帮助。 - An SO User

    2

    你需要将两个字节转换为一个短整型,所以这行代码是错误的:

    tempBufferShort[i] = (short) tempBufferByte[i];
    

    你需要类似以下内容:
    tempBufferShort[i] = (short) 
       (tempBufferByte[i*2] & 0xFF)*256 + (tempBufferByte[i*2+1] & 0xFF);
    

    这将与大端字节数组相符。

    ByteBuffer 也可以使用,我猜它会自动使用 order(ByteBuffer.BIG_ENDIAN) 进行转换,对吗? - An SO User
    是的,使用ByteBuffer的方法涉及到为此目的准备好的API。 - Marko Topolnik
    bb = ByteBuffer.wrap(tempBufferByte); tempBufferShort = bb.asShortBuffer().array(); 被标记为不支持的操作。 - An SO User
    1
    是的,那不是API的适当用法。asShortBuffer只创建原始缓冲区的视图;该视图没有支撑数组(如所述)。因此,hasArray返回false - Marko Topolnik
    我猜问题出在Xuggler。请查看问题中有关JavaDoc的文本 :) 无论如何,谢谢。 - An SO User

    1

    这里其他人关于字节转短整型的说法是正确的,但它不能导致你看到的问题,它只会导致输出音频大部分是噪声。您可以使用全零(或任何其他内容)缓冲区调用writeAudio,因此,在其他条件相等的情况下,缓冲区中的值对调用是否成功无影响(当然,它们对输出中听到的声音有影响:)

    1. 异常是否发生在流的开头(第一个音频块)?您能成功编写仅音频的流吗?

    2. 在调用addAudioStream时设置音频编解码器。尝试使用ICodec.ID.CODEC_ID_MP3ICodec.ID.CODEC_ID_AAC

    3. 检查fmt.getChannels()fmt.getSampleRate()是否正确。并非所有可能的值都受到任何特定编解码器的支持。(2个通道,44100 Hz应该被几乎所有编解码器支持)。

    4. 您是否编写了音频和视频,以使时间戳严格不降?

    5. 您是否有足够的音频样本来表示您的时间戳所指示的持续时间?是否tempBufferShort.length == ((timeStamp - lastTimeStamp) / 1e+9) * sampleRate * channels?(这可能只是近似相等,但应该非常接近,轻微的舍入误差可能是可以接受的)。


    等一下,我猜问题出在第五点,即样本。我在那里遇到了问题。难以维护样本率。 - An SO User

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