Converting from AMR to PCM16 does not work.
| Thu, 2005-07-21 08:23 | |
|
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. |
|






Forum posts: 142
const TInt KAmrBufferSize = 320;
const TInt KPcmBufferSize = 10000;
might just work a bit better.
yucca
Forum posts: 127
const TInt KPcmBufferSize = 10000;
320 is less than the actual amr file, so application crashes.
Forum posts: 29
pleaaaaassee!
can't somebody just put a working example code(project) to newlc.
i think a tutorial is required about amr conversion issue.
Forum posts: 127
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.
Forum posts: 29
Forum posts: 16
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?
Forum posts: 127
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.
Forum posts: 76
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:
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