Путаница BigEndian, LittleEndian в Xuggler

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:

  • Я использую 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];
    }  
    

    где:
    fromMic равно TargetDataLine
    tempBufferbyte равно byte[10000]
    tempBufferShort равно short[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);
    

    Документ Java на AudioFormat

    ...Помимо кодировки, аудиоформат включает в себя другие свойства, которые дополнительно определяют точное расположение данных. К ним относятся количество каналов, частота дискретизации, размер выборки, порядок байтов, частота кадров и размер кадра...

    и

    Для 16-битных выборок (или любых других выборок размером больше байта) важен порядок байтов; байты в каждом образце расположены либо в стиле «с прямым порядком байтов», либо в стиле «с прямым порядком байтов».

    Вопросы:

  • Нужно ли сохранять BigEndian как true в объекте javax.sound.sampled.AudioFormat?

  • Что вызывает ошибку? Это формат?



  • I guess I get BigEndian data preformatted by the AudioFormat object.


    person An SO User    schedule 25.12.2012    source источник
    comment
    Вы уверены, что актерский состав подходит? Если ваши шорты не подписаны, вы получите много шума. BTW Не удалось записать пакет — это сообщение, а не исключение. Можете ли вы дать нам фактическое исключение, поскольку оно может не иметь ничего общего с кодировкой.   -  person Peter Lawrey    schedule 26.12.2012
    comment
    Это исключение, которое я получаю. Я использовал 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;]   -  person An SO User    schedule 26.12.2012


    Ответы (3)


    Если ваши данные действительно имеют обратный порядок байтов, вы можете напрямую преобразовать их в короткий массив (обратный порядок байтов) следующим образом:

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

    Результирующий массив short будет иметь весь исходный массив byte напрямую и правильно отображенным, учитывая, что ваши данные имеют обратный порядок байтов. Итак, исходный массив, например:

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

    будет преобразовано в:

    // shorts
    [00ae], [007f]
    
    person fge    schedule 25.12.2012
    comment
    short[] shortArray = buf.asShortBuffer().array; помечен как неподдерживаемая операция - person An SO User; 26.12.2012
    comment
    проблема в том, что с ребятами из Xuggler не связаться. Иначе я бы задал им этот вопрос. - person An SO User; 26.12.2012
    comment
    @LittleChild вам нужно помнить, что на уровне JVM все примитивные числовые типы данных (включая byte, short, int, long, а также float и double) обрабатываются с прямым порядком байтов. , также называемый способом MSB, т.е. первым путем наиболее значимого байта. Я не знаю точно API, но я думаю, что он устроен так, что если вы укажете читать его способом MSB, он будет соответствовать тому, что Java изначально ожидает для примитивных типов, и я не понимаю, почему он когда-либо предлагал другой наоборот, как выбор... На данный момент лучше всего попробовать и посмотреть, что произойдет :/ - person fge; 26.12.2012
    comment
    Парни из Xuggler должны быть более доступными. Теперь помочь может только какой-нибудь ветеран, который использовал Xuggler. - person An SO User; 26.12.2012

    Вам нужно преобразовать два байта в один короткий, поэтому эта строка неверна:

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

    Вам нужно что-то вроде

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

    Это будет соответствовать массиву байтов с обратным порядком байтов.

    person Marko Topolnik    schedule 25.12.2012
    comment
    ByteBuffer также можно использовать, и я думаю, что преобразование выполняется автоматически с использованием order(ByteBuffer.BIG_ENDIAN), верно? - person An SO User; 26.12.2012
    comment
    Да, подход с ByteBuffer предполагает уже готовый API для этой цели. - person Marko Topolnik; 26.12.2012
    comment
    bb = ByteBuffer.wrap(tempBufferByte); tempBufferShort = bb.asShortBuffer().array(); помечен как неподдерживаемая операция. - person An SO User; 26.12.2012
    comment
    Да; это не было бы подходящим использованием API. asShortBuffer просто создает представление исходного буфера; представление не имеет резервного массива (hasArray возвращает false, как задокументировано). - person Marko Topolnik; 26.12.2012
    comment
    Я предполагаю, что проблема с Xuggler. См. текст о рассматриваемом JavaDoc :) В любом случае спасибо - person An SO User; 26.12.2012

    То, что другие здесь сказали о преобразовании байтов в короткие, верно, но это не может вызвать проблему, которую вы видите, это просто приведет к тому, что выходной звук будет в основном шумом. Вы можете вызывать writeAudio с буфером, состоящим из всех нулей (или чего угодно), так что, при прочих равных условиях, значения в буфере не имеют значения для успешного выполнения вызова (они имеют значение для того, что вы слышите на выходе, курс :)

    1. Возникает ли исключение в начале потока (первый фрагмент аудио)? Можете ли вы успешно написать поток только для аудио?

    2. Установите аудиокодек при вызове addAudioStream. Попробуйте ICodec.ID.CODEC_ID_MP3 или ICodec.ID.CODEC_ID_AAC.

    3. Убедитесь, что fmt.getChannels() и fmt.getSampleRate() указаны правильно. Не все возможные значения поддерживаются каким-либо конкретным кодеком. (2 канала, 44100 Гц должны поддерживаться почти всем).

    4. Вы записываете аудио и видео так, чтобы временные метки были строго неубывающими?

    5. Достаточно ли у вас аудиосэмплов на время, указанное вашими временными метками? tempBufferShort.length == ((timeStamp - lastTimeStamp) / 1e+9) * sampleRate * channels ? (Это может быть только приблизительно равно, но должно быть очень близко, небольшие ошибки округления, вероятно, в порядке).

    person Alex I    schedule 25.12.2012
    comment
    Подождите, я думаю, проблема с 5-й точкой, образцами. У меня там проблема. С сохранением скорости выборки. - person An SO User; 26.12.2012