caf input support
[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) {
57 struct sigaction sa = { 0 };
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"
135" -L, --lowdelay-sbr Enable ELD-SBR (AAC ELD only)\n"
136" -s, --sbr-signaling <n> SBR signaling mode\n"
137" 0: Implicit, backward compatible(default)\n"
138" 1: Explicit SBR and implicit PS\n"
139" 2: Explicit hierarchical signaling\n"
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"
5c534696 156" --ignorelength Ignore length of WAV header\n"
aa2ca1e3 157" -S, --silent Don't print progress messages\n"
fb2b3635 158" --moov-before-mdat Place moov box before mdat box on m4a output\n"
48e2f01c 159"\n"
68543176 160"Options for raw (headerless) input:\n"
161" -R, --raw Treat input as raw (by default WAV is\n"
162" assumed)\n"
163" --raw-channels <n> Number of channels (default: 2)\n"
164" --raw-rate <n> Sample rate (default: 44100)\n"
165" --raw-format <spec> Sample format, default is \"S16L\".\n"
166" Spec is as follows:\n"
167" 1st char: S(igned)|U(nsigned)|F(loat)\n"
168" 2nd part: bits per channel\n"
169" Last char: L(ittle)|B(ig)\n"
170" Last char can be omitted, in which case L is\n"
171" assumed. Spec is case insensitive, therefore\n"
172" \"u16b\" is same as \"U16B\".\n"
173"\n"
48e2f01c 174"Tagging options:\n"
175" --title <string>\n"
176" --artist <string>\n"
177" --album <string>\n"
178" --genre <string>\n"
179" --date <string>\n"
180" --composer <string>\n"
181" --grouping <string>\n"
182" --comment <string>\n"
183" --album-artist <string>\n"
184" --track <number[/total]>\n"
185" --disk <number[/total]>\n"
186" --tempo <n>\n"
c5c45908 187" --tag <fcc>:<value> Set iTunes predefined tag with four char code.\n"
a56831da 188" --tag-from-file <fcc>:<filename>\n"
189" Same as above, but value is read from file.\n"
c5c45908 190" --long-tag <name>:<value> Set arbitrary tag as iTunes custom metadata.\n"
cbb23cdb 191" --tag-from-json <filename[?dot_notation]>\n"
192" Read tags from JSON. By default, tags are\n"
193" assumed to be direct children of the root\n"
194" object(dictionary).\n"
195" Optionally, position of the dictionary\n"
196" that contains tags can be specified with\n"
197" dotted notation.\n"
198" Example:\n"
199" --tag-from-json /path/to/json?format.tags\n"
48e2f01c 200 , fdkaac_version);
201}
202
48e2f01c 203typedef struct aacenc_param_ex_t {
204 AACENC_PARAMS
205
206 char *input_filename;
2d744bd5 207 FILE *input_fp;
48e2f01c 208 char *output_filename;
2d744bd5 209 FILE *output_fp;
d317e29d 210 unsigned gapless_mode;
48e2f01c 211 unsigned ignore_length;
aa2ca1e3 212 int silent;
fb2b3635 213 int moov_before_mdat;
48e2f01c 214
68543176 215 int is_raw;
216 unsigned raw_channels;
217 unsigned raw_rate;
218 const char *raw_format;
219
3b666b75 220 aacenc_tag_store_t tags;
1af8624b 221 aacenc_tag_store_t source_tags;
222 aacenc_translate_generic_text_tag_ctx_t source_tag_ctx;
48e2f01c 223
cbb23cdb 224 char *json_filename;
225} aacenc_param_ex_t;
c5c45908 226
48e2f01c 227static
228int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
229{
230 int ch;
231 unsigned n;
48e2f01c 232
fb2b3635 233#define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v')
a56831da 234#define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n')
235#define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t')
236#define OPT_RAW_FORMAT M4AF_FOURCC('r','f','m','t')
237#define OPT_SHORT_TAG M4AF_FOURCC('s','t','a','g')
238#define OPT_SHORT_TAG_FILE M4AF_FOURCC('s','t','g','f')
239#define OPT_LONG_TAG M4AF_FOURCC('l','t','a','g')
cbb23cdb 240#define OPT_TAG_FROM_JSON M4AF_FOURCC('t','f','j','s')
68543176 241
48e2f01c 242 static struct option long_options[] = {
243 { "help", no_argument, 0, 'h' },
244 { "profile", required_argument, 0, 'p' },
245 { "bitrate", required_argument, 0, 'b' },
34b319e0 246 { "bitrate-mode", required_argument, 0, 'm' },
48e2f01c 247 { "bandwidth", required_argument, 0, 'w' },
248 { "afterburner", required_argument, 0, 'a' },
249 { "lowdelay-sbr", no_argument, 0, 'L' },
250 { "sbr-signaling", required_argument, 0, 's' },
251 { "transport-format", required_argument, 0, 'f' },
68543176 252 { "adts-crc-check", no_argument, 0, 'C' },
48e2f01c 253 { "header-period", required_argument, 0, 'P' },
254
d317e29d 255 { "gapless-mode", required_argument, 0, 'G' },
5c534696 256 { "ignorelength", no_argument, 0, 'I' },
aa2ca1e3 257 { "silent", no_argument, 0, 'S' },
fb2b3635 258 { "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT },
48e2f01c 259
68543176 260 { "raw", no_argument, 0, 'R' },
261 { "raw-channels", required_argument, 0, OPT_RAW_CHANNELS },
262 { "raw-rate", required_argument, 0, OPT_RAW_RATE },
263 { "raw-format", required_argument, 0, OPT_RAW_FORMAT },
264
265 { "title", required_argument, 0, M4AF_TAG_TITLE },
266 { "artist", required_argument, 0, M4AF_TAG_ARTIST },
267 { "album", required_argument, 0, M4AF_TAG_ALBUM },
268 { "genre", required_argument, 0, M4AF_TAG_GENRE },
269 { "date", required_argument, 0, M4AF_TAG_DATE },
270 { "composer", required_argument, 0, M4AF_TAG_COMPOSER },
271 { "grouping", required_argument, 0, M4AF_TAG_GROUPING },
272 { "comment", required_argument, 0, M4AF_TAG_COMMENT },
273 { "album-artist", required_argument, 0, M4AF_TAG_ALBUM_ARTIST },
274 { "track", required_argument, 0, M4AF_TAG_TRACK },
275 { "disk", required_argument, 0, M4AF_TAG_DISK },
276 { "tempo", required_argument, 0, M4AF_TAG_TEMPO },
c5c45908 277 { "tag", required_argument, 0, OPT_SHORT_TAG },
a56831da 278 { "tag-from-file", required_argument, 0, OPT_SHORT_TAG_FILE },
c5c45908 279 { "long-tag", required_argument, 0, OPT_LONG_TAG },
cbb23cdb 280 { "tag-from-json", required_argument, 0, OPT_TAG_FROM_JSON },
5c534696 281 { 0, 0, 0, 0 },
48e2f01c 282 };
283 params->afterburner = 1;
284
285 aacenc_getmainargs(&argc, &argv);
d317e29d 286 while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:Ls:f:CP:G:Io:SR",
48e2f01c 287 long_options, 0)) != EOF) {
288 switch (ch) {
289 case 'h':
290 return usage(), -1;
291 case 'p':
292 if (sscanf(optarg, "%u", &n) != 1) {
293 fprintf(stderr, "invalid arg for profile\n");
294 return -1;
295 }
296 params->profile = n;
297 break;
298 case 'b':
299 if (sscanf(optarg, "%u", &n) != 1) {
300 fprintf(stderr, "invalid arg for bitrate\n");
301 return -1;
302 }
303 params->bitrate = n;
304 break;
305 case 'm':
306 if (sscanf(optarg, "%u", &n) != 1 || n > 5) {
307 fprintf(stderr, "invalid arg for bitrate-mode\n");
308 return -1;
309 }
310 params->bitrate_mode = n;
311 break;
312 case 'w':
313 if (sscanf(optarg, "%u", &n) != 1) {
314 fprintf(stderr, "invalid arg for bandwidth\n");
315 return -1;
316 }
317 params->bandwidth = n;
318 break;
319 case 'a':
320 if (sscanf(optarg, "%u", &n) != 1 || n > 1) {
321 fprintf(stderr, "invalid arg for afterburner\n");
322 return -1;
323 }
324 params->afterburner = n;
325 break;
326 case 'L':
327 params->lowdelay_sbr = 1;
328 break;
329 case 's':
330 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
331 fprintf(stderr, "invalid arg for sbr-signaling\n");
332 return -1;
333 }
334 params->sbr_signaling = n;
335 break;
336 case 'f':
337 if (sscanf(optarg, "%u", &n) != 1) {
338 fprintf(stderr, "invalid arg for transport-format\n");
339 return -1;
340 }
341 params->transport_format = n;
342 break;
229c3ead 343 case 'C':
48e2f01c 344 params->adts_crc_check = 1;
345 break;
346 case 'P':
347 if (sscanf(optarg, "%u", &n) != 1) {
348 fprintf(stderr, "invalid arg for header-period\n");
349 return -1;
350 }
351 params->header_period = n;
352 break;
353 case 'o':
354 params->output_filename = optarg;
355 break;
d317e29d 356 case 'G':
357 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
358 fprintf(stderr, "invalid arg for gapless-mode\n");
359 return -1;
360 }
361 params->gapless_mode = n;
362 break;
48e2f01c 363 case 'I':
364 params->ignore_length = 1;
365 break;
aa2ca1e3 366 case 'S':
367 params->silent = 1;
368 break;
fb2b3635 369 case OPT_MOOV_BEFORE_MDAT:
370 params->moov_before_mdat = 1;
371 break;
68543176 372 case 'R':
373 params->is_raw = 1;
374 break;
375 case OPT_RAW_CHANNELS:
376 if (sscanf(optarg, "%u", &n) != 1) {
377 fprintf(stderr, "invalid arg for raw-channels\n");
378 return -1;
379 }
380 params->raw_channels = n;
381 break;
382 case OPT_RAW_RATE:
383 if (sscanf(optarg, "%u", &n) != 1) {
384 fprintf(stderr, "invalid arg for raw-rate\n");
385 return -1;
386 }
387 params->raw_rate = n;
388 break;
389 case OPT_RAW_FORMAT:
390 params->raw_format = optarg;
391 break;
48e2f01c 392 case M4AF_TAG_TITLE:
393 case M4AF_TAG_ARTIST:
394 case M4AF_TAG_ALBUM:
395 case M4AF_TAG_GENRE:
396 case M4AF_TAG_DATE:
397 case M4AF_TAG_COMPOSER:
398 case M4AF_TAG_GROUPING:
399 case M4AF_TAG_COMMENT:
400 case M4AF_TAG_ALBUM_ARTIST:
401 case M4AF_TAG_TRACK:
402 case M4AF_TAG_DISK:
403 case M4AF_TAG_TEMPO:
3b666b75 404 aacenc_add_tag_to_store(&params->tags, ch, 0, optarg,
405 strlen(optarg), 0);
c5c45908 406 break;
407 case OPT_SHORT_TAG:
a56831da 408 case OPT_SHORT_TAG_FILE:
c5c45908 409 case OPT_LONG_TAG:
410 {
411 char *val;
412 size_t klen;
413 unsigned fcc = M4AF_FOURCC('-','-','-','-');
414
415 if ((val = strchr(optarg, ':')) == 0) {
416 fprintf(stderr, "invalid arg for tag\n");
417 return -1;
418 }
419 *val++ = '\0';
a56831da 420 if (ch == OPT_SHORT_TAG || ch == OPT_SHORT_TAG_FILE) {
360cf7dc 421 /*
422 * take care of U+00A9(COPYRIGHT SIGN).
423 * 1) if length of fcc is 3, we prepend '\xa9'.
424 * 2) U+00A9 becomes "\xc2\xa9" in UTF-8. Therefore
425 * we remove first '\xc2'.
426 */
427 if (optarg[0] == '\xc2')
428 ++optarg;
c5c45908 429 if ((klen = strlen(optarg))== 3)
430 fcc = 0xa9;
431 else if (klen != 4) {
432 fprintf(stderr, "invalid arg for tag\n");
433 return -1;
434 }
435 for (; *optarg; ++optarg)
436 fcc = ((fcc << 8) | (*optarg & 0xff));
437 }
3b666b75 438 aacenc_add_tag_to_store(&params->tags, fcc, optarg,
439 val, strlen(val),
440 ch == OPT_SHORT_TAG_FILE);
48e2f01c 441 }
48e2f01c 442 break;
cbb23cdb 443 case OPT_TAG_FROM_JSON:
444 params->json_filename = optarg;
445 break;
48e2f01c 446 default:
447 return usage(), -1;
448 }
449 }
450 if (argc == optind)
451 return usage(), -1;
68543176 452
48e2f01c 453 if (!params->bitrate && !params->bitrate_mode) {
454 fprintf(stderr, "bitrate or bitrate-mode is mandatory\n");
455 return -1;
456 }
457 if (params->output_filename && !strcmp(params->output_filename, "-") &&
458 !params->transport_format) {
459 fprintf(stderr, "stdout streaming is not available on M4A output\n");
460 return -1;
461 }
462 if (params->bitrate && params->bitrate < 10000)
463 params->bitrate *= 1000;
68543176 464
465 if (params->is_raw) {
466 if (!params->raw_channels)
467 params->raw_channels = 2;
468 if (!params->raw_rate)
469 params->raw_rate = 44100;
470 if (!params->raw_format)
471 params->raw_format = "S16L";
472 }
48e2f01c 473 params->input_filename = argv[optind];
474 return 0;
475};
476
477static
e4bbeeb0 478int write_sample(FILE *ofp, m4af_ctx_t *m4af,
48e2f01c 479 const void *data, uint32_t size, uint32_t duration)
480{
481 if (!m4af) {
5e1168a4 482 fwrite(data, 1, size, ofp);
483 if (ferror(ofp)) {
48e2f01c 484 fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno));
485 return -1;
486 }
487 } else if (m4af_write_sample(m4af, 0, data, size, duration) < 0) {
488 fprintf(stderr, "ERROR: failed to write m4a sample\n");
489 return -1;
490 }
491 return 0;
492}
493
494static
2d744bd5 495int encode(pcm_reader_t *reader, HANDLE_AACENCODER encoder,
e4bbeeb0 496 uint32_t frame_length, FILE *ofp, m4af_ctx_t *m4af,
aa2ca1e3 497 int show_progress)
48e2f01c 498{
e8e9f79e 499 int16_t *ibuf = 0;
48e2f01c 500 uint8_t *obuf = 0;
501 uint32_t olen;
502 uint32_t osize = 0;
503 int nread = 1;
504 int consumed;
505 int rc = -1;
506 int frames_written = 0;
507 aacenc_progress_t progress = { 0 };
2d744bd5 508 const pcm_sample_description_t *fmt = pcm_get_format(reader);
48e2f01c 509
2d744bd5 510 ibuf = malloc(frame_length * fmt->bytes_per_frame);
511 aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate);
48e2f01c 512 do {
bd3b4b34 513 if (g_interrupted)
514 nread = 0;
515 else if (nread) {
2d744bd5 516 if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) {
48e2f01c 517 fprintf(stderr, "ERROR: read failed\n");
518 goto END;
48e2f01c 519 }
aa2ca1e3 520 if (show_progress)
2d744bd5 521 aacenc_progress_update(&progress, pcm_get_position(reader),
522 fmt->sample_rate * 2);
48e2f01c 523 }
e8e9f79e 524 if ((consumed = aac_encode_frame(encoder, fmt, ibuf, nread,
48e2f01c 525 &obuf, &olen, &osize)) < 0)
526 goto END;
527 if (olen > 0) {
528 if (write_sample(ofp, m4af, obuf, olen, frame_length) < 0)
529 goto END;
530 ++frames_written;
531 }
532 } while (nread > 0 || olen > 0);
aa2ca1e3 533
534 if (show_progress)
2d744bd5 535 aacenc_progress_finish(&progress, pcm_get_position(reader));
48e2f01c 536 rc = frames_written;
537END:
538 if (ibuf) free(ibuf);
48e2f01c 539 if (obuf) free(obuf);
540 return rc;
541}
542
c5c45908 543static
e4bbeeb0 544void put_tool_tag(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
c5c45908 545 HANDLE_AACENCODER encoder)
546{
547 char tool_info[256];
548 char *p = tool_info;
549 LIB_INFO *lib_info = 0;
550
551 p += sprintf(p, PROGNAME " %s, ", fdkaac_version);
552
553 lib_info = calloc(FDK_MODULE_LAST, sizeof(LIB_INFO));
554 if (aacEncGetLibInfo(lib_info) == AACENC_OK) {
555 int i;
556 for (i = 0; i < FDK_MODULE_LAST; ++i)
557 if (lib_info[i].module_id == FDK_AACENC)
558 break;
559 p += sprintf(p, "libfdk-aac %s, ", lib_info[i].versionStr);
560 }
561 free(lib_info);
562 if (params->bitrate_mode)
563 sprintf(p, "VBR mode %d", params->bitrate_mode);
564 else
565 sprintf(p, "CBR %dkbps",
566 aacEncoder_GetParam(encoder, AACENC_BITRATE) / 1000);
567
568 m4af_add_itmf_string_tag(m4af, M4AF_TAG_TOOL, tool_info);
569}
570
48e2f01c 571static
e4bbeeb0 572int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
48e2f01c 573 HANDLE_AACENCODER encoder)
574{
575 unsigned i;
1af8624b 576 aacenc_tag_entry_t *tag;
577
578 tag = params->source_tags.tag_table;
579 for (i = 0; i < params->source_tags.tag_count; ++i, ++tag)
580 aacenc_write_tag_entry(m4af, tag);
cbb23cdb 581
582 if (params->json_filename)
3b666b75 583 aacenc_write_tags_from_json(m4af, params->json_filename);
cbb23cdb 584
1af8624b 585 tag = params->tags.tag_table;
cbb23cdb 586 for (i = 0; i < params->tags.tag_count; ++i, ++tag)
3b666b75 587 aacenc_write_tag_entry(m4af, tag);
c5c45908 588
589 put_tool_tag(m4af, params, encoder);
48e2f01c 590
fb2b3635 591 if (m4af_finalize(m4af, params->moov_before_mdat) < 0) {
48e2f01c 592 fprintf(stderr, "ERROR: failed to finalize m4a\n");
593 return -1;
594 }
595 return 0;
596}
597
af8fa38d 598static
599char *generate_output_filename(const char *filename, const char *ext)
600{
601 char *p = 0;
602 size_t ext_len = strlen(ext);
603
604 if (strcmp(filename, "-") == 0) {
605 p = malloc(ext_len + 6);
606 sprintf(p, "stdin%s", ext);
607 } else {
5888fddc 608 const char *base = aacenc_basename(filename);
af8fa38d 609 size_t ilen = strlen(base);
610 const char *ext_org = strrchr(base, '.');
611 if (ext_org) ilen = ext_org - base;
612 p = malloc(ilen + ext_len + 1);
613 sprintf(p, "%.*s%s", ilen, base, ext);
614 }
615 return p;
616}
617
68543176 618static
619int parse_raw_spec(const char *spec, pcm_sample_description_t *desc)
620{
621 unsigned bits;
622 unsigned char c_type, c_endian = 'L';
623 int type;
624
625 if (sscanf(spec, "%c%u%c", &c_type, &bits, &c_endian) < 2)
626 return -1;
627 c_type = toupper(c_type);
628 c_endian = toupper(c_endian);
629
630 if (c_type == 'S')
631 type = 1;
632 else if (c_type == 'U')
633 type = 2;
634 else if (c_type == 'F')
635 type = 4;
636 else
637 return -1;
638
639 if (c_endian == 'B')
640 type |= 8;
641 else if (c_endian != 'L')
642 return -1;
643
644 if (c_type == 'F' && bits != 32 && bits != 64)
645 return -1;
646 if (c_type != 'F' && (bits < 8 || bits > 32))
647 return -1;
648
649 desc->sample_type = type;
650 desc->bits_per_channel = bits;
651 return 0;
652}
653
29a8f73f 654static pcm_io_vtbl_t pcm_io_vtbl = {
655 read_callback, seek_callback, tell_callback
656};
657static pcm_io_vtbl_t pcm_io_vtbl_noseek = { read_callback, 0, 0 };
658
2d744bd5 659static
660pcm_reader_t *open_input(aacenc_param_ex_t *params)
661{
29a8f73f 662 pcm_io_context_t io = { 0 };
2d744bd5 663 pcm_reader_t *reader = 0;
664 struct stat stb = { 0 };
665
666 if ((params->input_fp = aacenc_fopen(params->input_filename, "rb")) == 0) {
667 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params->input_filename,
668 strerror(errno));
669 goto END;
670 }
29a8f73f 671 io.cookie = params->input_fp;
672 if (fstat(fileno(io.cookie), &stb) == 0
673 && (stb.st_mode & S_IFMT) == S_IFREG)
674 io.vtbl = &pcm_io_vtbl;
675 else
676 io.vtbl = &pcm_io_vtbl_noseek;
677
2d744bd5 678 if (params->is_raw) {
679 int bytes_per_channel;
680 pcm_sample_description_t desc = { 0 };
681 if (parse_raw_spec(params->raw_format, &desc) < 0) {
682 fprintf(stderr, "ERROR: invalid raw-format spec\n");
683 goto END;
684 }
685 desc.sample_rate = params->raw_rate;
686 desc.channels_per_frame = params->raw_channels;
687 bytes_per_channel = (desc.bits_per_channel + 7) / 8;
688 desc.bytes_per_frame = params->raw_channels * bytes_per_channel;
29a8f73f 689 if ((reader = raw_open(&io, &desc)) == 0) {
2d744bd5 690 fprintf(stderr, "ERROR: failed to open raw input\n");
691 goto END;
692 }
693 } else {
1af8624b 694 int c;
695 ungetc(c = getc(params->input_fp), params->input_fp);
696
697 switch (c) {
698 case 'R':
699 if ((reader = wav_open(&io, params->ignore_length)) == 0) {
700 fprintf(stderr, "ERROR: broken / unsupported input file\n");
701 goto END;
702 }
703 break;
704 case 'c':
705 params->source_tag_ctx.add = aacenc_add_tag_entry_to_store;
706 params->source_tag_ctx.add_ctx = &params->source_tags;
707 if ((reader = caf_open(&io,
708 aacenc_translate_generic_text_tag,
709 &params->source_tag_ctx)) == 0) {
710 fprintf(stderr, "ERROR: broken / unsupported input file\n");
711 goto END;
712 }
713 break;
714 default:
2d744bd5 715 goto END;
716 }
717 }
e8e9f79e 718 return pcm_open_sint16_converter(reader);
2d744bd5 719END:
e8e9f79e 720 return 0;
2d744bd5 721}
722
48e2f01c 723int main(int argc, char **argv)
724{
2d744bd5 725 static m4af_io_callbacks_t m4af_io = {
726 read_callback, write_callback, seek_callback, tell_callback
727 };
48e2f01c 728 aacenc_param_ex_t params = { 0 };
729
730 int result = 2;
48e2f01c 731 char *output_filename = 0;
2d744bd5 732 pcm_reader_t *reader = 0;
48e2f01c 733 HANDLE_AACENCODER encoder = 0;
734 AACENC_InfoStruct aacinfo = { 0 };
e4bbeeb0 735 m4af_ctx_t *m4af = 0;
48e2f01c 736 const pcm_sample_description_t *sample_format;
737 int downsampled_timescale = 0;
738 int frame_count = 0;
739
740 setlocale(LC_CTYPE, "");
741 setbuf(stderr, 0);
742
743 if (parse_options(argc, argv, &params) < 0)
744 return 1;
745
2d744bd5 746 if ((reader = open_input(&params)) == 0)
48e2f01c 747 goto END;
2d744bd5 748
749 sample_format = pcm_get_format(reader);
48e2f01c 750
751 if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
752 &aacinfo) < 0)
753 goto END;
754
755 if (!params.output_filename) {
af8fa38d 756 const char *ext = params.transport_format ? ".aac" : ".m4a";
757 output_filename = generate_output_filename(params.input_filename, ext);
48e2f01c 758 params.output_filename = output_filename;
759 }
760
2d744bd5 761 if ((params.output_fp = aacenc_fopen(params.output_filename, "wb+")) == 0) {
48e2f01c 762 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename,
763 strerror(errno));
764 goto END;
765 }
bd3b4b34 766 handle_signals();
48e2f01c 767 if (!params.transport_format) {
768 uint32_t scale;
769 unsigned framelen = aacinfo.frameLength;
7b1f2136 770 int sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)&params);
771 int sig_mode = aacEncoder_GetParam(encoder, AACENC_SIGNALING_MODE);
772 if (sbr_mode && !sig_mode)
773 downsampled_timescale = 1;
48e2f01c 774 scale = sample_format->sample_rate >> downsampled_timescale;
2d744bd5 775 if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
776 params.output_fp)) < 0)
48e2f01c 777 goto END;
e4bbeeb0 778 m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf,
779 aacinfo.confSize);
48e2f01c 780 m4af_set_fixed_frame_duration(m4af, 0,
781 framelen >> downsampled_timescale);
2f6fc566 782 m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
d317e29d 783 m4af_set_priming_mode(m4af, params.gapless_mode + 1);
48e2f01c 784 m4af_begin_write(m4af);
785 }
2d744bd5 786 frame_count = encode(reader, encoder, aacinfo.frameLength,
787 params.output_fp, m4af, !params.silent);
48e2f01c 788 if (frame_count < 0)
789 goto END;
790 if (m4af) {
791 uint32_t delay = aacinfo.encoderDelay;
2d744bd5 792 int64_t frames_read = pcm_get_position(reader);
48e2f01c 793 uint32_t padding = frame_count * aacinfo.frameLength
794 - frames_read - aacinfo.encoderDelay;
795 m4af_set_priming(m4af, 0, delay >> downsampled_timescale,
796 padding >> downsampled_timescale);
797 if (finalize_m4a(m4af, &params, encoder) < 0)
798 goto END;
799 }
800 result = 0;
801END:
2d744bd5 802 if (reader) pcm_teardown(&reader);
803 if (params.input_fp) fclose(params.input_fp);
48e2f01c 804 if (m4af) m4af_teardown(&m4af);
2d744bd5 805 if (params.output_fp) fclose(params.output_fp);
48e2f01c 806 if (encoder) aacEncClose(&encoder);
807 if (output_filename) free(output_filename);
1af8624b 808 if (params.tags.tag_table)
809 aacenc_free_tag_store(&params.tags);
810 if (params.source_tags.tag_table)
811 aacenc_free_tag_store(&params.source_tags);
48e2f01c 812
813 return result;
814}
This page took 0.059272 seconds and 4 git commands to generate.