/* * 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 #include #include #include #include #include "gsmamr_dec.h" #include // 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 \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; }