1 /**
2 * Aften: A/52 audio encoder
3 * Copyright (c) 2006 Justin Ruggles
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /**
21 * @file aften.c
22 * Commandline encoder frontend
23 */
24
25 #include "common.h"
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <time.h>
31
32 #ifdef _WIN32
33 #include <io.h>
34 #include <fcntl.h>
35 #endif
36
37 #include "aften.h"
38 #include "pcm.h"
39 #include "opts.h"
40
41 static const int acmod_to_ch[8] = { 2, 1, 2, 3, 3, 4, 4, 5 };
42
43 static const char *acmod_str[8] = {
44 "dual mono (1+1)", "mono (1/0)", "stereo (2/0)",
45 "3/0", "2/1", "3/1", "2/2", "3/2"
46 };
47
48 static void
print_intro(FILE * out)49 print_intro(FILE *out)
50 {
51 const char *vers = aften_get_version();
52 fprintf(out, "\nAften: A/52 audio encoder\n"
53 "Version %s\n"
54 "(c) 2006-2007 Justin Ruggles, Prakash Punnoor, et al.\n\n",
55 vers);
56 }
57
58 static void
print_simd_in_use(FILE * out,AftenSimdInstructions * simd_instructions)59 print_simd_in_use(FILE *out, AftenSimdInstructions *simd_instructions)
60 {
61 fprintf(out, "SIMD usage:");
62 if (simd_instructions->mmx)
63 fprintf(out, " MMX");
64 if (simd_instructions->sse)
65 fprintf(out, " SSE");
66 if (simd_instructions->sse2)
67 fprintf(out, " SSE2");
68 if (simd_instructions->sse3)
69 fprintf(out, " SSE3");
70 if (simd_instructions->ssse3)
71 fprintf(out, " SSSE3");
72 if (simd_instructions->amd_3dnow)
73 fprintf(out, " 3DNOW");
74 if (simd_instructions->amd_3dnowext)
75 fprintf(out, " 3DNOWEXT");
76 if (simd_instructions->amd_sse_mmx)
77 fprintf(out, " SSE-MMX");
78 if (simd_instructions->altivec)
79 fprintf(out, " Altivec");
80 fprintf(out, "\n");
81 }
82
83 int
main(int argc,char ** argv)84 main(int argc, char **argv)
85 {
86 uint8_t *frame;
87 FLOAT *fwav;
88 int nr, fs, err;
89 FILE *ifp;
90 FILE *ofp;
91 PcmFile pf;
92 CommandOptions opts;
93 AftenContext s;
94 uint32_t samplecount, bytecount, t0, t1, percent;
95 FLOAT kbps, qual, bw;
96 int last_frame;
97 int frame_cnt;
98 int done;
99 int input_file_format;
100 enum PcmSampleFormat read_format;
101 /* update output every 200ms */
102 clock_t update_clock_span = 0.2f * CLOCKS_PER_SEC;
103 clock_t current_clock;
104 clock_t last_update_clock = clock() - update_clock_span;
105
106 opts.s = &s;
107 aften_set_defaults(&s);
108 err = parse_commandline(argc, argv, &opts);
109 if(err) {
110 if(err == 1) {
111 print_intro(stderr);
112 print_usage(stderr);
113 return 1;
114 } else {
115 print_intro(stdout);
116 if(err == 2) {
117 print_help(stdout);
118 } else if(err == 3) {
119 print_long_help(stdout);
120 }
121 return 0;
122 }
123 }
124
125 if(s.verbose > 0) {
126 print_intro(stderr);
127 }
128
129 if(!strncmp(opts.infile, "-", 2)) {
130 #ifdef _WIN32
131 _setmode(_fileno(stdin), _O_BINARY);
132 #endif
133 ifp = stdin;
134 } else {
135 ifp = fopen(opts.infile, "rb");
136 if(!ifp) {
137 fprintf(stderr, "error opening input file: %s\n", opts.infile);
138 return 1;
139 }
140 }
141
142 #ifdef CONFIG_DOUBLE
143 read_format = PCM_SAMPLE_FMT_DBL;
144 #else
145 read_format = PCM_SAMPLE_FMT_FLT;
146 #endif
147
148 // initialize pcmfile using input
149 input_file_format = PCM_FORMAT_UNKNOWN;
150 if(opts.raw_input)
151 input_file_format = PCM_FORMAT_RAW;
152 if(pcmfile_init(&pf, ifp, read_format, input_file_format)) {
153 fprintf(stderr, "invalid input file: %s\n", argv[1]);
154 return 1;
155 }
156 if(opts.read_to_eof)
157 pf.read_to_eof = 1;
158 if(opts.raw_input) {
159 pf.sample_rate = opts.raw_sr;
160 pf.channels = opts.raw_ch;
161 pcmfile_set_source(&pf, opts.raw_fmt, opts.raw_order);
162 }
163
164 // print wav info to console
165 if(s.verbose > 0) {
166 fprintf(stderr, "input format: ");
167 pcmfile_print(&pf, stderr);
168 }
169
170 // if acmod is given on commandline, determine lfe from number of channels
171 if(s.acmod >= 0) {
172 int ch = acmod_to_ch[s.acmod];
173 if(ch == pf.channels) {
174 if(s.lfe < 0) {
175 s.lfe = 0;
176 } else {
177 if(s.lfe != 0) {
178 fprintf(stderr, "acmod and lfe do not match number of channels\n");
179 return 1;
180 }
181 }
182 } else if(ch == (pf.channels - 1)) {
183 if(s.lfe < 0) {
184 s.lfe = 1;
185 } else {
186 if(s.lfe != 1) {
187 fprintf(stderr, "acmod and lfe do not match number of channels\n");
188 return 1;
189 }
190 }
191 } else {
192 fprintf(stderr, "acmod does not match number of channels\n");
193 return 1;
194 }
195 } else {
196 // if acmod is not given on commandline, determine from WAVE file
197 int ch = pf.channels;
198 if(s.lfe >= 0) {
199 if(s.lfe == 0 && ch == 6) {
200 fprintf(stderr, "cannot encode 6 channels w/o LFE\n");
201 return 1;
202 } else if(s.lfe == 1 && ch == 1) {
203 fprintf(stderr, "cannot encode LFE channel only\n");
204 return 1;
205 }
206 if(s.lfe) {
207 pf.ch_mask |= 0x08;
208 }
209 }
210 if(aften_wav_channels_to_acmod(ch, pf.ch_mask, &s.acmod, &s.lfe)) {
211 fprintf(stderr, "mismatch in channels, acmod, and lfe params\n");
212 return 1;
213 }
214 }
215 // set some encoding parameters using wav info
216 s.channels = pf.channels;
217 s.samplerate = pf.sample_rate;
218 #ifdef CONFIG_DOUBLE
219 s.sample_format = A52_SAMPLE_FMT_DBL;
220 #else
221 s.sample_format = A52_SAMPLE_FMT_FLT;
222 #endif
223
224 // initialize encoder
225 if(aften_encode_init(&s)) {
226 fprintf(stderr, "error initializing encoder\n");
227 aften_encode_close(&s);
228 return 1;
229 }
230
231 // open output file
232 if(!strncmp(opts.outfile, "-", 2)) {
233 #ifdef _WIN32
234 _setmode(_fileno(stdout), _O_BINARY);
235 #endif
236 ofp = stdout;
237 } else {
238 ofp = fopen(opts.outfile, "wb");
239 if(!ofp) {
240 fprintf(stderr, "error opening output file: %s\n", opts.outfile);
241 return 1;
242 }
243 }
244
245 // print ac3 info to console
246 if(s.verbose > 0) {
247 fprintf(stderr, "output format: %d Hz %s", s.samplerate,
248 acmod_str[s.acmod]);
249 if(s.lfe) {
250 fprintf(stderr, " + LFE");
251 }
252 fprintf(stderr, "\n\n");
253 }
254
255 /* print SIMD instructions used */
256 print_simd_in_use(stderr, &s.system.wanted_simd_instructions);
257
258 /* print number of threads used */
259 fprintf(stderr, "Threads: %i\n\n", s.system.n_threads);
260
261 // allocate memory for coded frame and sample buffer
262 frame = calloc(A52_MAX_CODED_FRAME_SIZE, 1);
263 fwav = calloc(A52_SAMPLES_PER_FRAME * s.channels, sizeof(FLOAT));
264 if(frame == NULL || fwav == NULL) {
265 aften_encode_close(&s);
266 exit(1);
267 }
268
269 samplecount = bytecount = t0 = t1 = percent = 0;
270 qual = bw = 0.0;
271 last_frame = 0;
272 frame_cnt = 0;
273 done = 0;
274 fs = 0;
275 nr = 0;
276
277 // don't pad start with zero samples, use input audio instead.
278 // not recommended, but providing the option here for when sync is needed
279 if(!opts.pad_start) {
280 FLOAT *sptr = &fwav[1280*s.channels];
281 nr = pcmfile_read_samples(&pf, sptr, 256);
282 if(opts.chmap == 0) {
283 aften_remap_wav_to_a52(sptr, nr, s.channels, s.sample_format,
284 s.acmod);
285 } else if(opts.chmap == 2) {
286 aften_remap_mpeg_to_a52(sptr, nr, s.channels, s.sample_format,
287 s.acmod);
288 }
289 fs = aften_encode_frame(&s, frame, fwav);
290 if(fs < 0) {
291 fprintf(stderr, "Error encoding initial frame\n");
292 goto end;
293 }
294 }
295
296 nr = pcmfile_read_samples(&pf, fwav, A52_SAMPLES_PER_FRAME);
297 while(nr > 0 || fs > 0) {
298 if(opts.chmap == 0) {
299 aften_remap_wav_to_a52(fwav, nr, s.channels, s.sample_format,
300 s.acmod);
301 } else if(opts.chmap == 2) {
302 aften_remap_mpeg_to_a52(fwav, nr, s.channels, s.sample_format,
303 s.acmod);
304 }
305
306 // append extra silent frame if final frame is > 1280 samples
307 if(nr == 0) {
308 if(last_frame <= 1280) {
309 done = 1;
310 }
311 }
312
313 // zero leftover samples at end of last frame
314 if(!done && nr < A52_SAMPLES_PER_FRAME) {
315 int i;
316 for(i=nr*s.channels; i<A52_SAMPLES_PER_FRAME*s.channels; i++) {
317 fwav[i] = 0.0;
318 }
319 }
320
321 fs = aften_encode_frame(&s, frame, done ? NULL : fwav);
322
323 if(fs < 0) {
324 fprintf(stderr, "Error encoding frame %d\n", frame_cnt);
325 break;
326 } else {
327 if(s.verbose > 0) {
328 if (fs > 0) {
329 samplecount += A52_SAMPLES_PER_FRAME;
330 bytecount += fs;
331 qual += s.status.quality;
332 bw += s.status.bwcode;
333 }
334 current_clock = clock();
335 /* make sure we write out when finished, i.e. when fs == 0 */
336 if (current_clock - last_update_clock >= update_clock_span || !fs || s.verbose == 2) {
337 if(s.verbose == 1) {
338 t1 = samplecount / pf.sample_rate;
339 if(frame_cnt > 0 && (t1 > t0 || samplecount >= pf.samples)) {
340 kbps = (bytecount * FCONST(8.0) * pf.sample_rate) /
341 (FCONST(1000.0) * samplecount);
342 percent = 0;
343 if(pf.samples > 0) {
344 percent = (uint32_t)((samplecount * FCONST(100.0)) /
345 pf.samples);
346 percent = CLIP(percent, 0, 100);
347 }
348 fprintf(stderr, "\rprogress: %3u%% | q: %4.1f | "
349 "bw: %2.1f | bitrate: %4.1f kbps ",
350 percent, (qual / (frame_cnt+1)),
351 (bw / (frame_cnt+1)), kbps);
352 }
353 t0 = t1;
354 } else if(s.verbose == 2) {
355 fprintf(stderr, "frame: %7d | q: %4d | bw: %2d | bitrate: %3d kbps\n",
356 frame_cnt, s.status.quality, s.status.bwcode,
357 s.status.bit_rate);
358 }
359 last_update_clock = current_clock;
360 }
361 }
362 fwrite(frame, 1, fs, ofp);
363 }
364 frame_cnt++;
365 last_frame = nr;
366 nr = pcmfile_read_samples(&pf, fwav, A52_SAMPLES_PER_FRAME);
367 }
368 if(s.verbose == 1) {
369 fprintf(stderr, "\n\n");
370 } else if(s.verbose == 2) {
371 if(samplecount > 0) {
372 kbps = (bytecount * FCONST(8.0) * pf.sample_rate) / (FCONST(1000.0) * samplecount);
373 } else {
374 kbps = 0;
375 }
376 frame_cnt = MAX(frame_cnt, 1);
377 fprintf(stderr, "\n");
378 fprintf(stderr, "average quality: %4.1f\n", (qual / frame_cnt));
379 fprintf(stderr, "average bandwidth: %2.1f\n", (bw / frame_cnt));
380 fprintf(stderr, "average bitrate: %4.1f kbps\n\n", kbps);
381 }
382 end:
383 free(fwav);
384 free(frame);
385
386 pcmfile_close(&pf);
387 fclose(ifp);
388 fclose(ofp);
389
390 aften_encode_close(&s);
391
392 return 0;
393 }
394