Converting from AMR to PCM16 does not work.

Login to reply to this topic.
Thu, 2005-07-21 08:23
Joined: 2005-07-16
Forum posts: 127
Hi everybody,

I have been trying to play AMR file. I used lots of different way to do it. I could not success from any of it. Finally I used CMMFCodec to convert AMR to PCM16 then play the stream.

But Conversion did not work. I took the code snippet from this Forum. I would really appreciate if somebody tell me what I am doing wrong.

void PlayStreamL()
{
RFs fs;
CleanupClosePushL(fs);
User::LeaveIfError(fs.Connect());
RFile file;
CleanupClosePushL(file);

TFileName streamFile(KAmrFile);
User::LeaveIfError(CompleteWithAppPath(streamFile));
User::LeaveIfError(file.Open(fs, streamFile, EFileRead | EFileShareReadersOnly));

TInt fileSize = 0;
file.Size(fileSize);
iStreamData = new (ELeave) TUint8[fileSize];

iStreamBuffer = new (ELeave) TPtr8(iStreamData, fileSize, fileSize);
file.Read(*iStreamBuffer);

//Now iStreamBuffer contains AMR data

CMMFCodec* codec = CMMFCodec::NewL(TUid::Uid(0x101FAF67));
CleanupStack::PushL(codec);

//Program crashes here because 320 is smaller the the AMR file size, I also increased it. I read that AMR frame size should be 320.
CMMFDescriptorBuffer* srcbuf = CMMFDescriptorBuffer::NewL(320);
CleanupStack::PushL(srcbuf);
// Copy your PCM frame data into srcbuf, for example:
srcbuf->Data().Copy(*iStreamBuffer);
CMMFDescriptorBuffer* dstbuf = CMMFDescriptorBuffer::NewL(320);
CleanupStack::PushL(dstbuf);

//Does not process the AMR data, I get the result.iStatus as EDistNotFilled.
TCodecProcessResult result = codec->ProcessL(*srcbuf, *dstbuf);
// dstbuf is empty.

TDesC8 temp = dstbuf->Data();
HBufC8* buf = temp.Alloc();
*iStreamBuffer = buf->Des();

CleanupStack::PopAndDestroy(dstbuf);
CleanupStack::PopAndDestroy(srcbuf);
CleanupStack::PopAndDestroy(codec);

CleanupStack::PopAndDestroy(2);

iState = EPlaying;
iPlayerStream = CMdaAudioOutputStream::NewL(*this);
iPlayerStream->Open(&iStreamSettings);
}

Thanks for any comments.


Thu, 2005-07-21 11:22
Joined: 2003-04-01
Forum posts: 142
Re: Converting from AMR to PCM16 does not work.
try with thsese values:
const TInt KAmrBufferSize = 320;
const TInt KPcmBufferSize = 10000;

might just work a bit better.

yucca
Thu, 2005-07-21 12:54
Joined: 2005-07-16
Forum posts: 127
Re: Converting from AMR to PCM16 does not work.
Quote
const TInt KAmrBufferSize = 320;
const TInt KPcmBufferSize = 10000;

320 is less than the actual amr file, so application crashes.
Fri, 2005-07-22 07:17
Joined: 2005-04-09
Forum posts: 29
Re: Converting from AMR to PCM16 does not work.
I'm also waiting for a good answer to this question desperately .
pleaaaaassee!
can't somebody just put a working example code(project) to newlc.
i think a tutorial is required about amr conversion issue.
Fri, 2005-07-22 07:44
Joined: 2005-07-16
Forum posts: 127
Re: Converting from AMR to PCM16 does not work.
Hello kesken,

I completely agree with you. There is no good example about converting AMR to PCM. Those code snippets you may find around about conversion, does not work. I don't know, why this should be so difficult. Anyway If I find any working solution, I will let you know.
Fri, 2005-07-22 16:01
Joined: 2005-04-09
Forum posts: 29
Re: Converting from AMR to PCM16 does not work.
thanks for your kindness, i hope you'll get success
Tue, 2005-07-26 11:26
Joined: 2005-07-19
Forum posts: 16
Re: Converting from AMR to PCM16 does not work.
I wonder why you chose a value of 320 bytes for the input for AMR. In a packed format, the maximum size for a frame for AMR is 32bytes (for the hishest possible bit rate in AMR).

Symbian has a codec ported which is built in which does the AMR decoding? Which AMR decoder are you trying to use for the decoding?
Wed, 2005-07-27 12:16
Joined: 2005-07-16
Forum posts: 127
Re: Converting from AMR to PCM16 does not work.
Quote
I wonder why you chose a value of 320 bytes for the input for AMR. In a packed format, the maximum size for a frame for AMR is 32bytes (for the hishest possible bit rate in AMR).

Symbian has a codec ported which is built in which does the AMR decoding? Which AMR decoder are you trying to use for the decoding?

Please read the above code, you can see, I am not trying to decode. What I am doing is just converting AMR to PCM.
Tue, 2005-08-16 23:18
Joined: 2005-01-24
Forum posts: 76
Re: Converting from AMR to PCM16 does not work.
Hi

Huh You really don't seem to have understood what an AMR file is and how it is encoded.  Or how to use MMF codecs and buffers.  There's so many things wrong with this code. A little tutorial is in order:

Point 1:
You've new'ed a TPtr8 into existence, and then not put it onto the cleanup stack even though you've called leaving functions subsequently.  Bad man!  The TPtr8 should be an automatic variable in any case.  I'm not sure why you've set the length and the maximum length as the same value either.

Point 2:
An AMR file (a .amr file you can play on any AMR file player) contains a 6-byte binary header, this is always {0x23,0x21,0x41,0x4D,0x52,0x0A}.  If this is the type of file you're trying to decode and convert above, you need to remove the first 6-bytes before you even hit the AMR data you'll feed into the codec.  You haven't done that above.

Point 3:
An AMR file consists of a number of encoded frames of audio data.  Each frame represents 20ms of audio.

Assuming this is a normal AMR file (and not AMR-WB) the sound will decode into 8KHz, 16-bit PCM.  20ms of PCM of this type is 320bytes in size, do the math (8000Hz * 16-bits * 0.02sec = 2560bits = 320bytes).  So, your output MMF buffer in your decoder should be 320 bytes in size, enough to hold 1 frame of decoded AMR. That's all you need.

These 20ms frames of audio are compressed in the AMR file.  Depending on the encoding level used, frames will be the following sizes:

CMR        Mode          Frame size (bytes)
0            AMR 4.75    13
1            AMR 5.15    14
2            AMR 5.9      16
3            AMR 6.7      18
4            AMR 7.4      20
5            AMR 7.95    21
6            AMR 10.2    27
7            AMR 12.2    32

Each frame consists of a 1 byte header, then the rest of the frame is audio data.  The entire frame is fed into the decoder (header too).  The frame size can be deduced from the frame header.  The top 4 bits of the header comprise the CMR, values 0-7 being valid for AMR, the top bit can actually be ignored, though it is used when AMR forms RTP payloads.  The lower 4-bits of the header are reserved and are not used.

Possibly in the code above, you may want to read the frame header byte, deduce the frame size then read enough data to cover that one frame.  Decode that frame into the waiting 320byte PCM output buffer then write that buffer out to another file?

None of this is necessary however as the MMF does all of this for you...

Point 4:
You're output MMF buffer is set to be 320bytes, enough to hold 1 frame of decoded AMR.  OK

You're input buffer can be any size you like really as long as it's big enough to hold at least one frame of AMR.

How to use an MMF codec:
Calling ProcessL() on a codec with a source buffer and a destination buffer will (in this instance) decode 1 frame of AMR from the source into the destination. The processing results in a TCodecProcessResult. This will have one of the following statuses:
  • EProcessComplete - all of the source data has been used and the destination buffer is full.  Read all new data into the source buffer and copy out the decoded frame from the destination buffer before calling ProcessL() again
  • EProcessIncomplete - the destination buffer is filled with one decoded frame, but there is still source data remaining.  Copy the decoded frame out of the destination buffer. Check the number of bytes remaining in the source buffer, if it's less than the minimum AMR frame size (13bytes) copy in new data onto the end of the remaining data and call ProcessL() again
  • EDstNotFilled - should not happen in this case - decoding an AMR frame will ALWAYS produce 320bytes in the destination buffer
  • EEndOfData - not applicable to AMR decoding - once there is no data left in the file, the AMR stream has ended.
  • Other statuses are not used

Keep calling ProcessL() in a loop until all data in the file has been read and decoded.  Copy out the decoded PCM frame each time to another file and everything should be OK.

Hope that helps.

Andy
  • Login to reply to this topic.