Open zukopvd opened 8 years ago
Hello again!
Here is more information about this issue. I'm working with m4a files that was encoded by android MediaCodec (code below). On all of my test devices encoding works fine: resutl codec name is correct (OMX.google.aac.decoder), file is playable and can be parsed to waveform by ringdroid. But issue comes to the one of devices when I try to parse file with your waveform-android libriary. Device is: Sony Xperia Tablet Z3 Compact under Android 5.1.1 - file that was encoded there is playable, can be parsed with ringdroid, but with waveform-android it's always throw "java.io.IOException: Went over by 7 bytes" and it's always at third step of parse iterations:
04-03 15:08:26.853 24412-24628/com.semantive.waveformandroid.waveform.soundfile.CheapAAC: skipLen: 16, atomLen: 24, mOffset: 8, initialOffset: 0, header: [0, 0, 0, 24, 102, 116, 121, 112] 04-03 15:08:26.853 24412-24628/com.semantive.waveformandroid.waveform.soundfile.CheapAAC: skipLen: 6136, atomLen: 6144, mOffset: 32, initialOffset: 24, header: [0, 0, 24, 0, 102, 114, 101, 101] 04-03 15:08:26.854 24412-24628/com.semantive.waveformandroid.waveform.soundfile.CheapAAC: skipLen: -7, atomLen: 1, mOffset: 6176, initialOffset: 6168, header: [0, 0, 0, 1, 109, 100, 97, 116] 04-03 15:08:26.854 24412-24628/ W/System.err: java.io.IOException: Went over by 7 bytes 04-03 15:08:26.854 24412-24628/W/System.err: at com.semantive.waveformandroid.waveform.soundfile.CheapAAC.parseMp4(CheapAAC.java:288) 04-03 15:08:26.854 24412-24628/ W/System.err: at com.semantive.waveformandroid.waveform.soundfile.CheapAAC.ReadFile(CheapAAC.java:200) 04-03 15:08:26.855 24412-24628/ W/System.err: at com.semantive.waveformandroid.waveform.soundfile.CheapSoundFile.create(CheapSoundFile.java:100)
If I put to Sony any m4a file, that was encoded on other device parse works fine. Here is encoding code that I used. May be I should do something in different way:
`
private static void convertWavToM4A(File wavFile, File dstM4AFile, MediaFormat format) {
final String COMPRESSED_AUDIO_FILE_MIME_TYPE = "audio/mp4a-latm";
final int COMPRESSED_AUDIO_FILE_BIT_RATE = 256000;
final int SAMPLING_RATE = format == null ? 44100 : format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
final int BUFFER_SIZE = SAMPLING_RATE;
final int CODEC_TIMEOUT_IN_MS = 5000;
final int CHANNELS_COUNT = format == null ? 1 : format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
try {
FileInputStream fis = new FileInputStream(wavFile);
if (dstM4AFile.exists()) dstM4AFile.delete();
MediaMuxer mux = new MediaMuxer(dstM4AFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
MediaFormat outputFormat = MediaFormat.createAudioFormat(COMPRESSED_AUDIO_FILE_MIME_TYPE, SAMPLING_RATE, CHANNELS_COUNT);
outputFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, COMPRESSED_AUDIO_FILE_BIT_RATE);
outputFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, BUFFER_SIZE);
MediaCodec codec = MediaCodec.createEncoderByType(COMPRESSED_AUDIO_FILE_MIME_TYPE);
codec.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();
ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); // Note: Array of buffers
ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
MediaCodec.BufferInfo outBuffInfo = new MediaCodec.BufferInfo();
byte[] tempBuffer = new byte[BUFFER_SIZE];
boolean hasMoreData = true;
double presentationTimeUs = 0;
int audioTrackIdx = 0;
int totalBytesRead = 0;
do {
int inputBufIndex = 0;
while (inputBufIndex != -1 && hasMoreData) {
inputBufIndex = codec.dequeueInputBuffer(CODEC_TIMEOUT_IN_MS);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
dstBuf.clear();
int bytesRead = fis.read(tempBuffer, 0, dstBuf.limit());
if (bytesRead == -1) { // -1 implies EOS
hasMoreData = false;
codec.queueInputBuffer(inputBufIndex, 0, 0, (long) presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
totalBytesRead += bytesRead;
dstBuf.put(tempBuffer, 0, bytesRead);
codec.queueInputBuffer(inputBufIndex, 0, bytesRead, (long) presentationTimeUs, 0);
presentationTimeUs = 1000000l * (totalBytesRead / (SAMPLING_RATE/10000)) / SAMPLING_RATE;
}
}
}
int outputBufIndex = 0;
while (outputBufIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
outputBufIndex = codec.dequeueOutputBuffer(outBuffInfo, CODEC_TIMEOUT_IN_MS);
if (outputBufIndex >= 0) {
ByteBuffer encodedData = codecOutputBuffers[outputBufIndex];
encodedData.position(outBuffInfo.offset);
encodedData.limit(outBuffInfo.offset + outBuffInfo.size);
if ((outBuffInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 && outBuffInfo.size != 0) {
codec.releaseOutputBuffer(outputBufIndex, false);
} else {
mux.writeSampleData(audioTrackIdx, codecOutputBuffers[outputBufIndex], outBuffInfo);
codec.releaseOutputBuffer(outputBufIndex, false);
}
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
outputFormat = codec.getOutputFormat();
audioTrackIdx = mux.addTrack(outputFormat);
mux.start();
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
} else if (outputBufIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
// NO OP
} else {
}
}
} while (outBuffInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM);
codec.stop();
codec.release();
fis.close();
mux.stop();
mux.release();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}`
I hope it's will be helpful to resolve this issue.
Thanks. Serge.
Hi, Waveform Android is based on the Ringdroid app, but it doesn't use it's newest audio API (last year Ringdroid changed it completely). I can update the library to use the same audio API as the Ringdroid - this will probably solve the issue. Just to be sure, are your using the newest version of the Ringdroid (2.7.3)?
Thanks a lot for your reply! Yes, I'am using Ringdroid 2.7.3 - everything works with this version (but it's extremely slow for me). If API update can solve the issue it's will be great if you'll do it!
Here is attached example of audio file that can cause the issue. May be it's will be useful for testing. test_audio.m4a.zip
Hi,
I updated the library - it now works with the file you posted. The code is on a new branch new-audio-api
and can be added to your gradle dependencies with compile 'com.github.Semantive:waveform-android:v1.2a'
. This solution is far from being perfect - audio decoding makes it slow and memory consuming for larger files.
Hello! Yes, new api is too slow. The reason is that source file is decoded to wav format before parsing instead of using CheapMP3 or CheapAAC as at previous api version. May be it's possible to fix CheapAAC class, but I don't really understand how it works currently. Or may be it's time for me to find another solution. Thank you, anyway!
Hello! Can you please suggest me what can i do with "Went over 7 bytes" exception? One of my test devices always trows it at CheapAAC.parseMp4(CheapAAC.java:285). It's always "7" bytes for every m4a file that i try to use. How can i solve it?
Thanks. Serge.