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