1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28#include <stdio.h> 29#include <stdlib.h> 30#include <time.h> 31#include <stdint.h> 32#include <assert.h> 33#include "gsmamr_enc.h" 34 35enum { 36 kInputSize = 320, // 160 samples * 16-bit per sample. 37 kOutputSize = 1024 38}; 39 40struct AmrNbEncState { 41 void *encCtx; 42 void *pidSyncCtx; 43}; 44 45void usage(void) { 46 printf("Usage:\n"); 47 printf("AMRNBEnc [options] <input file> <output file>\n"); 48 printf("\n"); 49 printf("Options +M* for setting compression bitrate mode, default is 4.75 kbps\n"); 50 printf(" +M0 = 4.75 kbps\n"); 51 printf(" +M1 = 5.15 kbps\n"); 52 printf(" +M2 = 5.90 kbps\n"); 53 printf(" +M3 = 6.70 kbps\n"); 54 printf(" +M4 = 7.40 kbps\n"); 55 printf(" +M5 = 7.95 kbps\n"); 56 printf(" +M6 = 10.2 kbps\n"); 57 printf(" +M7 = 12.2 kbps\n"); 58 printf("\n"); 59} 60 61int encode(int mode, const char *srcFile, const char *dstFile) { 62 int retVal = EXIT_SUCCESS; 63 FILE *fSrc = NULL; 64 FILE *fDst = NULL; 65 int frameNum = 0; 66 bool eofReached = false; 67 uint16_t *inputBuf = NULL; 68 uint8_t *outputBuf = NULL; 69 AmrNbEncState *amr = NULL; 70 71 clock_t start, finish; 72 double duration = 0.0; 73 74 // Open input file. 75 fSrc = fopen(srcFile, "rb"); 76 if (fSrc == NULL) { 77 fprintf(stderr, "Error opening input file\n"); 78 retVal = EXIT_FAILURE; 79 goto safe_exit; 80 } 81 82 // Open output file. 83 fDst = fopen(dstFile, "wb"); 84 if (fDst == NULL) { 85 fprintf(stderr, "Error opening output file\n"); 86 retVal = EXIT_FAILURE; 87 goto safe_exit; 88 } 89 90 // Allocate input buffer. 91 inputBuf = (uint16_t*) malloc(kInputSize); 92 assert(inputBuf != NULL); 93 94 // Allocate output buffer. 95 outputBuf = (uint8_t*) malloc(kOutputSize); 96 assert(outputBuf != NULL); 97 98 // Initialize encoder. 99 amr = (AmrNbEncState*) malloc(sizeof(AmrNbEncState)); 100 AMREncodeInit(&amr->encCtx, &amr->pidSyncCtx, 0); 101 102 // Write file header. 103 fwrite("#!AMR\n", 1, 6, fDst); 104 105 while (1) { 106 // Read next input frame. 107 int bytesRead; 108 bytesRead = fread(inputBuf, 1, kInputSize, fSrc); 109 if (bytesRead != kInputSize && !feof(fSrc)) { 110 retVal = EXIT_FAILURE; // Invalid magic number. 111 fprintf(stderr, "Error reading input file\n"); 112 goto safe_exit; 113 } else if (feof(fSrc) && bytesRead == 0) { 114 eofReached = true; 115 break; 116 } 117 118 start = clock(); 119 120 // Encode the frame. 121 Frame_Type_3GPP frame_type = (Frame_Type_3GPP) mode; 122 int bytesGenerated; 123 bytesGenerated = AMREncode(amr->encCtx, amr->pidSyncCtx, (Mode)mode, 124 (Word16*)inputBuf, outputBuf, &frame_type, 125 AMR_TX_WMF); 126 127 // Convert from WMF to RFC 3267 format. 128 if (bytesGenerated > 0) { 129 outputBuf[0] = ((outputBuf[0] << 3) | 4) & 0x7c; 130 } 131 132 finish = clock(); 133 duration += finish - start; 134 135 if (bytesGenerated < 0) { 136 retVal = EXIT_FAILURE; 137 fprintf(stderr, "Encoding error\n"); 138 goto safe_exit; 139 } 140 141 frameNum++; 142 printf(" Frames processed: %d\n", frameNum); 143 144 // Write the output. 145 fwrite(outputBuf, 1, bytesGenerated, fDst); 146 } 147 148 // Dump the time taken by encode. 149 printf("\n%2.5lf seconds\n", (double)duration/CLOCKS_PER_SEC); 150 151safe_exit: 152 153 // Free the encoder instance. 154 if (amr) { 155 AMREncodeExit(&amr->encCtx, &amr->pidSyncCtx); 156 free(amr); 157 } 158 159 // Free input and output buffer. 160 free(inputBuf); 161 free(outputBuf); 162 163 // Close the input and output files. 164 if (fSrc) { 165 fclose(fSrc); 166 } 167 if (fDst) { 168 fclose(fDst); 169 } 170 171 return retVal; 172} 173 174int main(int argc, char *argv[]) { 175 Mode mode = MR475; 176 int retVal; 177 char *inFileName = NULL; 178 char *outFileName = NULL; 179 int arg, filename = 0; 180 181 if (argc < 3) { 182 usage(); 183 return EXIT_FAILURE; 184 } else { 185 for (arg = 1; arg < argc; arg++) { 186 if (argv[arg][0] == '+') { 187 if (argv[arg][1] == 'M') { 188 switch (argv[arg][2]) { 189 case '0': mode = MR475; 190 break; 191 case '1': mode = MR515; 192 break; 193 case '2': mode = MR59; 194 break; 195 case '3': mode = MR67; 196 break; 197 case '4': mode = MR74; 198 break; 199 case '5': mode = MR795; 200 break; 201 case '6': mode = MR102; 202 break; 203 case '7': mode = MR122; 204 break; 205 default: 206 usage(); 207 fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]); 208 return EXIT_FAILURE; 209 break; 210 } 211 } else { 212 usage(); 213 fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]); 214 return EXIT_FAILURE; 215 } 216 } else { 217 switch (filename) { 218 case 0: 219 inFileName = argv[arg]; 220 break; 221 case 1: 222 outFileName = argv[arg]; 223 break; 224 default: 225 usage(); 226 fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]); 227 return EXIT_FAILURE; 228 } 229 filename++; 230 } 231 } 232 } 233 234 retVal = encode(mode, inFileName, outFileName); 235 return retVal; 236} 237 238