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