| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| #include <malloc.h> |
| #include <stdio.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <assert.h> |
| |
| #include "gsmamr_dec.h" |
| #include <audio_utils/sndfile.h> |
| |
| // Constants for AMR-NB |
| enum { |
| kInputBufferSize = 64, |
| kSamplesPerFrame = 160, |
| kBitsPerSample = 16, |
| kOutputBufferSize = kSamplesPerFrame * kBitsPerSample/8, |
| kSampleRate = 8000, |
| kChannels = 1, |
| kFileHeaderSize = 6 |
| }; |
| const uint32_t kFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31}; |
| |
| |
| int main(int argc, char *argv[]) { |
| |
| if(argc != 3) { |
| fprintf(stderr, "Usage %s <input file> <output file>\n", argv[0]); |
| return 1; |
| } |
| |
| // Open the input file |
| FILE* fpInput = fopen(argv[1], "rb"); |
| if (!fpInput) { |
| fprintf(stderr, "Could not open %s\n", argv[1]); |
| return 1; |
| } |
| |
| // Validate the input AMR file |
| char header[kFileHeaderSize]; |
| int bytesRead = fread(header, 1, kFileHeaderSize, fpInput); |
| if (bytesRead != kFileHeaderSize || memcmp(header, "#!AMR\n", kFileHeaderSize)) { |
| fprintf(stderr, "Invalid AMR-NB file\n"); |
| return 1; |
| } |
| |
| // Open the output file |
| SF_INFO sfInfo; |
| memset(&sfInfo, 0, sizeof(SF_INFO)); |
| sfInfo.channels = kChannels; |
| sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; |
| sfInfo.samplerate = kSampleRate; |
| SNDFILE *handle = sf_open(argv[2], SFM_WRITE, &sfInfo); |
| if(!handle){ |
| fprintf(stderr, "Could not create %s\n", argv[2]); |
| return 1; |
| } |
| |
| // Create AMR-NB decoder instance |
| void* amrHandle; |
| int err = GSMInitDecode(&amrHandle, (Word8*)"AMRNBDecoder"); |
| if(err != 0){ |
| fprintf(stderr, "Error creating AMR-NB decoder instance\n"); |
| return 1; |
| } |
| |
| //Allocate input buffer |
| void *inputBuf = malloc(kInputBufferSize); |
| assert(inputBuf != NULL); |
| |
| //Allocate output buffer |
| void *outputBuf = malloc(kOutputBufferSize); |
| assert(outputBuf != NULL); |
| |
| |
| // Decode loop |
| uint32_t retVal = 0; |
| while (1) { |
| // Read mode |
| uint8_t mode; |
| bytesRead = fread(&mode, 1, 1, fpInput); |
| if (bytesRead != 1) break; |
| |
| // Find frame type |
| Frame_Type_3GPP frameType = (Frame_Type_3GPP)((mode >> 3) & 0x0f); |
| if (frameType >= AMR_SID){ |
| fprintf(stderr, "Frame type %d not supported\n",frameType); |
| retVal = 1; |
| break; |
| } |
| |
| // Find frame type |
| int32_t frameSize = kFrameSizes[frameType]; |
| bytesRead = fread(inputBuf, 1, frameSize, fpInput); |
| if (bytesRead != frameSize) break; |
| |
| //Decode frame |
| int32_t decodeStatus; |
| decodeStatus = AMRDecode(amrHandle, frameType, (uint8_t*)inputBuf, |
| (int16_t*)outputBuf, MIME_IETF); |
| if(decodeStatus == -1) { |
| fprintf(stderr, "Decoder encountered error\n"); |
| retVal = 1; |
| break; |
| } |
| |
| //Write output to wav |
| sf_writef_short(handle, (int16_t*)outputBuf, kSamplesPerFrame); |
| |
| } |
| |
| // Close input and output file |
| fclose(fpInput); |
| sf_close(handle); |
| |
| //Free allocated memory |
| free(inputBuf); |
| free(outputBuf); |
| |
| // Close decoder instance |
| GSMDecodeFrameExit(&amrHandle); |
| |
| return retVal; |
| } |