add --gapless-mode
[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 "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 = { 0 };
57 sa.sa_handler = signal_handler;
58 sa.sa_flags |= SA_RESTART;
59 sigaction(sigs[i], &sa, 0);
60 }
61}
62#elif defined(_WIN32)
63static BOOL WINAPI signal_handler(DWORD type)
64{
65 g_interrupted = 1;
66 return TRUE;
67}
68
69static void handle_signals(void)
70{
71 SetConsoleCtrlHandler(signal_handler, TRUE);
72}
73#else
74static void handle_signals(void)
75{
76}
77#endif
78
79static
80int read_callback(void *cookie, void *data, uint32_t size)
81{
82 size_t rc = fread(data, 1, size, (FILE*)cookie);
83 return ferror((FILE*)cookie) ? -1 : (int)rc;
84}
85
86static
87int write_callback(void *cookie, const void *data, uint32_t size)
88{
89 size_t rc = fwrite(data, 1, size, (FILE*)cookie);
90 return ferror((FILE*)cookie) ? -1 : (int)rc;
91}
92
93static
94int seek_callback(void *cookie, int64_t off, int whence)
95{
96 return fseeko((FILE*)cookie, off, whence);
97}
98
99static
100int64_t tell_callback(void *cookie)
101{
102 return ftello((FILE*)cookie);
103}
104
105static
106void usage(void)
107{
108 printf(
109PROGNAME " %s\n"
110"Usage: " PROGNAME " [options] input_file\n"
111"Options:\n"
112" -h, --help Print this help message\n"
113" -p, --profile <n> Profile (audio object type)\n"
114" 2: MPEG-4 AAC LC (default)\n"
115" 5: MPEG-4 HE-AAC (SBR)\n"
116" 29: MPEG-4 HE-AAC v2 (SBR+PS)\n"
117" 23: MPEG-4 AAC LD\n"
118" 39: MPEG-4 AAC ELD\n"
119" 129: MPEG-2 AAC LC\n"
120" 132: MPEG-2 HE-AAC (SBR)\n"
121" 156: MPEG-2 HE-AAC v2 (SBR+PS)\n"
122" -b, --bitrate <n> Bitrate in bits per seconds (for CBR)\n"
123" -m, --bitrate-mode <n> Bitrate configuration\n"
124" 0: CBR (default)\n"
125" 1-5: VBR\n"
126" (VBR mode is not officially supported, and\n"
127" works only on a certain combination of\n"
128" parameter settings, sample rate, and\n"
129" channel configuration)\n"
130" -w, --bandwidth <n> Frequency bandwidth in Hz (AAC LC only)\n"
131" -a, --afterburner <n> Afterburner\n"
132" 0: Off\n"
133" 1: On(default)\n"
134" -L, --lowdelay-sbr Enable ELD-SBR (AAC ELD only)\n"
135" -s, --sbr-signaling <n> SBR signaling mode\n"
136" 0: Implicit, backward compatible(default)\n"
137" 1: Explicit SBR and implicit PS\n"
138" 2: Explicit hierarchical signaling\n"
139" -f, --transport-format <n> Transport format\n"
140" 0: RAW (default, muxed into M4A)\n"
141" 1: ADIF\n"
142" 2: ADTS\n"
143" 6: LATM MCP=1\n"
144" 7: LATM MCP=0\n"
145" 10: LOAS/LATM (LATM within LOAS)\n"
146" -C, --adts-crc-check Add CRC protection on ADTS header\n"
147" -h, --header-period <n> StreamMuxConfig/PCE repetition period in\n"
148" transport layer\n"
149"\n"
150" -o <filename> Output filename\n"
151" -G, --gapless-mode <n> Encoder delay signaling for gapless playback\n"
152" 0: iTunSMPB (default)\n"
153" 1: ISO standard (edts + sgpd)\n"
154" 2: Both\n"
155" --ignorelength Ignore length of WAV header\n"
156" -S, --silent Don't print progress messages\n"
157"\n"
158"Options for raw (headerless) input:\n"
159" -R, --raw Treat input as raw (by default WAV is\n"
160" assumed)\n"
161" --raw-channels <n> Number of channels (default: 2)\n"
162" --raw-rate <n> Sample rate (default: 44100)\n"
163" --raw-format <spec> Sample format, default is \"S16L\".\n"
164" Spec is as follows:\n"
165" 1st char: S(igned)|U(nsigned)|F(loat)\n"
166" 2nd part: bits per channel\n"
167" Last char: L(ittle)|B(ig)\n"
168" Last char can be omitted, in which case L is\n"
169" assumed. Spec is case insensitive, therefore\n"
170" \"u16b\" is same as \"U16B\".\n"
171"\n"
172"Tagging options:\n"
173" --title <string>\n"
174" --artist <string>\n"
175" --album <string>\n"
176" --genre <string>\n"
177" --date <string>\n"
178" --composer <string>\n"
179" --grouping <string>\n"
180" --comment <string>\n"
181" --album-artist <string>\n"
182" --track <number[/total]>\n"
183" --disk <number[/total]>\n"
184" --tempo <n>\n"
185" --tag <fcc>:<value> Set iTunes predefined tag with four char code.\n"
186" --tag-from-file <fcc>:<filename>\n"
187" Same as above, but value is read from file.\n"
188" --long-tag <name>:<value> Set arbitrary tag as iTunes custom metadata.\n"
189" --tag-from-json <filename[?dot_notation]>\n"
190" Read tags from JSON. By default, tags are\n"
191" assumed to be direct children of the root\n"
192" object(dictionary).\n"
193" Optionally, position of the dictionary\n"
194" that contains tags can be specified with\n"
195" dotted notation.\n"
196" Example:\n"
197" --tag-from-json /path/to/json?format.tags\n"
198 , fdkaac_version);
199}
200
201typedef struct aacenc_param_ex_t {
202 AACENC_PARAMS
203
204 char *input_filename;
205 char *output_filename;
206 unsigned gapless_mode;
207 unsigned ignore_length;
208 int silent;
209
210 int is_raw;
211 unsigned raw_channels;
212 unsigned raw_rate;
213 const char *raw_format;
214
215 aacenc_tag_param_t tags;
216
217 char *json_filename;
218} aacenc_param_ex_t;
219
220static
221int parse_options(int argc, char **argv, aacenc_param_ex_t *params)
222{
223 int ch;
224 unsigned n;
225
226#define OPT_RAW_CHANNELS M4AF_FOURCC('r','c','h','n')
227#define OPT_RAW_RATE M4AF_FOURCC('r','r','a','t')
228#define OPT_RAW_FORMAT M4AF_FOURCC('r','f','m','t')
229#define OPT_SHORT_TAG M4AF_FOURCC('s','t','a','g')
230#define OPT_SHORT_TAG_FILE M4AF_FOURCC('s','t','g','f')
231#define OPT_LONG_TAG M4AF_FOURCC('l','t','a','g')
232#define OPT_TAG_FROM_JSON M4AF_FOURCC('t','f','j','s')
233
234 static struct option long_options[] = {
235 { "help", no_argument, 0, 'h' },
236 { "profile", required_argument, 0, 'p' },
237 { "bitrate", required_argument, 0, 'b' },
238 { "bitrate-mode", required_argument, 0, 'm' },
239 { "bandwidth", required_argument, 0, 'w' },
240 { "afterburner", required_argument, 0, 'a' },
241 { "lowdelay-sbr", no_argument, 0, 'L' },
242 { "sbr-signaling", required_argument, 0, 's' },
243 { "transport-format", required_argument, 0, 'f' },
244 { "adts-crc-check", no_argument, 0, 'C' },
245 { "header-period", required_argument, 0, 'P' },
246
247 { "gapless-mode", required_argument, 0, 'G' },
248 { "ignorelength", no_argument, 0, 'I' },
249 { "silent", no_argument, 0, 'S' },
250
251 { "raw", no_argument, 0, 'R' },
252 { "raw-channels", required_argument, 0, OPT_RAW_CHANNELS },
253 { "raw-rate", required_argument, 0, OPT_RAW_RATE },
254 { "raw-format", required_argument, 0, OPT_RAW_FORMAT },
255
256 { "title", required_argument, 0, M4AF_TAG_TITLE },
257 { "artist", required_argument, 0, M4AF_TAG_ARTIST },
258 { "album", required_argument, 0, M4AF_TAG_ALBUM },
259 { "genre", required_argument, 0, M4AF_TAG_GENRE },
260 { "date", required_argument, 0, M4AF_TAG_DATE },
261 { "composer", required_argument, 0, M4AF_TAG_COMPOSER },
262 { "grouping", required_argument, 0, M4AF_TAG_GROUPING },
263 { "comment", required_argument, 0, M4AF_TAG_COMMENT },
264 { "album-artist", required_argument, 0, M4AF_TAG_ALBUM_ARTIST },
265 { "track", required_argument, 0, M4AF_TAG_TRACK },
266 { "disk", required_argument, 0, M4AF_TAG_DISK },
267 { "tempo", required_argument, 0, M4AF_TAG_TEMPO },
268 { "tag", required_argument, 0, OPT_SHORT_TAG },
269 { "tag-from-file", required_argument, 0, OPT_SHORT_TAG_FILE },
270 { "long-tag", required_argument, 0, OPT_LONG_TAG },
271 { "tag-from-json", required_argument, 0, OPT_TAG_FROM_JSON },
272 { 0, 0, 0, 0 },
273 };
274 params->afterburner = 1;
275
276 aacenc_getmainargs(&argc, &argv);
277 while ((ch = getopt_long(argc, argv, "hp:b:m:w:a:Ls:f:CP:G:Io:SR",
278 long_options, 0)) != EOF) {
279 switch (ch) {
280 case 'h':
281 return usage(), -1;
282 case 'p':
283 if (sscanf(optarg, "%u", &n) != 1) {
284 fprintf(stderr, "invalid arg for profile\n");
285 return -1;
286 }
287 params->profile = n;
288 break;
289 case 'b':
290 if (sscanf(optarg, "%u", &n) != 1) {
291 fprintf(stderr, "invalid arg for bitrate\n");
292 return -1;
293 }
294 params->bitrate = n;
295 break;
296 case 'm':
297 if (sscanf(optarg, "%u", &n) != 1 || n > 5) {
298 fprintf(stderr, "invalid arg for bitrate-mode\n");
299 return -1;
300 }
301 params->bitrate_mode = n;
302 break;
303 case 'w':
304 if (sscanf(optarg, "%u", &n) != 1) {
305 fprintf(stderr, "invalid arg for bandwidth\n");
306 return -1;
307 }
308 params->bandwidth = n;
309 break;
310 case 'a':
311 if (sscanf(optarg, "%u", &n) != 1 || n > 1) {
312 fprintf(stderr, "invalid arg for afterburner\n");
313 return -1;
314 }
315 params->afterburner = n;
316 break;
317 case 'L':
318 params->lowdelay_sbr = 1;
319 break;
320 case 's':
321 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
322 fprintf(stderr, "invalid arg for sbr-signaling\n");
323 return -1;
324 }
325 params->sbr_signaling = n;
326 break;
327 case 'f':
328 if (sscanf(optarg, "%u", &n) != 1) {
329 fprintf(stderr, "invalid arg for transport-format\n");
330 return -1;
331 }
332 params->transport_format = n;
333 break;
334 case 'C':
335 params->adts_crc_check = 1;
336 break;
337 case 'P':
338 if (sscanf(optarg, "%u", &n) != 1) {
339 fprintf(stderr, "invalid arg for header-period\n");
340 return -1;
341 }
342 params->header_period = n;
343 break;
344 case 'o':
345 params->output_filename = optarg;
346 break;
347 case 'G':
348 if (sscanf(optarg, "%u", &n) != 1 || n > 2) {
349 fprintf(stderr, "invalid arg for gapless-mode\n");
350 return -1;
351 }
352 params->gapless_mode = n;
353 break;
354 case 'I':
355 params->ignore_length = 1;
356 break;
357 case 'S':
358 params->silent = 1;
359 break;
360 case 'R':
361 params->is_raw = 1;
362 break;
363 case OPT_RAW_CHANNELS:
364 if (sscanf(optarg, "%u", &n) != 1) {
365 fprintf(stderr, "invalid arg for raw-channels\n");
366 return -1;
367 }
368 params->raw_channels = n;
369 break;
370 case OPT_RAW_RATE:
371 if (sscanf(optarg, "%u", &n) != 1) {
372 fprintf(stderr, "invalid arg for raw-rate\n");
373 return -1;
374 }
375 params->raw_rate = n;
376 break;
377 case OPT_RAW_FORMAT:
378 params->raw_format = optarg;
379 break;
380 case M4AF_TAG_TITLE:
381 case M4AF_TAG_ARTIST:
382 case M4AF_TAG_ALBUM:
383 case M4AF_TAG_GENRE:
384 case M4AF_TAG_DATE:
385 case M4AF_TAG_COMPOSER:
386 case M4AF_TAG_GROUPING:
387 case M4AF_TAG_COMMENT:
388 case M4AF_TAG_ALBUM_ARTIST:
389 case M4AF_TAG_TRACK:
390 case M4AF_TAG_DISK:
391 case M4AF_TAG_TEMPO:
392 aacenc_param_add_itmf_entry(&params->tags, ch, 0, optarg,
393 strlen(optarg), 0);
394 break;
395 case OPT_SHORT_TAG:
396 case OPT_SHORT_TAG_FILE:
397 case OPT_LONG_TAG:
398 {
399 char *val;
400 size_t klen;
401 unsigned fcc = M4AF_FOURCC('-','-','-','-');
402
403 if ((val = strchr(optarg, ':')) == 0) {
404 fprintf(stderr, "invalid arg for tag\n");
405 return -1;
406 }
407 *val++ = '\0';
408 if (ch == OPT_SHORT_TAG || ch == OPT_SHORT_TAG_FILE) {
409 /*
410 * take care of U+00A9(COPYRIGHT SIGN).
411 * 1) if length of fcc is 3, we prepend '\xa9'.
412 * 2) U+00A9 becomes "\xc2\xa9" in UTF-8. Therefore
413 * we remove first '\xc2'.
414 */
415 if (optarg[0] == '\xc2')
416 ++optarg;
417 if ((klen = strlen(optarg))== 3)
418 fcc = 0xa9;
419 else if (klen != 4) {
420 fprintf(stderr, "invalid arg for tag\n");
421 return -1;
422 }
423 for (; *optarg; ++optarg)
424 fcc = ((fcc << 8) | (*optarg & 0xff));
425 }
426 aacenc_param_add_itmf_entry(&params->tags, fcc, optarg,
427 val, strlen(val),
428 ch == OPT_SHORT_TAG_FILE);
429 }
430 break;
431 case OPT_TAG_FROM_JSON:
432 params->json_filename = optarg;
433 break;
434 default:
435 return usage(), -1;
436 }
437 }
438 if (argc == optind)
439 return usage(), -1;
440
441 if (!params->bitrate && !params->bitrate_mode) {
442 fprintf(stderr, "bitrate or bitrate-mode is mandatory\n");
443 return -1;
444 }
445 if (params->output_filename && !strcmp(params->output_filename, "-") &&
446 !params->transport_format) {
447 fprintf(stderr, "stdout streaming is not available on M4A output\n");
448 return -1;
449 }
450 if (params->bitrate && params->bitrate < 10000)
451 params->bitrate *= 1000;
452
453 if (params->is_raw) {
454 if (!params->raw_channels)
455 params->raw_channels = 2;
456 if (!params->raw_rate)
457 params->raw_rate = 44100;
458 if (!params->raw_format)
459 params->raw_format = "S16L";
460 }
461 params->input_filename = argv[optind];
462 return 0;
463};
464
465static
466int write_sample(FILE *ofp, m4af_ctx_t *m4af,
467 const void *data, uint32_t size, uint32_t duration)
468{
469 if (!m4af) {
470 fwrite(data, 1, size, ofp);
471 if (ferror(ofp)) {
472 fprintf(stderr, "ERROR: fwrite(): %s\n", strerror(errno));
473 return -1;
474 }
475 } else if (m4af_write_sample(m4af, 0, data, size, duration) < 0) {
476 fprintf(stderr, "ERROR: failed to write m4a sample\n");
477 return -1;
478 }
479 return 0;
480}
481
482static
483int encode(wav_reader_t *wavf, HANDLE_AACENCODER encoder,
484 uint32_t frame_length, FILE *ofp, m4af_ctx_t *m4af,
485 int show_progress)
486{
487 uint8_t *ibuf = 0;
488 int16_t *pcmbuf = 0;
489 uint32_t pcmsize = 0;
490 uint8_t *obuf = 0;
491 uint32_t olen;
492 uint32_t osize = 0;
493 int nread = 1;
494 int consumed;
495 int rc = -1;
496 int frames_written = 0;
497 aacenc_progress_t progress = { 0 };
498 const pcm_sample_description_t *format = wav_get_format(wavf);
499
500 ibuf = malloc(frame_length * format->bytes_per_frame);
501 aacenc_progress_init(&progress, wav_get_length(wavf), format->sample_rate);
502 do {
503 if (g_interrupted)
504 nread = 0;
505 else if (nread) {
506 if ((nread = wav_read_frames(wavf, ibuf, frame_length)) < 0) {
507 fprintf(stderr, "ERROR: read failed\n");
508 goto END;
509 } else if (nread > 0) {
510 if (pcm_convert_to_native_sint16(format, ibuf, nread,
511 &pcmbuf, &pcmsize) < 0) {
512 fprintf(stderr, "ERROR: unsupported sample format\n");
513 goto END;
514 }
515 }
516 if (show_progress)
517 aacenc_progress_update(&progress, wav_get_position(wavf),
518 format->sample_rate * 2);
519 }
520 if ((consumed = aac_encode_frame(encoder, format, pcmbuf, nread,
521 &obuf, &olen, &osize)) < 0)
522 goto END;
523 if (olen > 0) {
524 if (write_sample(ofp, m4af, obuf, olen, frame_length) < 0)
525 goto END;
526 ++frames_written;
527 }
528 } while (nread > 0 || olen > 0);
529
530 if (show_progress)
531 aacenc_progress_finish(&progress, wav_get_position(wavf));
532 rc = frames_written;
533END:
534 if (ibuf) free(ibuf);
535 if (pcmbuf) free(pcmbuf);
536 if (obuf) free(obuf);
537 return rc;
538}
539
540static
541void put_tool_tag(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
542 HANDLE_AACENCODER encoder)
543{
544 char tool_info[256];
545 char *p = tool_info;
546 LIB_INFO *lib_info = 0;
547
548 p += sprintf(p, PROGNAME " %s, ", fdkaac_version);
549
550 lib_info = calloc(FDK_MODULE_LAST, sizeof(LIB_INFO));
551 if (aacEncGetLibInfo(lib_info) == AACENC_OK) {
552 int i;
553 for (i = 0; i < FDK_MODULE_LAST; ++i)
554 if (lib_info[i].module_id == FDK_AACENC)
555 break;
556 p += sprintf(p, "libfdk-aac %s, ", lib_info[i].versionStr);
557 }
558 free(lib_info);
559 if (params->bitrate_mode)
560 sprintf(p, "VBR mode %d", params->bitrate_mode);
561 else
562 sprintf(p, "CBR %dkbps",
563 aacEncoder_GetParam(encoder, AACENC_BITRATE) / 1000);
564
565 m4af_add_itmf_string_tag(m4af, M4AF_TAG_TOOL, tool_info);
566}
567
568static
569int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params,
570 HANDLE_AACENCODER encoder)
571{
572 unsigned i;
573 aacenc_tag_entry_t *tag = params->tags.tag_table;
574
575 if (params->json_filename)
576 aacenc_put_tags_from_json(m4af, params->json_filename);
577
578 for (i = 0; i < params->tags.tag_count; ++i, ++tag)
579 aacenc_put_tag_entry(m4af, tag);
580
581 put_tool_tag(m4af, params, encoder);
582
583 if (m4af_finalize(m4af) < 0) {
584 fprintf(stderr, "ERROR: failed to finalize m4a\n");
585 return -1;
586 }
587 return 0;
588}
589
590static
591char *generate_output_filename(const char *filename, const char *ext)
592{
593 char *p = 0;
594 size_t ext_len = strlen(ext);
595
596 if (strcmp(filename, "-") == 0) {
597 p = malloc(ext_len + 6);
598 sprintf(p, "stdin%s", ext);
599 } else {
600 const char *base = aacenc_basename(filename);
601 size_t ilen = strlen(base);
602 const char *ext_org = strrchr(base, '.');
603 if (ext_org) ilen = ext_org - base;
604 p = malloc(ilen + ext_len + 1);
605 sprintf(p, "%.*s%s", ilen, base, ext);
606 }
607 return p;
608}
609
610static
611int parse_raw_spec(const char *spec, pcm_sample_description_t *desc)
612{
613 unsigned bits;
614 unsigned char c_type, c_endian = 'L';
615 int type;
616
617 if (sscanf(spec, "%c%u%c", &c_type, &bits, &c_endian) < 2)
618 return -1;
619 c_type = toupper(c_type);
620 c_endian = toupper(c_endian);
621
622 if (c_type == 'S')
623 type = 1;
624 else if (c_type == 'U')
625 type = 2;
626 else if (c_type == 'F')
627 type = 4;
628 else
629 return -1;
630
631 if (c_endian == 'B')
632 type |= 8;
633 else if (c_endian != 'L')
634 return -1;
635
636 if (c_type == 'F' && bits != 32 && bits != 64)
637 return -1;
638 if (c_type != 'F' && (bits < 8 || bits > 32))
639 return -1;
640
641 desc->sample_type = type;
642 desc->bits_per_channel = bits;
643 return 0;
644}
645
646int main(int argc, char **argv)
647{
648 wav_io_context_t wav_io = { read_callback, seek_callback, tell_callback };
649 m4af_io_callbacks_t
650 m4af_io = { 0, write_callback, seek_callback, tell_callback };
651 aacenc_param_ex_t params = { 0 };
652
653 int result = 2;
654 FILE *ifp = 0;
655 FILE *ofp = 0;
656 char *output_filename = 0;
657 wav_reader_t *wavf = 0;
658 HANDLE_AACENCODER encoder = 0;
659 AACENC_InfoStruct aacinfo = { 0 };
660 m4af_ctx_t *m4af = 0;
661 const pcm_sample_description_t *sample_format;
662 int downsampled_timescale = 0;
663 int frame_count = 0;
664 struct stat stb = { 0 };
665
666 setlocale(LC_CTYPE, "");
667 setbuf(stderr, 0);
668
669 if (parse_options(argc, argv, &params) < 0)
670 return 1;
671
672 if ((ifp = aacenc_fopen(params.input_filename, "rb")) == 0) {
673 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.input_filename,
674 strerror(errno));
675 goto END;
676 }
677 if (fstat(fileno(ifp), &stb) == 0 && (stb.st_mode & S_IFMT) != S_IFREG) {
678 wav_io.seek = 0;
679 wav_io.tell = 0;
680 }
681 if (!params.is_raw) {
682 if ((wavf = wav_open(&wav_io, ifp, params.ignore_length)) == 0) {
683 fprintf(stderr, "ERROR: broken / unsupported input file\n");
684 goto END;
685 }
686 } else {
687 int bytes_per_channel;
688 pcm_sample_description_t desc = { 0 };
689 if (parse_raw_spec(params.raw_format, &desc) < 0) {
690 fprintf(stderr, "ERROR: invalid raw-format spec\n");
691 goto END;
692 }
693 desc.sample_rate = params.raw_rate;
694 desc.channels_per_frame = params.raw_channels;
695 bytes_per_channel = (desc.bits_per_channel + 7) / 8;
696 desc.bytes_per_frame = params.raw_channels * bytes_per_channel;
697 if ((wavf = raw_open(&wav_io, ifp, &desc)) == 0) {
698 fprintf(stderr, "ERROR: failed to open raw input\n");
699 goto END;
700 }
701 }
702 sample_format = wav_get_format(wavf);
703
704 if (aacenc_init(&encoder, (aacenc_param_t*)&params, sample_format,
705 &aacinfo) < 0)
706 goto END;
707
708 if (!params.output_filename) {
709 const char *ext = params.transport_format ? ".aac" : ".m4a";
710 output_filename = generate_output_filename(params.input_filename, ext);
711 params.output_filename = output_filename;
712 }
713
714 if ((ofp = aacenc_fopen(params.output_filename, "wb")) == 0) {
715 aacenc_fprintf(stderr, "ERROR: %s: %s\n", params.output_filename,
716 strerror(errno));
717 goto END;
718 }
719 handle_signals();
720 if (!params.transport_format) {
721 uint32_t scale;
722 unsigned framelen = aacinfo.frameLength;
723 int sbr_mode = aacenc_is_sbr_active((aacenc_param_t*)&params);
724 int sig_mode = aacEncoder_GetParam(encoder, AACENC_SIGNALING_MODE);
725 if (sbr_mode && !sig_mode)
726 downsampled_timescale = 1;
727 scale = sample_format->sample_rate >> downsampled_timescale;
728 if ((m4af = m4af_create(M4AF_CODEC_MP4A, scale, &m4af_io, ofp)) < 0)
729 goto END;
730 m4af_set_decoder_specific_info(m4af, 0, aacinfo.confBuf,
731 aacinfo.confSize);
732 m4af_set_fixed_frame_duration(m4af, 0,
733 framelen >> downsampled_timescale);
734 m4af_set_priming_mode(m4af, params.gapless_mode + 1);
735 m4af_begin_write(m4af);
736 }
737 frame_count = encode(wavf, encoder, aacinfo.frameLength, ofp, m4af,
738 !params.silent);
739 if (frame_count < 0)
740 goto END;
741 if (m4af) {
742 uint32_t delay = aacinfo.encoderDelay;
743 int64_t frames_read = wav_get_position(wavf);
744 uint32_t padding = frame_count * aacinfo.frameLength
745 - frames_read - aacinfo.encoderDelay;
746 m4af_set_priming(m4af, 0, delay >> downsampled_timescale,
747 padding >> downsampled_timescale);
748 if (finalize_m4a(m4af, &params, encoder) < 0)
749 goto END;
750 }
751 result = 0;
752END:
753 if (wavf) wav_teardown(&wavf);
754 if (ifp) fclose(ifp);
755 if (m4af) m4af_teardown(&m4af);
756 if (ofp) fclose(ofp);
757 if (encoder) aacEncClose(&encoder);
758 if (output_filename) free(output_filename);
759 if (params.tags.tag_table) free(params.tags.tag_table);
760
761 return result;
762}
This page took 0.011535 seconds and 4 git commands to generate.