New upstream version 1.0.0
[fdkaac.git] / src / main.c
... / ...
CommitLineData
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
11#if HAVE_INTTYPES_H
12# include <inttypes.h>
13#elif defined(_MSC_VER)
14# define SCNd64 "I64d"
15#endif
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <ctype.h>
20#include <locale.h>
21#include <errno.h>
22#include <sys/stat.h>
23#include <getopt.h>
24#if HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#if HAVE_SIGACTION
28#include <signal.h>
29#endif
30#ifdef _WIN32
31#include <io.h>
32#define WIN32_LEAN_AND_MEAN
33#include <windows.h>
34#endif
35#include "compat.h"
36#include "pcm_reader.h"
37#include "aacenc.h"
38#include "m4af.h"
39#include "progress.h"
40#include "version.h"
41#include "metadata.h"
42
43#define PROGNAME "fdkaac"
44
45static volatile int g_interrupted = 0;
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) {
56 struct sigaction sa;
57 memset(&sa, 0, sizeof sa);
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
80static
81int read_callback(void *cookie, void *data, uint32_t size)
82{
83 size_t rc = fread(data, 1, size, (FILE*)cookie);
84 return ferror((FILE*)cookie) ? -1 : (int)rc;
85}
86
87static
88int write_callback(void *cookie, const void *data, uint32_t size)
89{
90 size_t rc = fwrite(data, 1, size, (FILE*)cookie);
91 return ferror((FILE*)cookie) ? -1 : (int)rc;
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" -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"
129" -a, --afterburner <n> Afterburner\n"
130" 0: Off\n"
131" 1: On(default)\n"
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"
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"
147" -C, --adts-crc-check Add CRC protection on ADTS header\n"
148" -h, --header-period <n> StreamMuxConfig/PCE repetition period in\n"
149" transport layer\n"
150"\n"
151" -o <filename> Output filename\n"
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"
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"
159" -I, --ignorelength Ignore length of WAV header\n"
160" -S, --silent Don't print progress messages\n"
161" --moov-before-mdat Place moov box before mdat box on m4a output\n"
162"\n"
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"
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"
190" --tag <fcc>:<value> Set iTunes predefined tag with four char code.\n"
191" --tag-from-file <fcc>:<filename>\n"
192" Same as above, but value is read from file.\n"
193" --long-tag <name>:<value> Set arbitrary tag as iTunes custom metadata.\n"
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"
203 , fdkaac_version);
204}
205
206typedef struct aacenc_param_ex_t {
207 AACENC_PARAMS
208
209 char *input_filename;
210 FILE *input_fp;
211 char *output_filename;
212 FILE *output_fp;
213 unsigned gapless_mode;
214 unsigned include_sbr_delay;
215 unsigned ignore_length;
216 int silent;
217 int moov_before_mdat;
218
219 int is_raw;
220 unsigned raw_channels;
221 unsigned raw_rate;
222 const char *raw_format;
223
224 aacenc_tag_store_t tags;
225 aacenc_tag_store_t source_tags;
226 aacenc_translate_generic_text_tag_ctx_t source_tag_ctx;
227
228 char *json_filename;
229} aacenc_param_ex_t;
230
231static
232int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
233{
234 int ch;
235 int n;
236
237#define OPT_INCLUDE_SBR_DELAY M4AF_FOURCC('s','d','l','y')
238#define OPT_MOOV_BEFORE_MDAT M4AF_FOURCC('m','o','o','v')
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')
245#define OPT_TAG_FROM_JSON M4AF_FOURCC('t','f','j','s')
246
247 static struct option long_options[] = {
248 { "help", no_argument, 0, 'h' },
249 { "profile", required_argument, 0, 'p' },
250 { "bitrate", required_argument, 0, 'b' },
251 { "bitrate-mode", required_argument, 0, 'm' },
252 { "bandwidth", required_argument, 0, 'w' },
253 { "afterburner", required_argument, 0, 'a' },
254 { "lowdelay-sbr", required_argument, 0, 'L' },
255 { "sbr-ratio", required_argument, 0, 's' },
256 { "transport-format", required_argument, 0, 'f' },
257 { "adts-crc-check", no_argument, 0, 'C' },
258 { "header-period", required_argument, 0, 'P' },
259
260 { "gapless-mode", required_argument, 0, 'G' },
261 { "include-sbr-delay", no_argument, 0, OPT_INCLUDE_SBR_DELAY },
262 { "ignorelength", no_argument, 0, 'I' },
263 { "silent", no_argument, 0, 'S' },
264 { "moov-before-mdat", no_argument, 0, OPT_MOOV_BEFORE_MDAT },
265
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 },
283 { "tag", required_argument, 0, OPT_SHORT_TAG },
284 { "tag-from-file", required_argument, 0, OPT_SHORT_TAG_FILE },
285 { "long-tag", required_argument, 0, OPT_LONG_TAG },
286 { "tag-from-json", required_argument, 0, OPT_TAG_FROM_JSON },
287 { 0, 0, 0, 0 },
288 };
289 params->afterburner = 1;
290
291 aacenc_getmainargs(&argc, &argv);
292 while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:L:s:f:CP:G:Io:SR",
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':
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;
345 break;
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;
353 case 'C':
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;
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;
373 case OPT_INCLUDE_SBR_DELAY:
374 params->include_sbr_delay = 1;
375 break;
376 case 'I':
377 params->ignore_length = 1;
378 break;
379 case 'S':
380 params->silent = 1;
381 break;
382 case OPT_MOOV_BEFORE_MDAT:
383 params->moov_before_mdat = 1;
384 break;
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;
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:
417 aacenc_add_tag_to_store(&params->tags, ch, 0, optarg,
418 strlen(optarg), 0);
419 break;
420 case OPT_SHORT_TAG:
421 case OPT_SHORT_TAG_FILE:
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';
433 if (ch == OPT_SHORT_TAG || ch == OPT_SHORT_TAG_FILE) {
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;
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 }
451 aacenc_add_tag_to_store(&params->tags, fcc, optarg,
452 val, strlen(val),
453 ch == OPT_SHORT_TAG_FILE);
454 }
455 break;
456 case OPT_TAG_FROM_JSON:
457 params->json_filename = optarg;
458 break;
459 default:
460 return usage(), -1;
461 }
462 }
463 if (argc == optind)
464 return usage(), -1;
465
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;
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 }
486 params->input_filename = argv[optind];
487 return 0;
488};
489
490static
491int write_sample(FILE *ofp, m4af_ctx_t *m4af, aacenc_frame_t *frame)
492{
493 if (!m4af) {
494 fwrite(frame->data, 1, frame->size, ofp);
495 if (ferror(ofp)) {
496 fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno));
497 return -1;
498 }
499 } else if (m4af_write_sample(m4af, 0, frame->data, frame->size, 0) < 0) {
500 fprintf(stderr, "ERROR: failed to write m4a sample\n");
501 return -1;
502 }
503 return 0;
504}
505
506static int do_smart_padding(int profile)
507{
508 return profile == 2 || profile == 5 || profile == 29;
509}
510
511static
512int encode(aacenc_param_ex_t *params, pcm_reader_t *reader,
513 HANDLE_AACENCODER encoder, uint32_t frame_length,
514 m4af_ctx_t *m4af)
515{
516 int16_t *ibuf = 0, *ip;
517 aacenc_frame_t obuf[2] = {{ 0 }}, *obp;
518 unsigned flip = 0;
519 int nread = 1;
520 int rc = -1;
521 int remaining, consumed;
522 int frames_written = 0, encoded = 0;
523 aacenc_progress_t progress = { 0 };
524 const pcm_sample_description_t *fmt = pcm_get_format(reader);
525 const int is_padding = do_smart_padding(params->profile);
526
527 ibuf = malloc(frame_length * fmt->bytes_per_frame);
528 aacenc_progress_init(&progress, pcm_get_length(reader), fmt->sample_rate);
529
530 for (;;) {
531 if (g_interrupted)
532 nread = 0;
533 if (nread > 0) {
534 if ((nread = pcm_read_frames(reader, ibuf, frame_length)) < 0) {
535 fprintf(stderr, "ERROR: read failed\n");
536 goto END;
537 }
538 if (!params->silent)
539 aacenc_progress_update(&progress, pcm_get_position(reader),
540 fmt->sample_rate * 2);
541 }
542 ip = ibuf;
543 remaining = nread;
544 do {
545 obp = &obuf[flip];
546 consumed = aac_encode_frame(encoder, fmt, ip, remaining, obp);
547 if (consumed < 0) goto END;
548 if (consumed == 0 && obp->size == 0) goto DONE;
549 if (obp->size == 0) break;
550
551 remaining -= consumed;
552 ip += consumed * fmt->channels_per_frame;
553 if (is_padding) {
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 */
562 flip ^= 1;
563 ++encoded;
564 if (encoded == 1 || encoded == 3)
565 continue;
566 }
567 if (write_sample(params->output_fp, m4af, &obuf[flip]) < 0)
568 goto END;
569 ++frames_written;
570 } while (remaining > 0);
571 }
572DONE:
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 }
582 if (!params->silent)
583 aacenc_progress_finish(&progress, pcm_get_position(reader));
584 rc = frames_written;
585END:
586 if (ibuf) free(ibuf);
587 if (obuf[0].data) free(obuf[0].data);
588 if (obuf[1].data) free(obuf[1].data);
589 return rc;
590}
591
592static
593void put_tool_tag(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
594 HANDLE_AACENCODER encoder)
595{
596 char tool_info[256];
597 char *p = tool_info;
598 LIB_INFO lib_info;
599
600 p += sprintf(p, PROGNAME " %s, ", fdkaac_version);
601 aacenc_get_lib_info(&lib_info);
602 p += sprintf(p, "libfdk-aac %s, ", lib_info.versionStr);
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
612static
613int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
614 HANDLE_AACENCODER encoder)
615{
616 unsigned i;
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);
622
623 if (params->json_filename)
624 aacenc_write_tags_from_json(m4af, params->json_filename);
625
626 tag = params->tags.tag_table;
627 for (i = 0; i < params->tags.tag_count; ++i, ++tag)
628 aacenc_write_tag_entry(m4af, tag);
629
630 put_tool_tag(m4af, params, encoder);
631
632 if (m4af_finalize(m4af, params->moov_before_mdat) < 0) {
633 fprintf(stderr, "ERROR: failed to finalize m4a\n");
634 return -1;
635 }
636 return 0;
637}
638
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 {
649 const char *base = aacenc_basename(filename);
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);
654 sprintf(p, "%.*s%s", (int)ilen, base, ext);
655 }
656 return p;
657}
658
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
695static pcm_io_vtbl_t pcm_io_vtbl = {
696 read_callback, seek_callback, tell_callback
697};
698static pcm_io_vtbl_t pcm_io_vtbl_noseek = { read_callback, 0, tell_callback };
699
700static
701pcm_reader_t *open_input(aacenc_param_ex_t *params)
702{
703 pcm_io_context_t io = { 0 };
704 pcm_reader_t *reader = 0;
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));
709 goto FAIL;
710 }
711 io.cookie = params->input_fp;
712 if (aacenc_seekable(params->input_fp))
713 io.vtbl = &pcm_io_vtbl;
714 else
715 io.vtbl = &pcm_io_vtbl_noseek;
716
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");
722 goto FAIL;
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;
728 if ((reader = raw_open(&io, &desc)) == 0) {
729 fprintf(stderr, "ERROR: failed to open raw input\n");
730 goto FAIL;
731 }
732 } else {
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");
740 goto FAIL;
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");
750 goto FAIL;
751 }
752 break;
753 default:
754 fprintf(stderr, "ERROR: unsupported input file\n");
755 goto FAIL;
756 }
757 }
758 reader = pcm_open_native_converter(reader);
759 if (reader && PCM_IS_FLOAT(pcm_get_format(reader)))
760 reader = limiter_open(reader);
761 if (reader && (reader = pcm_open_sint16_converter(reader)) != 0) {
762 if (do_smart_padding(params->profile))
763 reader = extrapolater_open(reader);
764 }
765 return reader;
766FAIL:
767 return 0;
768}
769
770int main(int argc, char **argv)
771{
772 static m4af_io_callbacks_t m4af_io = {
773 read_callback, write_callback, seek_callback, tell_callback
774 };
775 aacenc_param_ex_t params = { 0 };
776
777 int result = 2;
778 char *output_filename = 0;
779 pcm_reader_t *reader = 0;
780 HANDLE_AACENCODER encoder = 0;
781 AACENC_InfoStruct aacinfo = { 0 };
782 m4af_ctx_t *m4af = 0;
783 const pcm_sample_description_t *sample_format;
784 int frame_count = 0;
785 int sbr_mode = 0;
786 unsigned scale_shift = 0;
787
788 setlocale(LC_CTYPE, "");
789 setbuf(stderr, 0);
790
791 if (parse_options(argc, argv, &params) < 0)
792 return 1;
793
794 if ((reader = open_input(&params)) == 0)
795 goto END;
796
797 sample_format = pcm_get_format(reader);
798
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);
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 }
814 if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
815 &aacinfo) < 0)
816 goto END;
817
818 if (!params.output_filename) {
819 const char *ext = params.transport_format ? ".aac" : ".m4a";
820 output_filename = generate_output_filename(params.input_filename, ext);
821 params.output_filename = output_filename;
822 }
823
824 if ((params.output_fp = aacenc_fopen(params.output_filename, "wb+")) == 0) {
825 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename,
826 strerror(errno));
827 goto END;
828 }
829 handle_signals();
830
831 if (!params.transport_format) {
832 uint32_t scale;
833 unsigned framelen = aacinfo.frameLength;
834 scale = sample_format->sample_rate >> scale_shift;
835 if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io,
836 params.output_fp)) < 0)
837 goto END;
838 m4af_set_num_channels(m4af, 0, sample_format->channels_per_frame);
839 m4af_set_fixed_frame_duration(m4af, 0, framelen >> scale_shift);
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 }
850 m4af_set_vbr_mode(m4af, 0, params.bitrate_mode);
851 m4af_set_priming_mode(m4af, params.gapless_mode + 1);
852 m4af_begin_write(m4af);
853 }
854 frame_count = encode(&params, reader, encoder, aacinfo.frameLength, m4af);
855 if (frame_count < 0)
856 goto END;
857 if (m4af) {
858 uint32_t padding;
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
868 int64_t frames_read = pcm_get_position(reader);
869
870 padding = frame_count * aacinfo.frameLength - frames_read - delay;
871 m4af_set_priming(m4af, 0, delay >> scale_shift, padding >> scale_shift);
872 if (finalize_m4a(m4af, &params, encoder) < 0)
873 goto END;
874 }
875 result = 0;
876END:
877 if (reader) pcm_teardown(&reader);
878 if (params.input_fp) fclose(params.input_fp);
879 if (m4af) m4af_teardown(&m4af);
880 if (params.output_fp) fclose(params.output_fp);
881 if (encoder) aacEncClose(&encoder);
882 if (output_filename) free(output_filename);
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);
887
888 return result;
889}
This page took 0.015516 seconds and 4 git commands to generate.