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