]> iEval git - fdkaac.git/blame - src/main.c
New upstream version 1.0.0
[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);
b5d0b6b1 292 while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:L:s: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
b5d0b6b1
MG
506static int do_smart_padding(int profile)
507{
508 return profile == 2 || profile == 5 || profile == 29;
509}
510
48e2f01c 511static
4d48b091 512int encode(aacenc_param_ex_t *params, pcm_reader_t *reader,
513 HANDLE_AACENCODER encoder, uint32_t frame_length,
514 m4af_ctx_t *m4af)
48e2f01c 515{
4d48b091 516 int16_t *ibuf = 0, *ip;
d533c8e0 517 aacenc_frame_t obuf[2] = {{ 0 }}, *obp;
4d48b091 518 unsigned flip = 0;
48e2f01c 519 int nread = 1;
48e2f01c 520 int rc = -1;
4d48b091 521 int remaining, consumed;
522 int frames_written = 0, encoded = 0;
48e2f01c 523 aacenc_progress_t progress = { 0 };
2d744bd5 524 const pcm_sample_description_t *fmt = pcm_get_format(reader);
b5d0b6b1 525 const int is_padding = do_smart_padding(params->profile);
48e2f01c 526
2d744bd5 527 ibuf = malloc(frame_length * fmt->bytes_per_frame);
528 aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate);
4d48b091 529
530 for (;;) {
bd3b4b34 531 if (g_interrupted)
532 nread = 0;
4d48b091 533 if (nread > 0) {
2d744bd5 534 if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) {
48e2f01c 535 fprintf(stderr, "ERROR: read failed\n");
536 goto END;
48e2f01c 537 }
4d48b091 538 if (!params->silent)
2d744bd5 539 aacenc_progress_update(&progress, pcm_get_position(reader),
540 fmt->sample_rate * 2);
48e2f01c 541 }
4d48b091 542 ip = ibuf;
543 remaining = nread;
544 do {
545 obp = &obuf[flip];
3b518efd 546 consumed = aac_encode_frame(encoder, fmt, ip, remaining, obp);
4d48b091 547 if (consumed < 0) goto END;
d533c8e0 548 if (consumed == 0 && obp->size == 0) goto DONE;
549 if (obp->size == 0) break;
4d48b091 550
551 remaining -= consumed;
552 ip += consumed * fmt->channels_per_frame;
b5d0b6b1 553 if (is_padding) {
4d48b091 554 /*
555 * As we pad 1 frame at beginning and ending by our extrapolator,
556 * we want to drop them.
557 * We delay output by 1 frame by double buffering, and discard
558 * second frame and final frame from the encoder.
559 * Since sbr_header is included in the first frame (in case of
560 * SBR), we cannot discard first frame. So we pick second instead.
561 */
b5d0b6b1
MG
562 flip ^= 1;
563 ++encoded;
564 if (encoded == 1 || encoded == 3)
565 continue;
566 }
f75c9c7b 567 if (write_sample(params->output_fp, m4af, &obuf[flip]) < 0)
48e2f01c 568 goto END;
569 ++frames_written;
4d48b091 570 } while (remaining > 0);
571 }
572DONE:
b5d0b6b1
MG
573 /*
574 * When interrupted, we haven't pulled out last extrapolated frames
575 * from the reader. Therefore, we have to write the final outcome.
576 */
577 if (g_interrupted) {
578 if (write_sample(params->output_fp, m4af, &obp[flip^1]) < 0)
579 goto END;
580 ++frames_written;
581 }
4d48b091 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;
2d744bd5 705
706 if ((params->input_fp = aacenc_fopen(params->input_filename, "rb")) == 0) {
707 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params->input_filename,
708 strerror(errno));
b54538f7 709 goto FAIL;
2d744bd5 710 }
29a8f73f 711 io.cookie = params->input_fp;
9b7e1ca6 712 if (aacenc_seekable(params->input_fp))
29a8f73f 713 io.vtbl = &pcm_io_vtbl;
714 else
715 io.vtbl = &pcm_io_vtbl_noseek;
716
2d744bd5 717 if (params->is_raw) {
718 int bytes_per_channel;
719 pcm_sample_description_t desc = { 0 };
720 if (parse_raw_spec(params->raw_format, &desc) < 0) {
721 fprintf(stderr, "ERROR: invalid raw-format spec\n");
b54538f7 722 goto FAIL;
2d744bd5 723 }
724 desc.sample_rate = params->raw_rate;
725 desc.channels_per_frame = params->raw_channels;
726 bytes_per_channel = (desc.bits_per_channel + 7) / 8;
727 desc.bytes_per_frame = params->raw_channels * bytes_per_channel;
29a8f73f 728 if ((reader = raw_open(&io, &desc)) == 0) {
2d744bd5 729 fprintf(stderr, "ERROR: failed to open raw input\n");
b54538f7 730 goto FAIL;
2d744bd5 731 }
732 } else {
1af8624b 733 int c;
734 ungetc(c = getc(params->input_fp), params->input_fp);
735
736 switch (c) {
737 case 'R':
738 if ((reader = wav_open(&io, params->ignore_length)) == 0) {
739 fprintf(stderr, "ERROR: broken / unsupported input file\n");
b54538f7 740 goto FAIL;
1af8624b 741 }
742 break;
743 case 'c':
744 params->source_tag_ctx.add = aacenc_add_tag_entry_to_store;
745 params->source_tag_ctx.add_ctx = &params->source_tags;
746 if ((reader = caf_open(&io,
747 aacenc_translate_generic_text_tag,
748 &params->source_tag_ctx)) == 0) {
749 fprintf(stderr, "ERROR: broken / unsupported input file\n");
b54538f7 750 goto FAIL;
1af8624b 751 }
752 break;
753 default:
4d48b091 754 fprintf(stderr, "ERROR: unsupported input file\n");
b54538f7 755 goto FAIL;
2d744bd5 756 }
757 }
b54538f7 758 reader = pcm_open_native_converter(reader);
759 if (reader && PCM_IS_FLOAT(pcm_get_format(reader)))
760 reader = limiter_open(reader);
b5d0b6b1
MG
761 if (reader && (reader = pcm_open_sint16_converter(reader)) != 0) {
762 if (do_smart_padding(params->profile))
763 reader = extrapolater_open(reader);
764 }
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);
9b7e1ca6
MG
806 params.sbr_signaling = 0;
807 if (sbr_mode) {
808 if (params.transport_format == TT_MP4_LOAS || !scale_shift)
809 params.sbr_signaling = 2;
810 if (params.transport_format == TT_MP4_RAW &&
811 aacenc_is_explicit_bw_compatible_sbr_signaling_available())
812 params.sbr_signaling = 1;
813 }
48e2f01c 814 if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
815 &aacinfo) < 0)
816 goto END;
817
818 if (!params.output_filename) {
af8fa38d 819 const char *ext = params.transport_format ? ".aac" : ".m4a";
820 output_filename = generate_output_filename(params.input_filename, ext);
48e2f01c 821 params.output_filename = output_filename;
822 }
823
2d744bd5 824 if ((params.output_fp = aacenc_fopen(params.output_filename, "wb+")) == 0) {
48e2f01c 825 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename,
826 strerror(errno));
827 goto END;
828 }
bd3b4b34 829 handle_signals();
e1adc178 830
48e2f01c 831 if (!params.transport_format) {
832 uint32_t scale;
833 unsigned framelen = aacinfo.frameLength;
e1adc178 834 scale = sample_format->sample_rate >> scale_shift;
2d744bd5 835 if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
836 params.output_fp)) < 0)
48e2f01c 837 goto END;
fcfed4cd 838 m4af_set_num_channels(m4af, 0, sample_format->channels_per_frame);
a7e00a42 839 m4af_set_fixed_frame_duration(m4af, 0, framelen >> scale_shift);
9b7e1ca6
MG
840 if (aacenc_is_explicit_bw_compatible_sbr_signaling_available())
841 m4af_set_decoder_specific_info(m4af, 0,
842 aacinfo.confBuf, aacinfo.confSize);
843 else {
844 uint8_t mp4asc[32];
845 uint32_t ascsize = sizeof(mp4asc);
846 aacenc_mp4asc((aacenc_param_t*)&params, aacinfo.confBuf,
847 aacinfo.confSize, mp4asc, &ascsize);
848 m4af_set_decoder_specific_info(m4af, 0, mp4asc, ascsize);
849 }
2f6fc566 850 m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
d317e29d 851 m4af_set_priming_mode(m4af, params.gapless_mode + 1);
48e2f01c 852 m4af_begin_write(m4af);
853 }
4d48b091 854 frame_count = encode(&params, reader, encoder, aacinfo.frameLength, m4af);
48e2f01c 855 if (frame_count < 0)
856 goto END;
857 if (m4af) {
be234dc4 858 uint32_t padding;
b5d0b6b1
MG
859#if AACENCODER_LIB_VL0 < 4
860 uint32_t delay = aacinfo.encoderDelay;
861 if (sbr_mode && params.profile != AOT_ER_AAC_ELD
862 && !params.include_sbr_delay)
863 delay -= 481 << scale_shift;
864#else
865 uint32_t delay = params.include_sbr_delay ? aacinfo.nDelay
866 : aacinfo.nDelayCore;
867#endif
2d744bd5 868 int64_t frames_read = pcm_get_position(reader);
be234dc4 869
be234dc4 870 padding = frame_count * aacinfo.frameLength - frames_read - delay;
e1adc178 871 m4af_set_priming(m4af, 0, delay >> scale_shift, padding >> scale_shift);
48e2f01c 872 if (finalize_m4a(m4af, &params, encoder) < 0)
873 goto END;
874 }
875 result = 0;
876END:
2d744bd5 877 if (reader) pcm_teardown(&reader);
878 if (params.input_fp) fclose(params.input_fp);
48e2f01c 879 if (m4af) m4af_teardown(&m4af);
2d744bd5 880 if (params.output_fp) fclose(params.output_fp);
48e2f01c 881 if (encoder) aacEncClose(&encoder);
882 if (output_filename) free(output_filename);
1af8624b 883 if (params.tags.tag_table)
884 aacenc_free_tag_store(&params.tags);
885 if (params.source_tags.tag_table)
886 aacenc_free_tag_store(&params.source_tags);
48e2f01c 887
888 return result;
889}
This page took 0.130075 seconds and 4 git commands to generate.