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 
35 enum {
36     kInputSize = 320, // 160 samples * 16-bit per sample.
37     kOutputSize = 1024
38 };
39 
40 struct AmrNbEncState {
41     void *encCtx;
42     void *pidSyncCtx;
43 };
44 
usage(void)45 void 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 
encode(int mode,const char * srcFile,const char * dstFile)61 int 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 
151 safe_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 
main(int argc,char * argv[])174 int 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