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