fix gcc warnings
[fdkaac.git] / src / main.c
CommitLineData
48e2f01c 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
c5c45908 11#if HAVE_INTTYPES_H
12# include <inttypes.h>
13#elif defined(_MSC_VER)
14# define SCNd64 "I64d"
15#endif
48e2f01c 16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
68543176 19#include <ctype.h>
48e2f01c 20#include <locale.h>
21#include <errno.h>
7222b0b5 22#include <sys/stat.h>
48e2f01c 23#include <getopt.h>
7222b0b5 24#if HAVE_UNISTD_H
25#include <unistd.h>
26#endif
bd3b4b34 27#if HAVE_SIGACTION
28#include <signal.h>
29#endif
7222b0b5 30#ifdef _WIN32
31#include <io.h>
bd3b4b34 32#define WIN32_LEAN_AND_MEAN
33#include <windows.h>
7222b0b5 34#endif
48e2f01c 35#include "compat.h"
36#include "wav_reader.h"
1af8624b 37#include "caf_reader.h"
48e2f01c 38#include "aacenc.h"
39#include "m4af.h"
40#include "progress.h"
41#include "version.h"
cbb23cdb 42#include "metadata.h"
48e2f01c 43
44#define PROGNAME "fdkaac"
45
721d977f 46static volatile int g_interrupted = 0;
bd3b4b34 47
48#if HAVE_SIGACTION
49static void signal_handler(int signum)
50{
51 g_interrupted = 1;
52}
53static void handle_signals(void)
54{
55 int i, sigs[] = { SIGINT, SIGHUP, SIGTERM };
56 for (i = 0; i < sizeof(sigs)/sizeof(sigs[0]); ++i) {
ed646ccf 57 struct sigaction sa;
58 memset(&sa, 0, sizeof sa);
bd3b4b34 59 sa.sa_handler = signal_handler;
60 sa.sa_flags |= SA_RESTART;
61 sigaction(sigs[i], &sa, 0);
62 }
63}
64#elif defined(_WIN32)
65static BOOL WINAPI signal_handler(DWORD type)
66{
67 g_interrupted = 1;
68 return TRUE;
69}
70
71static void handle_signals(void)
72{
73 SetConsoleCtrlHandler(signal_handler, TRUE);
74}
75#else
76static void handle_signals(void)
77{
78}
79#endif
80
48e2f01c 81static
82int read_callback(void *cookie, void *data, uint32_t size)
83{
5e1168a4 84 size_t rc = fread(data, 1, size, (FILE*)cookie);
85 return ferror((FILE*)cookie) ? -1 : (int)rc;
48e2f01c 86}
87
88static
89int write_callback(void *cookie, const void *data, uint32_t size)
90{
5e1168a4 91 size_t rc = fwrite(data, 1, size, (FILE*)cookie);
92 return ferror((FILE*)cookie) ? -1 : (int)rc;
48e2f01c 93}
94
95static
96int seek_callback(void *cookie, int64_t off, int whence)
97{
98 return fseeko((FILE*)cookie, off, whence);
99}
100
101static
102int64_t tell_callback(void *cookie)
103{
104 return ftello((FILE*)cookie);
105}
106
107static
108void usage(void)
109{
110 printf(
111PROGNAME " %s\n"
112"Usage: " PROGNAME " [options] input_file\n"
113"Options:\n"
114" -h, --help Print this help message\n"
115" -p, --profile <n> Profile (audio object type)\n"
116" 2: MPEG-4 AAC LC (default)\n"
117" 5: MPEG-4 HE-AAC (SBR)\n"
118" 29: MPEG-4 HE-AAC v2 (SBR+PS)\n"
119" 23: MPEG-4 AAC LD\n"
120" 39: MPEG-4 AAC ELD\n"
121" 129: MPEG-2 AAC LC\n"
122" 132: MPEG-2 HE-AAC (SBR)\n"
123" 156: MPEG-2 HE-AAC v2 (SBR+PS)\n"
124" -b, --bitrate <n> Bitrate in bits per seconds (for CBR)\n"
125" -m, --bitrate-mode <n> Bitrate configuration\n"
126" 0: CBR (default)\n"
127" 1-5: VBR\n"
128" (VBR mode is not officially supported, and\n"
129" works only on a certain combination of\n"
130" parameter settings, sample rate, and\n"
131" channel configuration)\n"
132" -w, --bandwidth <n> Frequency bandwidth in Hz (AAC LC only)\n"
097ef9a8 133" -a, --afterburner <n> Afterburner\n"
48e2f01c 134" 0: Off\n"
135" 1: On(default)\n"
e1adc178 136" -L, --lowdelay-sbr <-1|0|1> Configure SBR activity on AAC ELD\n"
137" -1: Use ELD SBR auto configurator\n"
138" 0: Disable SBR on ELD (default)\n"
139" 1: Enable SBR on ELD\n"
140" -s, --sbr-ratio <0|1|2> Controls activation of downsampled SBR\n"
141" 0: Use lib default (default)\n"
142" 1: downsampled SBR (default for ELD+SBR)\n"
143" 2: dual-rate SBR (default for HE-AAC)\n"
48e2f01c 144" -f, --transport-format <n> Transport format\n"
145" 0: RAW (default, muxed into M4A)\n"
146" 1: ADIF\n"
147" 2: ADTS\n"
148" 6: LATM MCP=1\n"
149" 7: LATM MCP=0\n"
150" 10: LOAS/LATM (LATM within LOAS)\n"
68543176 151" -C, --adts-crc-check Add CRC protection on ADTS header\n"
48e2f01c 152" -h, --header-period <n> StreamMuxConfig/PCE repetition period in\n"
153" transport layer\n"
154"\n"
155" -o <filename> Output filename\n"
d317e29d 156" -G, --gapless-mode <n> Encoder delay signaling for gapless playback\n"
157" 0: iTunSMPB (default)\n"
158" 1: ISO standard (edts + sgpd)\n"
159" 2: Both\n"
be234dc4 160" --include-sbr-delay Count SBR decoder delay in encoder delay\n"
161" This is not iTunes compatible, but is default\n"
162" behavior of FDK library.\n"
c9ac59e8 163" -I, --ignorelength Ignore length of WAV header\n"
aa2ca1e3 164" -S, --silent Don't print progress messages\n"
fb2b3635 165" --moov-before-mdat Place moov box before mdat box on m4a output\n"
48e2f01c 166"\n"
68543176 167"Options for raw (headerless) input:\n"
168" -R, --raw Treat input as raw (by default WAV is\n"
169" assumed)\n"
170" --raw-channels <n> Number of channels (default: 2)\n"
171" --raw-rate <n> Sample rate (default: 44100)\n"
172" --raw-format <spec> Sample format, default is \"S16L\".\n"
173" Spec is as follows:\n"
174" 1st char: S(igned)|U(nsigned)|F(loat)\n"
175" 2nd part: bits per channel\n"
176" Last char: L(ittle)|B(ig)\n"
177" Last char can be omitted, in which case L is\n"
178" assumed. Spec is case insensitive, therefore\n"
179" \"u16b\" is same as \"U16B\".\n"
180"\n"
48e2f01c 181"Tagging options:\n"
182" --title <string>\n"
183" --artist <string>\n"
184" --album <string>\n"
185" --genre <string>\n"
186" --date <string>\n"
187" --composer <string>\n"
188" --grouping <string>\n"
189" --comment <string>\n"
190" --album-artist <string>\n"
191" --track <number[/total]>\n"
192" --disk <number[/total]>\n"
193" --tempo <n>\n"
c5c45908 194" --tag <fcc>:<value> Set iTunes predefined tag with four char code.\n"
a56831da 195" --tag-from-file <fcc>:<filename>\n"
196" Same as above, but value is read from file.\n"
c5c45908 197" --long-tag <name>:<value> Set arbitrary tag as iTunes custom metadata.\n"
cbb23cdb 198" --tag-from-json <filename[?dot_notation]>\n"
199" Read tags from JSON. By default, tags are\n"
200" assumed to be direct children of the root\n"
201" object(dictionary).\n"
202" Optionally, position of the dictionary\n"
203" that contains tags can be specified with\n"
204" dotted notation.\n"
205" Example:\n"
206" --tag-from-json /path/to/json?format.tags\n"
48e2f01c 207 , fdkaac_version);
208}
209
48e2f01c 210typedef struct aacenc_param_ex_t {
211 AACENC_PARAMS
212
213 char *input_filename;
2d744bd5 214 FILE *input_fp;
48e2f01c 215 char *output_filename;
2d744bd5 216 FILE *output_fp;
d317e29d 217 unsigned gapless_mode;
be234dc4 218 unsigned include_sbr_delay;
48e2f01c 219 unsigned ignore_length;
aa2ca1e3 220 int silent;
fb2b3635 221 int moov_before_mdat;
48e2f01c 222
68543176 223 int is_raw;
224 unsigned raw_channels;
225 unsigned raw_rate;
226 const char *raw_format;
227
3b666b75 228 aacenc_tag_store_t tags;
1af8624b 229 aacenc_tag_store_t source_tags;
230 aacenc_translate_generic_text_tag_ctx_t source_tag_ctx;
48e2f01c 231
cbb23cdb 232 char *json_filename;
233} aacenc_param_ex_t;
c5c45908 234
48e2f01c 235static
236int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
237{
238 int ch;
e1adc178 239 int n;
48e2f01c 240
be234dc4 241#define OPT_INCLUDE_SBR_DELAY M4AF_FOURCC('s','d','l','y')
fb2b3635 242#define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v')
a56831da 243#define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n')
244#define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t')
245#define OPT_RAW_FORMAT M4AF_FOURCC('r','f','m','t')
246#define OPT_SHORT_TAG M4AF_FOURCC('s','t','a','g')
247#define OPT_SHORT_TAG_FILE M4AF_FOURCC('s','t','g','f')
248#define OPT_LONG_TAG M4AF_FOURCC('l','t','a','g')
cbb23cdb 249#define OPT_TAG_FROM_JSON M4AF_FOURCC('t','f','j','s')
68543176 250
48e2f01c 251 static struct option long_options[] = {
252 { "help", no_argument, 0, 'h' },
253 { "profile", required_argument, 0, 'p' },
254 { "bitrate", required_argument, 0, 'b' },
34b319e0 255 { "bitrate-mode", required_argument, 0, 'm' },
48e2f01c 256 { "bandwidth", required_argument, 0, 'w' },
257 { "afterburner", required_argument, 0, 'a' },
e1adc178 258 { "lowdelay-sbr", required_argument, 0, 'L' },
259 { "sbr-ratio", required_argument, 0, 's' },
48e2f01c 260 { "transport-format", required_argument, 0, 'f' },
68543176 261 { "adts-crc-check", no_argument, 0, 'C' },
48e2f01c 262 { "header-period", required_argument, 0, 'P' },
263
d317e29d 264 { "gapless-mode", required_argument, 0, 'G' },
be234dc4 265 { "include-sbr-delay", no_argument, 0, OPT_INCLUDE_SBR_DELAY },
5c534696 266 { "ignorelength", no_argument, 0, 'I' },
aa2ca1e3 267 { "silent", no_argument, 0, 'S' },
fb2b3635 268 { "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT },
48e2f01c 269
68543176 270 { "raw", no_argument, 0, 'R' },
271 { "raw-channels", required_argument, 0, OPT_RAW_CHANNELS },
272 { "raw-rate", required_argument, 0, OPT_RAW_RATE },
273 { "raw-format", required_argument, 0, OPT_RAW_FORMAT },
274
275 { "title", required_argument, 0, M4AF_TAG_TITLE },
276 { "artist", required_argument, 0, M4AF_TAG_ARTIST },
277 { "album", required_argument, 0, M4AF_TAG_ALBUM },
278 { "genre", required_argument, 0, M4AF_TAG_GENRE },
279 { "date", required_argument, 0, M4AF_TAG_DATE },
280 { "composer", required_argument, 0, M4AF_TAG_COMPOSER },
281 { "grouping", required_argument, 0, M4AF_TAG_GROUPING },
282 { "comment", required_argument, 0, M4AF_TAG_COMMENT },
283 { "album-artist", required_argument, 0, M4AF_TAG_ALBUM_ARTIST },
284 { "track", required_argument, 0, M4AF_TAG_TRACK },
285 { "disk", required_argument, 0, M4AF_TAG_DISK },
286 { "tempo", required_argument, 0, M4AF_TAG_TEMPO },
c5c45908 287 { "tag", required_argument, 0, OPT_SHORT_TAG },
a56831da 288 { "tag-from-file", required_argument, 0, OPT_SHORT_TAG_FILE },
c5c45908 289 { "long-tag", required_argument, 0, OPT_LONG_TAG },
cbb23cdb 290 { "tag-from-json", required_argument, 0, OPT_TAG_FROM_JSON },
5c534696 291 { 0, 0, 0, 0 },
48e2f01c 292 };
293 params->afterburner = 1;
294
295 aacenc_getmainargs(&argc, &argv);
d317e29d 296 while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:Ls:f:CP:G:Io:SR",
48e2f01c 297 long_options, 0)) != EOF) {
298 switch (ch) {
299 case 'h':
300 return usage(), -1;
301 case 'p':
302 if (sscanf(optarg, "%u", &n) != 1) {
303 fprintf(stderr, "invalid arg for profile\n");
304 return -1;
305 }
306 params->profile = n;
307 break;
308 case 'b':
309 if (sscanf(optarg, "%u", &n) != 1) {
310 fprintf(stderr, "invalid arg for bitrate\n");
311 return -1;
312 }
313 params->bitrate = n;
314 break;
315 case 'm':
316 if (sscanf(optarg, "%u", &n) != 1 || n > 5) {
317 fprintf(stderr, "invalid arg for bitrate-mode\n");
318 return -1;
319 }
320 params->bitrate_mode = n;
321 break;
322 case 'w':
323 if (sscanf(optarg, "%u", &n) != 1) {
324 fprintf(stderr, "invalid arg for bandwidth\n");
325 return -1;
326 }
327 params->bandwidth = n;
328 break;
329 case 'a':
330 if (sscanf(optarg, "%u", &n) != 1 || n > 1) {
331 fprintf(stderr, "invalid arg for afterburner\n");
332 return -1;
333 }
334 params->afterburner = n;
335 break;
336 case 'L':
e1adc178 337 if (sscanf(optarg, "%d", &n) != 1 || n < -1 || n > 1) {
338 fprintf(stderr, "invalid arg for lowdelay-sbr\n");
339 return -1;
340 }
341 params->lowdelay_sbr = n;
342 break;
343 case 's':
344 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
345 fprintf(stderr, "invalid arg for sbr-ratio\n");
346 return -1;
347 }
348 params->sbr_ratio = n;
48e2f01c 349 break;
48e2f01c 350 case 'f':
351 if (sscanf(optarg, "%u", &n) != 1) {
352 fprintf(stderr, "invalid arg for transport-format\n");
353 return -1;
354 }
355 params->transport_format = n;
356 break;
229c3ead 357 case 'C':
48e2f01c 358 params->adts_crc_check = 1;
359 break;
360 case 'P':
361 if (sscanf(optarg, "%u", &n) != 1) {
362 fprintf(stderr, "invalid arg for header-period\n");
363 return -1;
364 }
365 params->header_period = n;
366 break;
367 case 'o':
368 params->output_filename = optarg;
369 break;
d317e29d 370 case 'G':
371 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
372 fprintf(stderr, "invalid arg for gapless-mode\n");
373 return -1;
374 }
375 params->gapless_mode = n;
376 break;
be234dc4 377 case OPT_INCLUDE_SBR_DELAY:
378 params->include_sbr_delay = 1;
379 break;
48e2f01c 380 case 'I':
381 params->ignore_length = 1;
382 break;
aa2ca1e3 383 case 'S':
384 params->silent = 1;
385 break;
fb2b3635 386 case OPT_MOOV_BEFORE_MDAT:
387 params->moov_before_mdat = 1;
388 break;
68543176 389 case 'R':
390 params->is_raw = 1;
391 break;
392 case OPT_RAW_CHANNELS:
393 if (sscanf(optarg, "%u", &n) != 1) {
394 fprintf(stderr, "invalid arg for raw-channels\n");
395 return -1;
396 }
397 params->raw_channels = n;
398 break;
399 case OPT_RAW_RATE:
400 if (sscanf(optarg, "%u", &n) != 1) {
401 fprintf(stderr, "invalid arg for raw-rate\n");
402 return -1;
403 }
404 params->raw_rate = n;
405 break;
406 case OPT_RAW_FORMAT:
407 params->raw_format = optarg;
408 break;
48e2f01c 409 case M4AF_TAG_TITLE:
410 case M4AF_TAG_ARTIST:
411 case M4AF_TAG_ALBUM:
412 case M4AF_TAG_GENRE:
413 case M4AF_TAG_DATE:
414 case M4AF_TAG_COMPOSER:
415 case M4AF_TAG_GROUPING:
416 case M4AF_TAG_COMMENT:
417 case M4AF_TAG_ALBUM_ARTIST:
418 case M4AF_TAG_TRACK:
419 case M4AF_TAG_DISK:
420 case M4AF_TAG_TEMPO:
3b666b75 421 aacenc_add_tag_to_store(&params->tags, ch, 0, optarg,
422 strlen(optarg), 0);
c5c45908 423 break;
424 case OPT_SHORT_TAG:
a56831da 425 case OPT_SHORT_TAG_FILE:
c5c45908 426 case OPT_LONG_TAG:
427 {
428 char *val;
429 size_t klen;
430 unsigned fcc = M4AF_FOURCC('-','-','-','-');
431
432 if ((val = strchr(optarg, ':')) == 0) {
433 fprintf(stderr, "invalid arg for tag\n");
434 return -1;
435 }
436 *val++ = '\0';
a56831da 437 if (ch == OPT_SHORT_TAG || ch == OPT_SHORT_TAG_FILE) {
360cf7dc 438 /*
439 * take care of U+00A9(COPYRIGHT SIGN).
440 * 1) if length of fcc is 3, we prepend '\xa9'.
441 * 2) U+00A9 becomes "\xc2\xa9" in UTF-8. Therefore
442 * we remove first '\xc2'.
443 */
444 if (optarg[0] == '\xc2')
445 ++optarg;
c5c45908 446 if ((klen = strlen(optarg))== 3)
447 fcc = 0xa9;
448 else if (klen != 4) {
449 fprintf(stderr, "invalid arg for tag\n");
450 return -1;
451 }
452 for (; *optarg; ++optarg)
453 fcc = ((fcc << 8) | (*optarg & 0xff));
454 }
3b666b75 455 aacenc_add_tag_to_store(&params->tags, fcc, optarg,
456 val, strlen(val),
457 ch == OPT_SHORT_TAG_FILE);
48e2f01c 458 }
48e2f01c 459 break;
cbb23cdb 460 case OPT_TAG_FROM_JSON:
461 params->json_filename = optarg;
462 break;
48e2f01c 463 default:
464 return usage(), -1;
465 }
466 }
467 if (argc == optind)
468 return usage(), -1;
68543176 469
48e2f01c 470 if (!params->bitrate && !params->bitrate_mode) {
471 fprintf(stderr, "bitrate or bitrate-mode is mandatory\n");
472 return -1;
473 }
474 if (params->output_filename && !strcmp(params->output_filename, "-") &&
475 !params->transport_format) {
476 fprintf(stderr, "stdout streaming is not available on M4A output\n");
477 return -1;
478 }
479 if (params->bitrate && params->bitrate < 10000)
480 params->bitrate *= 1000;
68543176 481
482 if (params->is_raw) {
483 if (!params->raw_channels)
484 params->raw_channels = 2;
485 if (!params->raw_rate)
486 params->raw_rate = 44100;
487 if (!params->raw_format)
488 params->raw_format = "S16L";
489 }
48e2f01c 490 params->input_filename = argv[optind];
491 return 0;
492};
493
494static
d533c8e0 495int write_sample(FILE *ofp, m4af_ctx_t *m4af, aacenc_frame_t *frame)
48e2f01c 496{
497 if (!m4af) {
d533c8e0 498 fwrite(frame->data, 1, frame->size, ofp);
5e1168a4 499 if (ferror(ofp)) {
48e2f01c 500 fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno));
501 return -1;
502 }
d533c8e0 503 } else if (m4af_write_sample(m4af, 0, frame->data, frame->size, 0) < 0) {
48e2f01c 504 fprintf(stderr, "ERROR: failed to write m4a sample\n");
505 return -1;
506 }
507 return 0;
508}
509
510static
4d48b091 511int encode(aacenc_param_ex_t *params, pcm_reader_t *reader,
512 HANDLE_AACENCODER encoder, uint32_t frame_length,
513 m4af_ctx_t *m4af)
48e2f01c 514{
4d48b091 515 int16_t *ibuf = 0, *ip;
d533c8e0 516 aacenc_frame_t obuf[2] = {{ 0 }}, *obp;
4d48b091 517 unsigned flip = 0;
48e2f01c 518 int nread = 1;
48e2f01c 519 int rc = -1;
4d48b091 520 int remaining, consumed;
521 int frames_written = 0, encoded = 0;
48e2f01c 522 aacenc_progress_t progress = { 0 };
2d744bd5 523 const pcm_sample_description_t *fmt = pcm_get_format(reader);
48e2f01c 524
2d744bd5 525 ibuf = malloc(frame_length * fmt->bytes_per_frame);
526 aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate);
4d48b091 527
528 for (;;) {
529 /*
530 * Since we delay the write, we cannot just exit loop when interrupted.
531 * Instead, we regard it as EOF.
532 */
bd3b4b34 533 if (g_interrupted)
534 nread = 0;
4d48b091 535 if (nread > 0) {
2d744bd5 536 if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) {
48e2f01c 537 fprintf(stderr, "ERROR: read failed\n");
538 goto END;
48e2f01c 539 }
4d48b091 540 if (!params->silent)
2d744bd5 541 aacenc_progress_update(&progress, pcm_get_position(reader),
542 fmt->sample_rate * 2);
48e2f01c 543 }
4d48b091 544 ip = ibuf;
545 remaining = nread;
546 do {
547 obp = &obuf[flip];
3b518efd 548 consumed = aac_encode_frame(encoder, fmt, ip, remaining, obp);
4d48b091 549 if (consumed < 0) goto END;
d533c8e0 550 if (consumed == 0 && obp->size == 0) goto DONE;
551 if (obp->size == 0) break;
4d48b091 552
553 remaining -= consumed;
554 ip += consumed * fmt->channels_per_frame;
555 flip ^= 1;
556 /*
557 * As we pad 1 frame at beginning and ending by our extrapolator,
558 * we want to drop them.
559 * We delay output by 1 frame by double buffering, and discard
560 * second frame and final frame from the encoder.
561 * Since sbr_header is included in the first frame (in case of
562 * SBR), we cannot discard first frame. So we pick second instead.
563 */
564 ++encoded;
565 if (encoded == 1 || encoded == 3)
566 continue;
567 obp = &obuf[flip];
d533c8e0 568 if (write_sample(params->output_fp, m4af, obp) < 0)
48e2f01c 569 goto END;
570 ++frames_written;
4d48b091 571 } while (remaining > 0);
572 }
573DONE:
574 if (!params->silent)
2d744bd5 575 aacenc_progress_finish(&progress, pcm_get_position(reader));
48e2f01c 576 rc = frames_written;
577END:
578 if (ibuf) free(ibuf);
4d48b091 579 if (obuf[0].data) free(obuf[0].data);
580 if (obuf[1].data) free(obuf[1].data);
48e2f01c 581 return rc;
582}
583
c5c45908 584static
e4bbeeb0 585void put_tool_tag(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
c5c45908 586 HANDLE_AACENCODER encoder)
587{
588 char tool_info[256];
589 char *p = tool_info;
e1adc178 590 LIB_INFO lib_info;
c5c45908 591
592 p += sprintf(p, PROGNAME " %s, ", fdkaac_version);
e1adc178 593 aacenc_get_lib_info(&lib_info);
594 p += sprintf(p, "libfdk-aac %s, ", lib_info.versionStr);
c5c45908 595 if (params->bitrate_mode)
596 sprintf(p, "VBR mode %d", params->bitrate_mode);
597 else
598 sprintf(p, "CBR %dkbps",
599 aacEncoder_GetParam(encoder, AACENC_BITRATE) / 1000);
600
601 m4af_add_itmf_string_tag(m4af, M4AF_TAG_TOOL, tool_info);
602}
603
48e2f01c 604static
e4bbeeb0 605int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
48e2f01c 606 HANDLE_AACENCODER encoder)
607{
608 unsigned i;
1af8624b 609 aacenc_tag_entry_t *tag;
610
611 tag = params->source_tags.tag_table;
612 for (i = 0; i < params->source_tags.tag_count; ++i, ++tag)
613 aacenc_write_tag_entry(m4af, tag);
cbb23cdb 614
615 if (params->json_filename)
3b666b75 616 aacenc_write_tags_from_json(m4af, params->json_filename);
cbb23cdb 617
1af8624b 618 tag = params->tags.tag_table;
cbb23cdb 619 for (i = 0; i < params->tags.tag_count; ++i, ++tag)
3b666b75 620 aacenc_write_tag_entry(m4af, tag);
c5c45908 621
622 put_tool_tag(m4af, params, encoder);
48e2f01c 623
fb2b3635 624 if (m4af_finalize(m4af, params->moov_before_mdat) < 0) {
48e2f01c 625 fprintf(stderr, "ERROR: failed to finalize m4a\n");
626 return -1;
627 }
628 return 0;
629}
630
af8fa38d 631static
632char *generate_output_filename(const char *filename, const char *ext)
633{
634 char *p = 0;
635 size_t ext_len = strlen(ext);
636
637 if (strcmp(filename, "-") == 0) {
638 p = malloc(ext_len + 6);
639 sprintf(p, "stdin%s", ext);
640 } else {
5888fddc 641 const char *base = aacenc_basename(filename);
af8fa38d 642 size_t ilen = strlen(base);
643 const char *ext_org = strrchr(base, '.');
644 if (ext_org) ilen = ext_org - base;
645 p = malloc(ilen + ext_len + 1);
6709cf69 646 sprintf(p, "%.*s%s", (int)ilen, base, ext);
af8fa38d 647 }
648 return p;
649}
650
68543176 651static
652int parse_raw_spec(const char *spec, pcm_sample_description_t *desc)
653{
654 unsigned bits;
655 unsigned char c_type, c_endian = 'L';
656 int type;
657
658 if (sscanf(spec, "%c%u%c", &c_type, &bits, &c_endian) < 2)
659 return -1;
660 c_type = toupper(c_type);
661 c_endian = toupper(c_endian);
662
663 if (c_type == 'S')
664 type = 1;
665 else if (c_type == 'U')
666 type = 2;
667 else if (c_type == 'F')
668 type = 4;
669 else
670 return -1;
671
672 if (c_endian == 'B')
673 type |= 8;
674 else if (c_endian != 'L')
675 return -1;
676
677 if (c_type == 'F' && bits != 32 && bits != 64)
678 return -1;
679 if (c_type != 'F' && (bits < 8 || bits > 32))
680 return -1;
681
682 desc->sample_type = type;
683 desc->bits_per_channel = bits;
684 return 0;
685}
686
29a8f73f 687static pcm_io_vtbl_t pcm_io_vtbl = {
688 read_callback, seek_callback, tell_callback
689};
3de0e22d 690static pcm_io_vtbl_t pcm_io_vtbl_noseek = { read_callback, 0, tell_callback };
29a8f73f 691
2d744bd5 692static
693pcm_reader_t *open_input(aacenc_param_ex_t *params)
694{
29a8f73f 695 pcm_io_context_t io = { 0 };
2d744bd5 696 pcm_reader_t *reader = 0;
697 struct stat stb = { 0 };
698
699 if ((params->input_fp = aacenc_fopen(params->input_filename, "rb")) == 0) {
700 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params->input_filename,
701 strerror(errno));
702 goto END;
703 }
29a8f73f 704 io.cookie = params->input_fp;
f48bf129 705 if (fstat(fileno(params->input_fp), &stb) == 0
29a8f73f 706 && (stb.st_mode & S_IFMT) == S_IFREG)
707 io.vtbl = &pcm_io_vtbl;
708 else
709 io.vtbl = &pcm_io_vtbl_noseek;
710
2d744bd5 711 if (params->is_raw) {
712 int bytes_per_channel;
713 pcm_sample_description_t desc = { 0 };
714 if (parse_raw_spec(params->raw_format, &desc) < 0) {
715 fprintf(stderr, "ERROR: invalid raw-format spec\n");
716 goto END;
717 }
718 desc.sample_rate = params->raw_rate;
719 desc.channels_per_frame = params->raw_channels;
720 bytes_per_channel = (desc.bits_per_channel + 7) / 8;
721 desc.bytes_per_frame = params->raw_channels * bytes_per_channel;
29a8f73f 722 if ((reader = raw_open(&io, &desc)) == 0) {
2d744bd5 723 fprintf(stderr, "ERROR: failed to open raw input\n");
724 goto END;
725 }
726 } else {
1af8624b 727 int c;
728 ungetc(c = getc(params->input_fp), params->input_fp);
729
730 switch (c) {
731 case 'R':
732 if ((reader = wav_open(&io, params->ignore_length)) == 0) {
733 fprintf(stderr, "ERROR: broken / unsupported input file\n");
734 goto END;
735 }
736 break;
737 case 'c':
738 params->source_tag_ctx.add = aacenc_add_tag_entry_to_store;
739 params->source_tag_ctx.add_ctx = &params->source_tags;
740 if ((reader = caf_open(&io,
741 aacenc_translate_generic_text_tag,
742 &params->source_tag_ctx)) == 0) {
743 fprintf(stderr, "ERROR: broken / unsupported input file\n");
744 goto END;
745 }
746 break;
747 default:
4d48b091 748 fprintf(stderr, "ERROR: unsupported input file\n");
2d744bd5 749 goto END;
750 }
751 }
4d48b091 752 if ((reader = pcm_open_sint16_converter(reader)) != 0)
753 reader = extrapolater_open(reader);
754 return reader;
2d744bd5 755END:
e8e9f79e 756 return 0;
2d744bd5 757}
758
48e2f01c 759int main(int argc, char **argv)
760{
2d744bd5 761 static m4af_io_callbacks_t m4af_io = {
762 read_callback, write_callback, seek_callback, tell_callback
763 };
48e2f01c 764 aacenc_param_ex_t params = { 0 };
765
766 int result = 2;
48e2f01c 767 char *output_filename = 0;
2d744bd5 768 pcm_reader_t *reader = 0;
48e2f01c 769 HANDLE_AACENCODER encoder = 0;
770 AACENC_InfoStruct aacinfo = { 0 };
e4bbeeb0 771 m4af_ctx_t *m4af = 0;
48e2f01c 772 const pcm_sample_description_t *sample_format;
48e2f01c 773 int frame_count = 0;
9b8f9915 774 int sbr_mode = 0;
e1adc178 775 unsigned scale_shift = 0;
48e2f01c 776
777 setlocale(LC_CTYPE, "");
778 setbuf(stderr, 0);
779
780 if (parse_options(argc, argv, &params) < 0)
781 return 1;
782
2d744bd5 783 if ((reader = open_input(&params)) == 0)
48e2f01c 784 goto END;
2d744bd5 785
786 sample_format = pcm_get_format(reader);
48e2f01c 787
9b8f9915 788 /*
789 * We use explicit/hierarchical signaling for LOAS.
790 * Other than that, we request implicit signaling to FDK library, then
791 * append explicit/backward-compatible signaling to ASC in case of MP4FF.
792 *
793 * Explicit/backward-compatible signaling of SBR is the most recommended
794 * way in MPEG4 part3 spec, and seems the only way supported by iTunes.
795 * Since FDK library does not support it, we have to do it on our side.
796 */
e1adc178 797 sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)&params);
798 if (sbr_mode && !aacenc_is_sbr_ratio_available()) {
799 fprintf(stderr, "WARNING: Only dual-rate SBR is available "
800 "for this version\n");
801 params.sbr_ratio = 2;
802 }
803 scale_shift = aacenc_is_dual_rate_sbr((aacenc_param_t*)&params);
9b8f9915 804 params.sbr_signaling = (params.transport_format == TT_MP4_LOAS) ? 2 : 0;
e1adc178 805 if (sbr_mode && !scale_shift)
806 params.sbr_signaling = 2;
9b8f9915 807
48e2f01c 808 if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
809 &aacinfo) < 0)
810 goto END;
811
812 if (!params.output_filename) {
af8fa38d 813 const char *ext = params.transport_format ? ".aac" : ".m4a";
814 output_filename = generate_output_filename(params.input_filename, ext);
48e2f01c 815 params.output_filename = output_filename;
816 }
817
2d744bd5 818 if ((params.output_fp = aacenc_fopen(params.output_filename, "wb+")) == 0) {
48e2f01c 819 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename,
820 strerror(errno));
821 goto END;
822 }
bd3b4b34 823 handle_signals();
e1adc178 824
48e2f01c 825 if (!params.transport_format) {
826 uint32_t scale;
9b8f9915 827 uint8_t mp4asc[32];
828 uint32_t ascsize = sizeof(mp4asc);
48e2f01c 829 unsigned framelen = aacinfo.frameLength;
e1adc178 830 scale = sample_format->sample_rate >> scale_shift;
2d744bd5 831 if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
832 params.output_fp)) < 0)
48e2f01c 833 goto END;
9b8f9915 834 aacenc_mp4asc((aacenc_param_t*)&params, aacinfo.confBuf,
835 aacinfo.confSize, mp4asc, &ascsize);
836 m4af_set_decoder_specific_info(m4af, 0, mp4asc, ascsize);
48e2f01c 837 m4af_set_fixed_frame_duration(m4af, 0,
e1adc178 838 framelen >> scale_shift);
2f6fc566 839 m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
d317e29d 840 m4af_set_priming_mode(m4af, params.gapless_mode + 1);
48e2f01c 841 m4af_begin_write(m4af);
842 }
e1adc178 843 if (scale_shift && (aacinfo.encoderDelay & 1)) {
c5eec155 844 /*
845 * Since odd delay cannot be exactly expressed in downsampled scale,
846 * we push one zero frame to the encoder here, to make delay even
847 */
848 int16_t zero[8] = { 0 };
d533c8e0 849 aacenc_frame_t frame = { 0 };
850 aac_encode_frame(encoder, sample_format, zero, 1, &frame);
851 free(frame.data);
c5eec155 852 }
4d48b091 853 frame_count = encode(&params, reader, encoder, aacinfo.frameLength, m4af);
48e2f01c 854 if (frame_count < 0)
855 goto END;
856 if (m4af) {
857 uint32_t delay = aacinfo.encoderDelay;
be234dc4 858 uint32_t padding;
2d744bd5 859 int64_t frames_read = pcm_get_position(reader);
be234dc4 860
861 if (sbr_mode && params.profile != AOT_ER_AAC_ELD &&
862 !params.include_sbr_delay)
e1adc178 863 delay -= 481 << scale_shift;
864 if (scale_shift && (delay & 1))
be234dc4 865 ++delay;
866 padding = frame_count * aacinfo.frameLength - frames_read - delay;
e1adc178 867 m4af_set_priming(m4af, 0, delay >> scale_shift, padding >> scale_shift);
48e2f01c 868 if (finalize_m4a(m4af, &params, encoder) < 0)
869 goto END;
870 }
871 result = 0;
872END:
2d744bd5 873 if (reader) pcm_teardown(&reader);
874 if (params.input_fp) fclose(params.input_fp);
48e2f01c 875 if (m4af) m4af_teardown(&m4af);
2d744bd5 876 if (params.output_fp) fclose(params.output_fp);
48e2f01c 877 if (encoder) aacEncClose(&encoder);
878 if (output_filename) free(output_filename);
1af8624b 879 if (params.tags.tag_table)
880 aacenc_free_tag_store(&params.tags);
881 if (params.source_tags.tag_table)
882 aacenc_free_tag_store(&params.source_tags);
48e2f01c 883
884 return result;
885}
This page took 0.0708 seconds and 4 git commands to generate.