4

Previously I posed a question about converting a byte[] to short[] and a new problem I encountered is converting/ not converting the data from byte[] to BigEndian.
Here is what is going on:

  • I am using TargetDataLine to read data into a byte[10000].
  • The AudioFormat object has BigEndian set to true, arbitrarily.
  • This byte[] needs to be converted to short[] so that it can be encoded using Xuggler
  • I don't know whether the AudioFormat BigEndian should be set to true or false.
    I have tried both the cases and I get an Exception in both the cases.
    To convert byte[] to short[], I do this:

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

    where:
    fromMic is TargetDataLine
    tempBufferbyte is byte[10000]
    tempBufferShort is short[10000]
    I get the Exception:

       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;]
    

    Miscellaneous information that may be needed:

  • How I set the stream for adding audio in Xuggler:
  • writer.addAudioStream(0,1,fmt.getChannels(),(int)fmt.getSampleRate());
    

  • How I perform the encoding
  • writer.encodeAudio(1,tempBufferShort,timeStamp,TimeUnit.NANOSECONDS);
    

    Java Doc on AudioFormat

    ...In addition to the encoding, the audio format includes other properties that further specify the exact arrangement of the data. These include the number of channels, sample rate, sample size, byte order, frame rate, and frame size...

    and

    For 16-bit samples (or any other sample size larger than a byte), byte order is important; the bytes in each sample are arranged in either the "little-endian" or "big-endian" style.

    Questions:

  • Do I need to keep the BigEndian as true in javax.sound.sampled.AudioFormat object?

  • What is causing the error? Is it the format?



  • I guess I get BigEndian data preformatted by the AudioFormat object.
    An SO User
    • 24,612
    • 35
    • 133
    • 221
    • 2
      Are you sure the cast is appropriate? If you shorts are unsigned you will get allot of noise. BTW Failed to write packet is a message, not an exception. Can you give us the actual exception as it may have nothing to do with encoding. – Peter Lawrey Dec 25 '12 at 20:42
    • 1
      That is the exception I get. I used `System.out.println(e)` to get what it contains. And I get `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 Dec 25 '12 at 20:52

    3 Answers3

    3

    If your data is indeed big endian, you can directly convert it to a (big endian) short array like this:

    ByteBuffer buf = ByteBuffer.wrap(originalByteArray);
    short[] shortArray = buf.asShortBuffer().array();
    

    The resulting short array will have all the original byte array directly, and correctly, mapped, given that your data is big endian. So, an original array, such as:

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

    will be converted to:

    // shorts
    [00ae], [007f]
    
    fge
    • 119,121
    • 33
    • 254
    • 329
    • `short[] shortArray = buf.asShortBuffer().array;` flagged as unsupported operation – An SO User Dec 25 '12 at 21:04
    • the problem is that Xuggler guys can not be contacted. Else, I would pose them this question. – An SO User Dec 25 '12 at 21:07
    • @LittleChild one thing you _have_ to remember is that at the JVM level, all primitive numeric data types (this includes `byte`, `short`, `int`, `long`, but also `float` and `double`) are handled the big endian way, also called the MSB way, ie the Most Significant Byte first way. I don't know the API exactly, but I guess it arranges so that if you specify to read it the MSB way, it will match what Java "natively" expects for primitive types -- and I fail to see why it would ever offer the other way around as a choice... At this point, your best bet is to try and see what happens :/ – fge Dec 25 '12 at 21:11
    • Xuggler guys need to be more accessible. Now, only some veteran who has used Xuggler can help. – An SO User Dec 25 '12 at 21:13
    2

    You need to convert two bytes into one short, so this line is wrong:

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

    You need something along the lines of

    tempBufferShort[i] = (short) 
       (tempBufferByte[i*2] & 0xFF)*256 + (tempBufferByte[i*2+1] & 0xFF);
    

    This would be in line with a big-endian byte array.

    Marko Topolnik
    • 195,646
    • 29
    • 319
    • 436
    • `ByteBuffer` can also be used and I guess it does the conversion automatically using `order(ByteBuffer.BIG_ENDIAN)` right? – An SO User Dec 25 '12 at 20:56
    • Yes, the approach with `ByteBuffer` involves the ready-made API for this purpose. – Marko Topolnik Dec 25 '12 at 21:05
    • `bb = ByteBuffer.wrap(tempBufferByte); tempBufferShort = bb.asShortBuffer().array();` is flagged as unsupported operation. – An SO User Dec 25 '12 at 21:34
    • 1
      Yes; that wouldn't be an appropriate usage of the API. `asShortBuffer` just creates a view of the original buffer; the view has no backing array (`hasArray` returns `false`, as documented). – Marko Topolnik Dec 25 '12 at 21:46
    • I guess problem is with Xuggler. See the text about JavaDoc in question :) Thanks anyways – An SO User Dec 25 '12 at 21:54
    1

    What others here have said about the byte-to-short conversion is correct, but it cannot cause the problem you see, it would just cause the output audio to be mostly noise. You can call writeAudio with a buffer of all zeros (or anything, really) so, everything else being equal, the values in the buffer don't matter to whether the call succeeds (they do matter to what you hear in the output, of course :)

    1. Does the exception happen at the beginning of the stream (first audio chunk)? Can you write an audio-only stream successfully?

    2. Set the audio codec when you call addAudioStream. Try ICodec.ID.CODEC_ID_MP3 or ICodec.ID.CODEC_ID_AAC.

    3. Check that fmt.getChannels() and fmt.getSampleRate() are correct. Not all possible values are supported by any particular codec. (2 ch, 44100 Hz should be supported by just about anything).

    4. Are you writing your audio and video such that the timestamps are strictly non-decreasing?

    5. Do you have enough audio samples for the duration your timestamps are indicating? Does tempBufferShort.length == ((timeStamp - lastTimeStamp) / 1e+9) * sampleRate * channels ? (This may be only approximately equal, but it should be very close, slight rounding errors probably ok).

    Alex I
    • 19,689
    • 9
    • 86
    • 158
    • Wait, I guess the issue is with 5th point, samples. I am having an issue there. With maintaining samples rate. – An SO User Dec 26 '12 at 08:06