]> iEval git - fdkaac.git/blame_incremental - src/main.c
improve handling of avgBitrate
[fdkaac.git] / src / main.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
4 */
5#if HAVE_CONFIG_H
6# include "config.h"
7#endif
8#if HAVE_STDINT_H
9# include <stdint.h>
10#endif
11#if HAVE_INTTYPES_H
12# include <inttypes.h>
13#elif defined(_MSC_VER)
14# define SCNd64 "I64d"
15#endif
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <ctype.h>
20#include <locale.h>
21#include <errno.h>
22#include <sys/stat.h>
23#include <getopt.h>
24#if HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#if HAVE_SIGACTION
28#include <signal.h>
29#endif
30#ifdef _WIN32
31#include <io.h>
32#define WIN32_LEAN_AND_MEAN
33#include <windows.h>
34#endif
35#include "compat.h"
36#include "wav_reader.h"
37#include "aacenc.h"
38#include "m4af.h"
39#include "progress.h"
40#include "version.h"
41#include "metadata.h"
42
43#define PROGNAME "fdkaac"
44
45static volatile int g_interrupted = 0;
46
47#if HAVE_SIGACTION
48static void signal_handler(int signum)
49{
50 g_interrupted = 1;
51}
52static void handle_signals(void)
53{
54 int i, sigs[] = { SIGINT, SIGHUP, SIGTERM };
55 for (i = 0; i < sizeof(sigs)/sizeof(sigs[0]); ++i) {
56 struct sigaction sa = { 0 };
57 sa.sa_handler = signal_handler;
58 sa.sa_flags |= SA_RESTART;
59 sigaction(sigs[i], &sa, 0);
60 }
61}
62#elif defined(_WIN32)
63static BOOL WINAPI signal_handler(DWORD type)
64{
65 g_interrupted = 1;
66 return TRUE;
67}
68
69static void handle_signals(void)
70{
71 SetConsoleCtrlHandler(signal_handler, TRUE);
72}
73#else
74static void handle_signals(void)
75{
76}
77#endif
78
79static
80int read_callback(void *cookie, void *data, uint32_t size)
81{
82 size_t rc = fread(data, 1, size, (FILE*)cookie);
83 return ferror((FILE*)cookie) ? -1 : (int)rc;
84}
85
86static
87int write_callback(void *cookie, const void *data, uint32_t size)
88{
89 size_t rc = fwrite(data, 1, size, (FILE*)cookie);
90 return ferror((FILE*)cookie) ? -1 : (int)rc;
91}
92
93static
94int seek_callback(void *cookie, int64_t off, int whence)
95{
96 return fseeko((FILE*)cookie, off, whence);
97}
98
99static
100int64_t tell_callback(void *cookie)
101{
102 return ftello((FILE*)cookie);
103}
104
105static
106void usage(void)
107{
108 printf(
109PROGNAME " %s\n"
110"Usage: " PROGNAME " [options] input_file\n"
111"Options:\n"
112" -h, --help Print this help message\n"
113" -p, --profile <n> Profile (audio object type)\n"
114" 2: MPEG-4 AAC LC (default)\n"
115" 5: MPEG-4 HE-AAC (SBR)\n"
116" 29: MPEG-4 HE-AAC v2 (SBR+PS)\n"
117" 23: MPEG-4 AAC LD\n"
118" 39: MPEG-4 AAC ELD\n"
119" 129: MPEG-2 AAC LC\n"
120" 132: MPEG-2 HE-AAC (SBR)\n"
121" 156: MPEG-2 HE-AAC v2 (SBR+PS)\n"
122" -b, --bitrate <n> Bitrate in bits per seconds (for CBR)\n"
123" -m, --bitrate-mode <n> Bitrate configuration\n"
124" 0: CBR (default)\n"
125" 1-5: VBR\n"
126" (VBR mode is not officially supported, and\n"
127" works only on a certain combination of\n"
128" parameter settings, sample rate, and\n"
129" channel configuration)\n"
130" -w, --bandwidth <n> Frequency bandwidth in Hz (AAC LC only)\n"
131" -a, --afterburner <n> Afterburner\n"
132" 0: Off\n"
133" 1: On(default)\n"
134" -L, --lowdelay-sbr Enable ELD-SBR (AAC ELD only)\n"
135" -s, --sbr-signaling <n> SBR signaling mode\n"
136" 0: Implicit, backward compatible(default)\n"
137" 1: Explicit SBR and implicit PS\n"
138" 2: Explicit hierarchical signaling\n"
139" -f, --transport-format <n> Transport format\n"
140" 0: RAW (default, muxed into M4A)\n"
141" 1: ADIF\n"
142" 2: ADTS\n"
143" 6: LATM MCP=1\n"
144" 7: LATM MCP=0\n"
145" 10: LOAS/LATM (LATM within LOAS)\n"
146" -C, --adts-crc-check Add CRC protection on ADTS header\n"
147" -h, --header-period <n> StreamMuxConfig/PCE repetition period in\n"
148" transport layer\n"
149"\n"
150" -o <filename> Output filename\n"
151" -G, --gapless-mode <n> Encoder delay signaling for gapless playback\n"
152" 0: iTunSMPB (default)\n"
153" 1: ISO standard (edts + sgpd)\n"
154" 2: Both\n"
155" --ignorelength Ignore length of WAV header\n"
156" -S, --silent Don't print progress messages\n"
157" --moov-before-mdat Place moov box before mdat box on m4a output\n"
158"\n"
159"Options for raw (headerless) input:\n"
160" -R, --raw Treat input as raw (by default WAV is\n"
161" assumed)\n"
162" --raw-channels <n> Number of channels (default: 2)\n"
163" --raw-rate <n> Sample rate (default: 44100)\n"
164" --raw-format <spec> Sample format, default is \"S16L\".\n"
165" Spec is as follows:\n"
166" 1st char: S(igned)|U(nsigned)|F(loat)\n"
167" 2nd part: bits per channel\n"
168" Last char: L(ittle)|B(ig)\n"
169" Last char can be omitted, in which case L is\n"
170" assumed. Spec is case insensitive, therefore\n"
171" \"u16b\" is same as \"U16B\".\n"
172"\n"
173"Tagging options:\n"
174" --title <string>\n"
175" --artist <string>\n"
176" --album <string>\n"
177" --genre <string>\n"
178" --date <string>\n"
179" --composer <string>\n"
180" --grouping <string>\n"
181" --comment <string>\n"
182" --album-artist <string>\n"
183" --track <number[/total]>\n"
184" --disk <number[/total]>\n"
185" --tempo <n>\n"
186" --tag <fcc>:<value> Set iTunes predefined tag with four char code.\n"
187" --tag-from-file <fcc>:<filename>\n"
188" Same as above, but value is read from file.\n"
189" --long-tag <name>:<value> Set arbitrary tag as iTunes custom metadata.\n"
190" --tag-from-json <filename[?dot_notation]>\n"
191" Read tags from JSON. By default, tags are\n"
192" assumed to be direct children of the root\n"
193" object(dictionary).\n"
194" Optionally, position of the dictionary\n"
195" that contains tags can be specified with\n"
196" dotted notation.\n"
197" Example:\n"
198" --tag-from-json /path/to/json?format.tags\n"
199 , fdkaac_version);
200}
201
202typedef struct aacenc_param_ex_t {
203 AACENC_PARAMS
204
205 char *input_filename;
206 char *output_filename;
207 unsigned gapless_mode;
208 unsigned ignore_length;
209 int silent;
210 int moov_before_mdat;
211
212 int is_raw;
213 unsigned raw_channels;
214 unsigned raw_rate;
215 const char *raw_format;
216
217 aacenc_tag_param_t tags;
218
219 char *json_filename;
220} aacenc_param_ex_t;
221
222static
223int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
224{
225 int ch;
226 unsigned n;
227
228#define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v')
229#define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n')
230#define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t')
231#define OPT_RAW_FORMAT M4AF_FOURCC('r','f','m','t')
232#define OPT_SHORT_TAG M4AF_FOURCC('s','t','a','g')
233#define OPT_SHORT_TAG_FILE M4AF_FOURCC('s','t','g','f')
234#define OPT_LONG_TAG M4AF_FOURCC('l','t','a','g')
235#define OPT_TAG_FROM_JSON M4AF_FOURCC('t','f','j','s')
236
237 static struct option long_options[] = {
238 { "help", no_argument, 0, 'h' },
239 { "profile", required_argument, 0, 'p' },
240 { "bitrate", required_argument, 0, 'b' },
241 { "bitrate-mode", required_argument, 0, 'm' },
242 { "bandwidth", required_argument, 0, 'w' },
243 { "afterburner", required_argument, 0, 'a' },
244 { "lowdelay-sbr", no_argument, 0, 'L' },
245 { "sbr-signaling", required_argument, 0, 's' },
246 { "transport-format", required_argument, 0, 'f' },
247 { "adts-crc-check", no_argument, 0, 'C' },
248 { "header-period", required_argument, 0, 'P' },
249
250 { "gapless-mode", required_argument, 0, 'G' },
251 { "ignorelength", no_argument, 0, 'I' },
252 { "silent", no_argument, 0, 'S' },
253 { "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT },
254
255 { "raw", no_argument, 0, 'R' },
256 { "raw-channels", required_argument, 0, OPT_RAW_CHANNELS },
257 { "raw-rate", required_argument, 0, OPT_RAW_RATE },
258 { "raw-format", required_argument, 0, OPT_RAW_FORMAT },
259
260 { "title", required_argument, 0, M4AF_TAG_TITLE },
261 { "artist", required_argument, 0, M4AF_TAG_ARTIST },
262 { "album", required_argument, 0, M4AF_TAG_ALBUM },
263 { "genre", required_argument, 0, M4AF_TAG_GENRE },
264 { "date", required_argument, 0, M4AF_TAG_DATE },
265 { "composer", required_argument, 0, M4AF_TAG_COMPOSER },
266 { "grouping", required_argument, 0, M4AF_TAG_GROUPING },
267 { "comment", required_argument, 0, M4AF_TAG_COMMENT },
268 { "album-artist", required_argument, 0, M4AF_TAG_ALBUM_ARTIST },
269 { "track", required_argument, 0, M4AF_TAG_TRACK },
270 { "disk", required_argument, 0, M4AF_TAG_DISK },
271 { "tempo", required_argument, 0, M4AF_TAG_TEMPO },
272 { "tag", required_argument, 0, OPT_SHORT_TAG },
273 { "tag-from-file", required_argument, 0, OPT_SHORT_TAG_FILE },
274 { "long-tag", required_argument, 0, OPT_LONG_TAG },
275 { "tag-from-json", required_argument, 0, OPT_TAG_FROM_JSON },
276 { 0, 0, 0, 0 },
277 };
278 params->afterburner = 1;
279
280 aacenc_getmainargs(&argc, &argv);
281 while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:Ls:f:CP:G:Io:SR",
282 long_options, 0)) != EOF) {
283 switch (ch) {
284 case 'h':
285 return usage(), -1;
286 case 'p':
287 if (sscanf(optarg, "%u", &n) != 1) {
288 fprintf(stderr, "invalid arg for profile\n");
289 return -1;
290 }
291 params->profile = n;
292 break;
293 case 'b':
294 if (sscanf(optarg, "%u", &n) != 1) {
295 fprintf(stderr, "invalid arg for bitrate\n");
296 return -1;
297 }
298 params->bitrate = n;
299 break;
300 case 'm':
301 if (sscanf(optarg, "%u", &n) != 1 || n > 5) {
302 fprintf(stderr, "invalid arg for bitrate-mode\n");
303 return -1;
304 }
305 params->bitrate_mode = n;
306 break;
307 case 'w':
308 if (sscanf(optarg, "%u", &n) != 1) {
309 fprintf(stderr, "invalid arg for bandwidth\n");
310 return -1;
311 }
312 params->bandwidth = n;
313 break;
314 case 'a':
315 if (sscanf(optarg, "%u", &n) != 1 || n > 1) {
316 fprintf(stderr, "invalid arg for afterburner\n");
317 return -1;
318 }
319 params->afterburner = n;
320 break;
321 case 'L':
322 params->lowdelay_sbr = 1;
323 break;
324 case 's':
325 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
326 fprintf(stderr, "invalid arg for sbr-signaling\n");
327 return -1;
328 }
329 params->sbr_signaling = n;
330 break;
331 case 'f':
332 if (sscanf(optarg, "%u", &n) != 1) {
333 fprintf(stderr, "invalid arg for transport-format\n");
334 return -1;
335 }
336 params->transport_format = n;
337 break;
338 case 'C':
339 params->adts_crc_check = 1;
340 break;
341 case 'P':
342 if (sscanf(optarg, "%u", &n) != 1) {
343 fprintf(stderr, "invalid arg for header-period\n");
344 return -1;
345 }
346 params->header_period = n;
347 break;
348 case 'o':
349 params->output_filename = optarg;
350 break;
351 case 'G':
352 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
353 fprintf(stderr, "invalid arg for gapless-mode\n");
354 return -1;
355 }
356 params->gapless_mode = n;
357 break;
358 case 'I':
359 params->ignore_length = 1;
360 break;
361 case 'S':
362 params->silent = 1;
363 break;
364 case OPT_MOOV_BEFORE_MDAT:
365 params->moov_before_mdat = 1;
366 break;
367 case 'R':
368 params->is_raw = 1;
369 break;
370 case OPT_RAW_CHANNELS:
371 if (sscanf(optarg, "%u", &n) != 1) {
372 fprintf(stderr, "invalid arg for raw-channels\n");
373 return -1;
374 }
375 params->raw_channels = n;
376 break;
377 case OPT_RAW_RATE:
378 if (sscanf(optarg, "%u", &n) != 1) {
379 fprintf(stderr, "invalid arg for raw-rate\n");
380 return -1;
381 }
382 params->raw_rate = n;
383 break;
384 case OPT_RAW_FORMAT:
385 params->raw_format = optarg;
386 break;
387 case M4AF_TAG_TITLE:
388 case M4AF_TAG_ARTIST:
389 case M4AF_TAG_ALBUM:
390 case M4AF_TAG_GENRE:
391 case M4AF_TAG_DATE:
392 case M4AF_TAG_COMPOSER:
393 case M4AF_TAG_GROUPING:
394 case M4AF_TAG_COMMENT:
395 case M4AF_TAG_ALBUM_ARTIST:
396 case M4AF_TAG_TRACK:
397 case M4AF_TAG_DISK:
398 case M4AF_TAG_TEMPO:
399 aacenc_param_add_itmf_entry(&params->tags, ch, 0, optarg,
400 strlen(optarg), 0);
401 break;
402 case OPT_SHORT_TAG:
403 case OPT_SHORT_TAG_FILE:
404 case OPT_LONG_TAG:
405 {
406 char *val;
407 size_t klen;
408 unsigned fcc = M4AF_FOURCC('-','-','-','-');
409
410 if ((val = strchr(optarg, ':')) == 0) {
411 fprintf(stderr, "invalid arg for tag\n");
412 return -1;
413 }
414 *val++ = '\0';
415 if (ch == OPT_SHORT_TAG || ch == OPT_SHORT_TAG_FILE) {
416 /*
417 * take care of U+00A9(COPYRIGHT SIGN).
418 * 1) if length of fcc is 3, we prepend '\xa9'.
419 * 2) U+00A9 becomes "\xc2\xa9" in UTF-8. Therefore
420 * we remove first '\xc2'.
421 */
422 if (optarg[0] == '\xc2')
423 ++optarg;
424 if ((klen = strlen(optarg))== 3)
425 fcc = 0xa9;
426 else if (klen != 4) {
427 fprintf(stderr, "invalid arg for tag\n");
428 return -1;
429 }
430 for (; *optarg; ++optarg)
431 fcc = ((fcc << 8) | (*optarg & 0xff));
432 }
433 aacenc_param_add_itmf_entry(&params->tags, fcc, optarg,
434 val, strlen(val),
435 ch == OPT_SHORT_TAG_FILE);
436 }
437 break;
438 case OPT_TAG_FROM_JSON:
439 params->json_filename = optarg;
440 break;
441 default:
442 return usage(), -1;
443 }
444 }
445 if (argc == optind)
446 return usage(), -1;
447
448 if (!params->bitrate && !params->bitrate_mode) {
449 fprintf(stderr, "bitrate or bitrate-mode is mandatory\n");
450 return -1;
451 }
452 if (params->output_filename && !strcmp(params->output_filename, "-") &&
453 !params->transport_format) {
454 fprintf(stderr, "stdout streaming is not available on M4A output\n");
455 return -1;
456 }
457 if (params->bitrate && params->bitrate < 10000)
458 params->bitrate *= 1000;
459
460 if (params->is_raw) {
461 if (!params->raw_channels)
462 params->raw_channels = 2;
463 if (!params->raw_rate)
464 params->raw_rate = 44100;
465 if (!params->raw_format)
466 params->raw_format = "S16L";
467 }
468 params->input_filename = argv[optind];
469 return 0;
470};
471
472static
473int write_sample(FILE *ofp, m4af_ctx_t *m4af,
474 const void *data, uint32_t size, uint32_t duration)
475{
476 if (!m4af) {
477 fwrite(data, 1, size, ofp);
478 if (ferror(ofp)) {
479 fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno));
480 return -1;
481 }
482 } else if (m4af_write_sample(m4af, 0, data, size, duration) < 0) {
483 fprintf(stderr, "ERROR: failed to write m4a sample\n");
484 return -1;
485 }
486 return 0;
487}
488
489static
490int encode(wav_reader_t *wavf, HANDLE_AACENCODER encoder,
491 uint32_t frame_length, FILE *ofp, m4af_ctx_t *m4af,
492 int show_progress)
493{
494 uint8_t *ibuf = 0;
495 int16_t *pcmbuf = 0;
496 uint32_t pcmsize = 0;
497 uint8_t *obuf = 0;
498 uint32_t olen;
499 uint32_t osize = 0;
500 int nread = 1;
501 int consumed;
502 int rc = -1;
503 int frames_written = 0;
504 aacenc_progress_t progress = { 0 };
505 const pcm_sample_description_t *format = wav_get_format(wavf);
506
507 ibuf = malloc(frame_length * format->bytes_per_frame);
508 aacenc_progress_init(&progress, wav_get_length(wavf), format->sample_rate);
509 do {
510 if (g_interrupted)
511 nread = 0;
512 else if (nread) {
513 if ((nread = wav_read_frames(wavf, ibuf, frame_length)) < 0) {
514 fprintf(stderr, "ERROR: read failed\n");
515 goto END;
516 } else if (nread > 0) {
517 if (pcm_convert_to_native_sint16(format, ibuf, nread,
518 &pcmbuf, &pcmsize) < 0) {
519 fprintf(stderr, "ERROR: unsupported sample format\n");
520 goto END;
521 }
522 }
523 if (show_progress)
524 aacenc_progress_update(&progress, wav_get_position(wavf),
525 format->sample_rate * 2);
526 }
527 if ((consumed = aac_encode_frame(encoder, format, pcmbuf, nread,
528 &obuf, &olen, &osize)) < 0)
529 goto END;
530 if (olen > 0) {
531 if (write_sample(ofp, m4af, obuf, olen, frame_length) < 0)
532 goto END;
533 ++frames_written;
534 }
535 } while (nread > 0 || olen > 0);
536
537 if (show_progress)
538 aacenc_progress_finish(&progress, wav_get_position(wavf));
539 rc = frames_written;
540END:
541 if (ibuf) free(ibuf);
542 if (pcmbuf) free(pcmbuf);
543 if (obuf) free(obuf);
544 return rc;
545}
546
547static
548void put_tool_tag(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
549 HANDLE_AACENCODER encoder)
550{
551 char tool_info[256];
552 char *p = tool_info;
553 LIB_INFO *lib_info = 0;
554
555 p += sprintf(p, PROGNAME " %s, ", fdkaac_version);
556
557 lib_info = calloc(FDK_MODULE_LAST, sizeof(LIB_INFO));
558 if (aacEncGetLibInfo(lib_info) == AACENC_OK) {
559 int i;
560 for (i = 0; i < FDK_MODULE_LAST; ++i)
561 if (lib_info[i].module_id == FDK_AACENC)
562 break;
563 p += sprintf(p, "libfdk-aac %s, ", lib_info[i].versionStr);
564 }
565 free(lib_info);
566 if (params->bitrate_mode)
567 sprintf(p, "VBR mode %d", params->bitrate_mode);
568 else
569 sprintf(p, "CBR %dkbps",
570 aacEncoder_GetParam(encoder, AACENC_BITRATE) / 1000);
571
572 m4af_add_itmf_string_tag(m4af, M4AF_TAG_TOOL, tool_info);
573}
574
575static
576int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
577 HANDLE_AACENCODER encoder)
578{
579 unsigned i;
580 aacenc_tag_entry_t *tag = params->tags.tag_table;
581
582 if (params->json_filename)
583 aacenc_put_tags_from_json(m4af, params->json_filename);
584
585 for (i = 0; i < params->tags.tag_count; ++i, ++tag)
586 aacenc_put_tag_entry(m4af, tag);
587
588 put_tool_tag(m4af, params, encoder);
589
590 if (m4af_finalize(m4af, params->moov_before_mdat) < 0) {
591 fprintf(stderr, "ERROR: failed to finalize m4a\n");
592 return -1;
593 }
594 return 0;
595}
596
597static
598char *generate_output_filename(const char *filename, const char *ext)
599{
600 char *p = 0;
601 size_t ext_len = strlen(ext);
602
603 if (strcmp(filename, "-") == 0) {
604 p = malloc(ext_len + 6);
605 sprintf(p, "stdin%s", ext);
606 } else {
607 const char *base = aacenc_basename(filename);
608 size_t ilen = strlen(base);
609 const char *ext_org = strrchr(base, '.');
610 if (ext_org) ilen = ext_org - base;
611 p = malloc(ilen + ext_len + 1);
612 sprintf(p, "%.*s%s", ilen, base, ext);
613 }
614 return p;
615}
616
617static
618int parse_raw_spec(const char *spec, pcm_sample_description_t *desc)
619{
620 unsigned bits;
621 unsigned char c_type, c_endian = 'L';
622 int type;
623
624 if (sscanf(spec, "%c%u%c", &c_type, &bits, &c_endian) < 2)
625 return -1;
626 c_type = toupper(c_type);
627 c_endian = toupper(c_endian);
628
629 if (c_type == 'S')
630 type = 1;
631 else if (c_type == 'U')
632 type = 2;
633 else if (c_type == 'F')
634 type = 4;
635 else
636 return -1;
637
638 if (c_endian == 'B')
639 type |= 8;
640 else if (c_endian != 'L')
641 return -1;
642
643 if (c_type == 'F' && bits != 32 && bits != 64)
644 return -1;
645 if (c_type != 'F' && (bits < 8 || bits > 32))
646 return -1;
647
648 desc->sample_type = type;
649 desc->bits_per_channel = bits;
650 return 0;
651}
652
653int main(int argc, char **argv)
654{
655 wav_io_context_t wav_io = { read_callback, seek_callback, tell_callback };
656 m4af_io_callbacks_t
657 m4af_io = { read_callback, write_callback, seek_callback, tell_callback };
658 aacenc_param_ex_t params = { 0 };
659
660 int result = 2;
661 FILE *ifp = 0;
662 FILE *ofp = 0;
663 char *output_filename = 0;
664 wav_reader_t *wavf = 0;
665 HANDLE_AACENCODER encoder = 0;
666 AACENC_InfoStruct aacinfo = { 0 };
667 m4af_ctx_t *m4af = 0;
668 const pcm_sample_description_t *sample_format;
669 int downsampled_timescale = 0;
670 int frame_count = 0;
671 struct stat stb = { 0 };
672
673 setlocale(LC_CTYPE, "");
674 setbuf(stderr, 0);
675
676 if (parse_options(argc, argv, &params) < 0)
677 return 1;
678
679 if ((ifp = aacenc_fopen(params.input_filename, "rb")) == 0) {
680 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.input_filename,
681 strerror(errno));
682 goto END;
683 }
684 if (fstat(fileno(ifp), &stb) == 0 && (stb.st_mode & S_IFMT) != S_IFREG) {
685 wav_io.seek = 0;
686 wav_io.tell = 0;
687 }
688 if (!params.is_raw) {
689 if ((wavf = wav_open(&wav_io, ifp, params.ignore_length)) == 0) {
690 fprintf(stderr, "ERROR: broken / unsupported input file\n");
691 goto END;
692 }
693 } else {
694 int bytes_per_channel;
695 pcm_sample_description_t desc = { 0 };
696 if (parse_raw_spec(params.raw_format, &desc) < 0) {
697 fprintf(stderr, "ERROR: invalid raw-format spec\n");
698 goto END;
699 }
700 desc.sample_rate = params.raw_rate;
701 desc.channels_per_frame = params.raw_channels;
702 bytes_per_channel = (desc.bits_per_channel + 7) / 8;
703 desc.bytes_per_frame = params.raw_channels * bytes_per_channel;
704 if ((wavf = raw_open(&wav_io, ifp, &desc)) == 0) {
705 fprintf(stderr, "ERROR: failed to open raw input\n");
706 goto END;
707 }
708 }
709 sample_format = wav_get_format(wavf);
710
711 if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
712 &aacinfo) < 0)
713 goto END;
714
715 if (!params.output_filename) {
716 const char *ext = params.transport_format ? ".aac" : ".m4a";
717 output_filename = generate_output_filename(params.input_filename, ext);
718 params.output_filename = output_filename;
719 }
720
721 if ((ofp = aacenc_fopen(params.output_filename, "wb+")) == 0) {
722 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename,
723 strerror(errno));
724 goto END;
725 }
726 handle_signals();
727 if (!params.transport_format) {
728 uint32_t scale;
729 unsigned framelen = aacinfo.frameLength;
730 int sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)&params);
731 int sig_mode = aacEncoder_GetParam(encoder, AACENC_SIGNALING_MODE);
732 if (sbr_mode && !sig_mode)
733 downsampled_timescale = 1;
734 scale = sample_format->sample_rate >> downsampled_timescale;
735 if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io, ofp)) < 0)
736 goto END;
737 m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf,
738 aacinfo.confSize);
739 m4af_set_fixed_frame_duration(m4af, 0,
740 framelen >> downsampled_timescale);
741 m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
742 m4af_set_priming_mode(m4af, params.gapless_mode + 1);
743 m4af_begin_write(m4af);
744 }
745 frame_count = encode(wavf, encoder, aacinfo.frameLength, ofp, m4af,
746 !params.silent);
747 if (frame_count < 0)
748 goto END;
749 if (m4af) {
750 uint32_t delay = aacinfo.encoderDelay;
751 int64_t frames_read = wav_get_position(wavf);
752 uint32_t padding = frame_count * aacinfo.frameLength
753 - frames_read - aacinfo.encoderDelay;
754 m4af_set_priming(m4af, 0, delay >> downsampled_timescale,
755 padding >> downsampled_timescale);
756 if (finalize_m4a(m4af, &params, encoder) < 0)
757 goto END;
758 }
759 result = 0;
760END:
761 if (wavf) wav_teardown(&wavf);
762 if (ifp) fclose(ifp);
763 if (m4af) m4af_teardown(&m4af);
764 if (ofp) fclose(ofp);
765 if (encoder) aacEncClose(&encoder);
766 if (output_filename) free(output_filename);
767 if (params.tags.tag_table) free(params.tags.tag_table);
768
769 return result;
770}
This page took 0.027328 seconds and 4 git commands to generate.