1
votes

How do I get duration of an AMR file?

mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

I want to get the duration of the file after the recording is stopped WITHOUT creating any MediaPlayer and get the duration from it. For a regular Wav file I simply do this:

fileLength / byteRate

but for AMR I didn't know the byteRate and I'm not sure this will be ok though since WAV is raw PCM data(uncompressed) and AMR is compressed.

2

2 Answers

6
votes

Maybe the 3GP container contains information about the content length? The 3GPP file format spec is available if you want to read it.


For a raw .amr file you'd have to traverse all the frames to find the length of the audio, since each frame can be encoded with a different bitrate.

The process for doing this would be:

  • Skip the first 6 bytes of the file (the AMR signature).

  • The rest of the file will be audio frames, which each starts with a one-byte header. Read that byte and look at bits 3..6 (the codec mode). For AMR-NB the valid codec modes are 0..7, which you can map to the size of the frame in bytes using the table below.

  • Once you know the size of the current frame, skip past it and parse the next frame. Repeat until you reach the end of the file.

If you've counted the number of frames in the file you can multiply that number by 20 to get the length of the audio in milliseconds.

Frame size table:

Codec mode  Frame size
----------------------
0             13
1             14
2             16
3             18
4             20
5             21
6             27
7             32

(Source)

0
votes

Java Code: https://blog.csdn.net/fjh658/article/details/12869073

C# Code (From MemoryStream):

private double getAmrDuration(MemoryStream originalAudio)
    {
            double duration = -1;
            int[] packedSize = new int[] { 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 };

            long length = originalAudio.Length;
            int pos = 6;

            int frameCount = 0;

            int packedPos = -1;

            byte[] datas = new byte[1];

            while ((pos <= length))
            {
            originalAudio.Seek(pos, SeekOrigin.Begin);
                if ((originalAudio.Read(datas, 0, 1) != 1))
                {
                    duration = length > 0 ? ((length - 6) / 650) : 0;
                    break;
                }


                packedPos = (datas[0] >> 3) & 0x0F;
                pos += packedSize[packedPos] + 1;
                frameCount++;
            }

            /// //////////////////////////////////////////////////
            duration = (duration + (frameCount * 20));
            // 'p*20

        return duration/1000;
    }