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