Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / vorbis-tools / oggenc / oggenc.c
blobb637853e2eec18e817816ba7cfb4162f45a11bb5
1 /* OggEnc
3 * This program is distributed under the GNU General Public License, version 2.
4 * A copy of this license is included with this source.
6 * Copyright 2000-2005, Michael Smith <msmith@xiph.org>
8 * Portions from Vorbize, (c) Kenneth Arnold <kcarnold-xiph@arnoldnet.net>
9 * and libvorbis examples, (c) Monty <monty@xiph.org>
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <math.h>
19 #include <getopt.h>
20 #include <string.h>
21 #include <time.h>
22 #include <locale.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #if defined WIN32 || defined _WIN32
27 #include <process.h>
28 #endif
30 #include "platform.h"
31 #include "encode.h"
32 #include "audio.h"
33 #include "utf8.h"
34 #include "i18n.h"
36 /* fallback for stand-alone compiles */
37 #ifndef PACKAGE
38 # define PACKAGE "oggenc"
39 #endif
40 #ifndef VERSION
41 # define VERSION "unknown"
42 #endif
44 #define CHUNK 4096 /* We do reads, etc. in multiples of this */
46 struct option long_options[] = {
47 {"quiet",0,0,'Q'},
48 {"help",0,0,'h'},
49 {"skeleton",no_argument,NULL, 'k'},
50 {"comment",1,0,'c'},
51 {"artist",1,0,'a'},
52 {"album",1,0,'l'},
53 {"title",1,0,'t'},
54 {"genre",1,0,'G'},
55 {"names",1,0,'n'},
56 {"name-remove",1,0,'X'},
57 {"name-replace",1,0,'P'},
58 {"output",1,0,'o'},
59 {"version",0,0,'V'},
60 {"raw",0,0,'r'},
61 {"raw-bits",1,0,'B'},
62 {"raw-chan",1,0,'C'},
63 {"raw-rate",1,0,'R'},
64 {"raw-endianness",1,0, 0},
65 {"bitrate",1,0,'b'},
66 {"min-bitrate",1,0,'m'},
67 {"max-bitrate",1,0,'M'},
68 {"quality",1,0,'q'},
69 {"date",1,0,'d'},
70 {"tracknum",1,0,'N'},
71 {"serial",1,0,'s'},
72 {"managed", 0, 0, 0},
73 {"resample",1,0,0},
74 {"downmix", 0,0,0},
75 {"scale", 1, 0, 0},
76 {"advanced-encode-option", 1, 0, 0},
77 {"discard-comments", 0, 0, 0},
78 {"utf8", 0,0,0},
79 {"ignorelength", 0, 0, 0},
80 {"lyrics",1,0,'L'},
81 {"lyrics-language",1,0,'Y'},
82 {NULL,0,0,0}
85 static char *generate_name_string(char *format, char *remove_list,
86 char *replace_list, char *artist, char *title, char *album,
87 char *track, char *date, char *genre);
88 static void parse_options(int argc, char **argv, oe_options *opt);
89 static void build_comments(vorbis_comment *vc, oe_options *opt, int filenum,
90 char **artist,char **album, char **title, char **tracknum, char **date,
91 char **genre);
92 static void usage(void);
94 int main(int argc, char **argv)
96 /* Default values */
97 oe_options opt = {
98 NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
99 NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
100 1, 0, 0, 0,
101 16,44100,2, 0,
102 NULL, DEFAULT_NAMEFMT_REMOVE, DEFAULT_NAMEFMT_REPLACE,
103 NULL,
104 0, -1,-1,-1,
105 .3,-1,
106 0,0,0.f,
107 0, 0, 0, 0, 0};
108 input_format raw_format = {NULL, 0, raw_open, wav_close, "raw",
109 N_("RAW file reader")};
111 int i;
113 char **infiles;
114 int numfiles;
115 int errors=0;
117 get_args_from_ucs16(&argc, &argv);
119 setlocale(LC_ALL, "");
120 bindtextdomain(PACKAGE, LOCALEDIR);
121 textdomain(PACKAGE);
123 parse_options(argc, argv, &opt);
125 if(optind >= argc)
127 fprintf(stderr, _("ERROR: No input files specified. Use -h for help.\n"));
128 return 1;
130 else
132 infiles = argv + optind;
133 numfiles = argc - optind;
136 /* Now, do some checking for illegal argument combinations */
138 for(i = 0; i < numfiles; i++)
140 if(!strcmp(infiles[i], "-") && numfiles > 1)
142 fprintf(stderr, _("ERROR: Multiple files specified when using stdin\n"));
143 exit(1);
147 if(numfiles > 1 && opt.outfile)
149 fprintf(stderr, _("ERROR: Multiple input files with specified output filename: suggest using -n\n"));
150 exit(1);
153 if(!opt.fixedserial)
155 /* We randomly pick a serial number. This is then incremented for each
156 file. The random seed includes the PID so two copies of oggenc that
157 start in the same second will generate different serial numbers. */
158 srand(time(NULL) ^ getpid());
159 opt.serial = rand();
161 opt.skeleton_serial = opt.serial + numfiles;
162 opt.kate_serial = opt.skeleton_serial + numfiles;
164 for(i = 0; i < numfiles; i++)
166 /* Once through the loop for each file */
168 oe_enc_opt enc_opts;
169 vorbis_comment vc;
170 char *out_fn = NULL;
171 FILE *in, *out = NULL;
172 int foundformat = 0;
173 int closeout = 0, closein = 0;
174 char *artist=NULL, *album=NULL, *title=NULL, *track=NULL;
175 char *date=NULL, *genre=NULL;
176 char *lyrics=NULL, *lyrics_language=NULL;
177 input_format *format;
178 int resampled = 0;
180 /* Set various encoding defaults */
182 enc_opts.serialno = opt.serial++;
183 enc_opts.skeleton_serialno = opt.skeleton_serial++;
184 enc_opts.kate_serialno = opt.kate_serial++;
185 enc_opts.progress_update = update_statistics_full;
186 enc_opts.start_encode = start_encode_full;
187 enc_opts.end_encode = final_statistics;
188 enc_opts.error = encode_error;
189 enc_opts.comments = &vc;
190 enc_opts.copy_comments = opt.copy_comments;
191 enc_opts.with_skeleton = opt.with_skeleton;
192 enc_opts.ignorelength = opt.ignorelength;
194 /* OK, let's build the vorbis_comments structure */
195 build_comments(&vc, &opt, i, &artist, &album, &title, &track,
196 &date, &genre);
198 if(opt.lyrics_count)
200 if(i >= opt.lyrics_count)
202 lyrics = NULL;
204 else
205 lyrics = opt.lyrics[i];
208 if(opt.lyrics_language_count)
210 if(i >= opt.lyrics_language_count)
212 if(!opt.quiet)
213 fprintf(stderr, _("WARNING: Insufficient lyrics languages specified, defaulting to final lyrics language.\n"));
214 lyrics_language = opt.lyrics_language[opt.lyrics_language_count-1];
216 else
217 lyrics_language = opt.lyrics_language[i];
220 if(!strcmp(infiles[i], "-"))
222 setbinmode(stdin);
223 in = stdin;
224 infiles[i] = NULL;
225 if(!opt.outfile)
227 setbinmode(stdout);
228 out = stdout;
231 else
233 in = oggenc_fopen(infiles[i], "rb", opt.isutf8);
235 if(in == NULL)
237 fprintf(stderr, _("ERROR: Cannot open input file \"%s\": %s\n"), infiles[i], strerror(errno));
238 free(out_fn);
239 errors++;
240 continue;
243 closein = 1;
246 /* Now, we need to select an input audio format - we do this before opening
247 the output file so that we don't end up with a 0-byte file if the input
248 file can't be read */
250 if(opt.rawmode)
253 enc_opts.rate=opt.raw_samplerate;
254 enc_opts.channels=opt.raw_channels;
255 enc_opts.samplesize=opt.raw_samplesize;
256 enc_opts.endianness=opt.raw_endianness;
258 format = &raw_format;
259 format->open_func(in, &enc_opts, NULL, 0);
260 foundformat=1;
262 else
264 format = open_audio_file(in, &enc_opts);
265 if(format)
267 if(!opt.quiet)
268 fprintf(stderr, _("Opening with %s module: %s\n"),
269 format->format, format->description);
270 foundformat=1;
275 if(!foundformat)
277 fprintf(stderr, _("ERROR: Input file \"%s\" is not a supported format\n"), infiles[i]?infiles[i]:"(stdin)");
278 if(closein)
279 fclose(in);
280 errors++;
281 continue;
284 if(enc_opts.rate <= 0)
286 fprintf(stderr, _("ERROR: Input file \"%s\" has invalid sampling rate\n"), infiles[i]?infiles[i]:"(stdin)");
287 if(closein)
288 fclose(in);
289 errors++;
290 continue;
293 /* Ok. We can read the file - so now open the output file */
295 if(opt.outfile && !strcmp(opt.outfile, "-"))
297 setbinmode(stdout);
298 out = stdout;
300 else if(out == NULL)
302 if(opt.outfile)
304 out_fn = strdup(opt.outfile);
306 else if(opt.namefmt)
308 out_fn = generate_name_string(opt.namefmt, opt.namefmt_remove,
309 opt.namefmt_replace, artist, title, album, track,date,
310 genre);
312 /* This bit was widely derided in mid-2002, so it's been removed */
314 else if(opt.title)
316 out_fn = malloc(strlen(title) + 5);
317 strcpy(out_fn, title);
318 strcat(out_fn, ".ogg");
321 else if(infiles[i])
323 /* Create a filename from existing filename, replacing extension with .ogg or .oga */
324 char *start, *end;
325 char *extension;
327 /* if adding Skeleton or Kate, we're not Vorbis I anymore */
328 extension = (opt.with_skeleton || opt.lyrics_count>0) ? ".oga" : ".ogg";
330 start = infiles[i];
331 end = strrchr(infiles[i], '.');
332 end = end?end:(start + strlen(infiles[i])+1);
334 out_fn = malloc(end - start + 5);
335 strncpy(out_fn, start, end-start);
336 out_fn[end-start] = 0;
337 strcat(out_fn, extension);
339 else {
340 /* if adding skeleton or kate, we're not Vorbis I anymore */
341 if (opt.with_skeleton || opt.lyrics_count>0)
342 out_fn = strdup("default.oga");
343 else
344 out_fn = strdup("default.ogg");
345 fprintf(stderr, _("WARNING: No filename, defaulting to \"%s\"\n"), out_fn);
348 /* Create any missing subdirectories, if possible */
349 if(create_directories(out_fn, opt.isutf8)) {
350 if(closein)
351 fclose(in);
352 fprintf(stderr, _("ERROR: Could not create required subdirectories for output filename \"%s\"\n"), out_fn);
353 errors++;
354 free(out_fn);
355 continue;
358 if(infiles[i] && !strcmp(infiles[i], out_fn)) {
359 fprintf(stderr, _("ERROR: Input filename is the same as output filename \"%s\"\n"), out_fn);
360 errors++;
361 free(out_fn);
362 continue;
365 out = oggenc_fopen(out_fn, "wb", opt.isutf8);
366 if(out == NULL)
368 if(closein)
369 fclose(in);
370 fprintf(stderr, _("ERROR: Cannot open output file \"%s\": %s\n"), out_fn, strerror(errno));
371 errors++;
372 free(out_fn);
373 continue;
375 closeout = 1;
378 /* Now, set the rest of the options */
379 enc_opts.out = out;
380 enc_opts.comments = &vc;
381 #ifdef _WIN32
382 if (opt.isutf8) {
383 enc_opts.filename = NULL;
384 enc_opts.infilename = NULL;
385 utf8_decode(out_fn, &enc_opts.filename);
386 utf8_decode(infiles[i], &enc_opts.infilename);
387 } else {
388 enc_opts.filename = strdup(out_fn);
389 enc_opts.infilename = strdup(infiles[i]);
391 #else
392 enc_opts.filename = out_fn;
393 enc_opts.infilename = infiles[i];
394 #endif
395 enc_opts.managed = opt.managed;
396 enc_opts.bitrate = opt.nominal_bitrate;
397 enc_opts.min_bitrate = opt.min_bitrate;
398 enc_opts.max_bitrate = opt.max_bitrate;
399 enc_opts.quality = opt.quality;
400 enc_opts.quality_set = opt.quality_set;
401 enc_opts.advopt = opt.advopt;
402 enc_opts.advopt_count = opt.advopt_count;
403 enc_opts.lyrics = lyrics;
404 enc_opts.lyrics_language = lyrics_language;
406 if(opt.resamplefreq && opt.resamplefreq != enc_opts.rate) {
407 int fromrate = enc_opts.rate;
409 resampled = 1;
410 enc_opts.resamplefreq = opt.resamplefreq;
411 if(setup_resample(&enc_opts)) {
412 errors++;
413 goto clear_all;
415 else if(!opt.quiet)
416 fprintf(stderr, _("Resampling input from %d Hz to %d Hz\n"), fromrate, opt.resamplefreq);
419 if(opt.downmix) {
420 if(enc_opts.channels == 2) {
421 setup_downmix(&enc_opts);
422 if(!opt.quiet)
423 fprintf(stderr, _("Downmixing stereo to mono\n"));
425 else {
426 fprintf(stderr, _("WARNING: Can't downmix except from stereo to mono\n"));
427 opt.downmix = 0;
431 if(opt.scale > 0.f) {
432 setup_scaler(&enc_opts, opt.scale);
433 if(!opt.quiet)
434 fprintf(stderr, _("Scaling input to %f\n"), opt.scale);
438 if(enc_opts.total_samples_per_channel <= 0)
439 enc_opts.progress_update = update_statistics_notime;
441 if(opt.quiet)
443 enc_opts.start_encode = start_encode_null;
444 enc_opts.progress_update = update_statistics_null;
445 enc_opts.end_encode = final_statistics_null;
448 if(oe_encode(&enc_opts))
449 errors++;
451 if(opt.scale > 0)
452 clear_scaler(&enc_opts);
453 if(opt.downmix)
454 clear_downmix(&enc_opts);
455 if(resampled)
456 clear_resample(&enc_opts);
457 clear_all:
459 if(out_fn) free(out_fn);
460 if(opt.outfile) free(opt.outfile);
461 #ifdef _WIN32
462 if(enc_opts.filename) free(enc_opts.filename);
463 if(enc_opts.infilename) free(enc_opts.infilename);
464 #endif
465 vorbis_comment_clear(&vc);
466 format->close_func(enc_opts.readdata);
468 if(closein)
469 fclose(in);
470 if(closeout)
471 fclose(out);
472 }/* Finished this file, loop around to next... */
474 return errors?1:0;
478 static void usage(void)
480 fprintf(stdout, _("oggenc from %s %s"), PACKAGE, VERSION);
481 fprintf(stdout, _(" by the Xiph.Org Foundation (http://www.xiph.org/)\n\n"));
482 fprintf(stdout, _("Usage: oggenc [options] inputfile [...]\n\n"));
483 fprintf(stdout, _("OPTIONS:\n"
484 " General:\n"
485 " -Q, --quiet Produce no output to stderr\n"
486 " -h, --help Print this help text\n"
487 " -V, --version Print the version number\n"));
488 fprintf(stdout, _(
489 " -k, --skeleton Adds an Ogg Skeleton bitstream\n"
490 " -r, --raw Raw mode. Input files are read directly as PCM data\n"
491 " -B, --raw-bits=n Set bits/sample for raw input; default is 16\n"
492 " -C, --raw-chan=n Set number of channels for raw input; default is 2\n"
493 " -R, --raw-rate=n Set samples/sec for raw input; default is 44100\n"
494 " --raw-endianness 1 for bigendian, 0 for little (defaults to 0)\n"));
495 fprintf(stdout, _(
496 " -b, --bitrate Choose a nominal bitrate to encode at. Attempt\n"
497 " to encode at a bitrate averaging this. Takes an\n"
498 " argument in kbps. By default, this produces a VBR\n"
499 " encoding, equivalent to using -q or --quality.\n"
500 " See the --managed option to use a managed bitrate\n"
501 " targetting the selected bitrate.\n"));
502 fprintf(stdout, _(
503 " --managed Enable the bitrate management engine. This will allow\n"
504 " much greater control over the precise bitrate(s) used,\n"
505 " but encoding will be much slower. Don't use it unless\n"
506 " you have a strong need for detailed control over\n"
507 " bitrate, such as for streaming.\n"));
508 fprintf(stdout, _(
509 " -m, --min-bitrate Specify a minimum bitrate (in kbps). Useful for\n"
510 " encoding for a fixed-size channel. Using this will\n"
511 " automatically enable managed bitrate mode (see\n"
512 " --managed).\n"
513 " -M, --max-bitrate Specify a maximum bitrate in kbps. Useful for\n"
514 " streaming applications. Using this will automatically\n"
515 " enable managed bitrate mode (see --managed).\n"));
516 fprintf(stdout, _(
517 " --advanced-encode-option option=value\n"
518 " Sets an advanced encoder option to the given value.\n"
519 " The valid options (and their values) are documented\n"
520 " in the man page supplied with this program. They are\n"
521 " for advanced users only, and should be used with\n"
522 " caution.\n"));
523 fprintf(stdout, _(
524 " -q, --quality Specify quality, between -1 (very low) and 10 (very\n"
525 " high), instead of specifying a particular bitrate.\n"
526 " This is the normal mode of operation.\n"
527 " Fractional qualities (e.g. 2.75) are permitted\n"
528 " The default quality level is 3.\n"));
529 fprintf(stdout, _(
530 " --resample n Resample input data to sampling rate n (Hz)\n"
531 " --downmix Downmix stereo to mono. Only allowed on stereo\n"
532 " input.\n"
533 " -s, --serial Specify a serial number for the stream. If encoding\n"
534 " multiple files, this will be incremented for each\n"
535 " stream after the first.\n"));
536 fprintf(stdout, _(
537 " --discard-comments Prevents comments in FLAC and Ogg FLAC files from\n"
538 " being copied to the output Ogg Vorbis file.\n"
539 " --ignorelength Ignore the datalength in Wave headers. This allows\n"
540 " support for files > 4GB and STDIN data streams. \n"
541 "\n"));
542 fprintf(stdout, _(
543 " Naming:\n"
544 " -o, --output=fn Write file to fn (only valid in single-file mode)\n"
545 " -n, --names=string Produce filenames as this string, with %%a, %%t, %%l,\n"
546 " %%n, %%d replaced by artist, title, album, track number,\n"
547 " and date, respectively (see below for specifying these).\n"
548 " %%%% gives a literal %%.\n"));
549 fprintf(stdout, _(
550 " -X, --name-remove=s Remove the specified characters from parameters to the\n"
551 " -n format string. Useful to ensure legal filenames.\n"
552 " -P, --name-replace=s Replace characters removed by --name-remove with the\n"
553 " characters specified. If this string is shorter than the\n"
554 " --name-remove list or is not specified, the extra\n"
555 " characters are just removed.\n"
556 " Default settings for the above two arguments are platform\n"
557 " specific.\n"));
558 fprintf(stdout, _(
559 " --utf8 Tells oggenc that the command line parameters date, title,\n"
560 " album, artist, genre, and comment are already in UTF-8.\n"
561 " On Windows, this switch applies to file names too.\n"
562 " -c, --comment=c Add the given string as an extra comment. This may be\n"
563 " used multiple times. The argument should be in the\n"
564 " format \"tag=value\".\n"
565 " -d, --date Date for track (usually date of performance)\n"));
566 fprintf(stdout, _(
567 " -N, --tracknum Track number for this track\n"
568 " -t, --title Title for this track\n"
569 " -l, --album Name of album\n"
570 " -a, --artist Name of artist\n"
571 " -G, --genre Genre of track\n"));
572 fprintf(stdout, _(
573 " -L, --lyrics Include lyrics from given file (.srt or .lrc format)\n"
574 " -Y, --lyrics-language Sets the language for the lyrics\n"));
575 fprintf(stdout, _(
576 " If multiple input files are given, then multiple\n"
577 " instances of the previous eight arguments will be used,\n"
578 " in the order they are given. If fewer titles are\n"
579 " specified than files, OggEnc will print a warning, and\n"
580 " reuse the final one for the remaining files. If fewer\n"
581 " track numbers are given, the remaining files will be\n"
582 " unnumbered. If fewer lyrics are given, the remaining\n"
583 " files will not have lyrics added. For the others, the\n"
584 " final tag will be reused for all others without warning\n"
585 " (so you can specify a date once, for example, and have\n"
586 " it used for all the files)\n"
587 "\n"));
588 fprintf(stdout, _(
589 "INPUT FILES:\n"
590 " OggEnc input files must currently be 24, 16, or 8 bit PCM Wave, AIFF, or AIFF/C\n"
591 " files, 32 bit IEEE floating point Wave, and optionally FLAC or Ogg FLAC. Files\n"
592 " may be mono or stereo (or more channels) and any sample rate.\n"
593 " Alternatively, the --raw option may be used to use a raw PCM data file, which\n"
594 " must be 16 bit stereo little-endian PCM ('headerless Wave'), unless additional\n"
595 " parameters for raw mode are specified.\n"
596 " You can specify taking the file from stdin by using - as the input filename.\n"
597 " In this mode, output is to stdout unless an output filename is specified\n"
598 " with -o\n"
599 " Lyrics files may be in SubRip (.srt) or LRC (.lrc) format\n"
600 "\n"));
603 static int strncpy_filtered(char *dst, char *src, int len, char *remove_list,
604 char *replace_list)
606 char *hit, *drop_margin;
607 int used=0;
609 if(remove_list == NULL || *remove_list == 0)
611 strncpy(dst, src, len-1);
612 dst[len-1] = 0;
613 return strlen(dst);
616 drop_margin = remove_list + (replace_list == NULL?0:strlen(replace_list));
618 while(*src && used < len-1)
620 if((hit = strchr(remove_list, *src)) != NULL)
622 if(hit < drop_margin)
624 *dst++ = replace_list[hit - remove_list];
625 used++;
628 else
630 *dst++ = *src;
631 used++;
633 src++;
635 *dst = 0;
637 return used;
640 static char *generate_name_string(char *format, char *remove_list,
641 char *replace_list, char *artist, char *title, char *album,
642 char *track, char *date, char *genre)
644 char *buffer;
645 char next;
646 char *string;
647 int used=0;
648 int buflen;
650 buffer = calloc(CHUNK+1,1);
651 buflen = CHUNK;
653 while(*format && used < buflen)
655 next = *format++;
657 if(next == '%')
659 switch(*format++)
661 case '%':
662 *(buffer+(used++)) = '%';
663 break;
664 case 'a':
665 string = artist?artist:_("(none)");
666 used += strncpy_filtered(buffer+used, string, buflen-used,
667 remove_list, replace_list);
668 break;
669 case 'd':
670 string = date?date:_("(none)");
671 used += strncpy_filtered(buffer+used, string, buflen-used,
672 remove_list, replace_list);
673 break;
674 case 'g':
675 string = genre?genre:_("(none)");
676 used += strncpy_filtered(buffer+used, string, buflen-used,
677 remove_list, replace_list);
678 break;
679 case 't':
680 string = title?title:_("(none)");
681 used += strncpy_filtered(buffer+used, string, buflen-used,
682 remove_list, replace_list);
683 break;
684 case 'l':
685 string = album?album:_("(none)");
686 used += strncpy_filtered(buffer+used, string, buflen-used,
687 remove_list, replace_list);
688 break;
689 case 'n':
690 string = track?track:_("(none)");
691 used += strncpy_filtered(buffer+used, string, buflen-used,
692 remove_list, replace_list);
693 break;
694 default:
695 fprintf(stderr, _("WARNING: Ignoring illegal escape character '%c' in name format\n"), *(format - 1));
696 break;
699 else
700 *(buffer + (used++)) = next;
703 return buffer;
706 static void parse_options(int argc, char **argv, oe_options *opt)
708 int ret;
709 int option_index = 1;
711 while((ret = getopt_long(argc, argv, "a:b:B:c:C:d:G:hkl:L:m:M:n:N:o:P:q:QrR:s:t:VX:Y:",
712 long_options, &option_index)) != -1)
714 switch(ret)
716 case 0:
717 if(!strcmp(long_options[option_index].name, "skeleton")) {
718 opt->with_skeleton = 1;
720 else if(!strcmp(long_options[option_index].name, "managed")) {
721 if(!opt->managed){
722 if(!opt->quiet)
723 fprintf(stderr,
724 _("Enabling bitrate management engine\n"));
725 opt->managed = 1;
728 else if(!strcmp(long_options[option_index].name,
729 "raw-endianness")) {
730 if (opt->rawmode != 1)
732 opt->rawmode = 1;
733 fprintf(stderr, _("WARNING: Raw endianness specified for non-raw data. Assuming input is raw.\n"));
735 if(sscanf(optarg, "%d", &opt->raw_endianness) != 1) {
736 fprintf(stderr, _("WARNING: Couldn't read endianness argument \"%s\"\n"), optarg);
737 opt->raw_endianness = 0;
740 else if(!strcmp(long_options[option_index].name,
741 "resample")) {
742 if(sscanf(optarg, "%d", &opt->resamplefreq) != 1) {
743 fprintf(stderr, _("WARNING: Couldn't read resampling frequency \"%s\"\n"), optarg);
744 opt->resamplefreq = 0;
746 if(opt->resamplefreq < 100) /* User probably specified it
747 in kHz accidently */
748 fprintf(stderr,
749 _("WARNING: Resample rate specified as %d Hz. Did you mean %d Hz?\n"),
750 opt->resamplefreq, opt->resamplefreq*1000);
752 else if(!strcmp(long_options[option_index].name, "downmix")) {
753 opt->downmix = 1;
755 else if(!strcmp(long_options[option_index].name, "scale")) {
756 opt->scale = atof(optarg);
757 if(sscanf(optarg, "%f", &opt->scale) != 1) {
758 opt->scale = 0;
759 fprintf(stderr, _("WARNING: Couldn't parse scaling factor \"%s\"\n"),
760 optarg);
763 else if(!strcmp(long_options[option_index].name, "utf8")) {
764 opt->isutf8 = 1;
766 else if(!strcmp(long_options[option_index].name, "advanced-encode-option")) {
767 char *arg = strdup(optarg);
768 char *val;
770 if(strcmp("disable_coupling",arg)){
771 val = strchr(arg, '=');
772 if(val == NULL) {
773 fprintf(stderr, _("No value for advanced encoder option found\n"));
774 continue;
776 else
777 *val++=0;
778 }else
779 val=0;
781 opt->advopt = realloc(opt->advopt, (++opt->advopt_count)*sizeof(adv_opt));
782 opt->advopt[opt->advopt_count - 1].arg = arg;
783 opt->advopt[opt->advopt_count - 1].val = val;
785 else if(!strcmp(long_options[option_index].name, "discard-comments")) {
786 opt->copy_comments = 0;
788 else if(!strcmp(long_options[option_index].name, "ignorelength")) {
789 opt->ignorelength = 1;
792 else {
793 fprintf(stderr, _("Internal error parsing command line options\n"));
794 exit(1);
797 break;
798 case 'a':
799 opt->artist = realloc(opt->artist, (++opt->artist_count)*sizeof(char *));
800 opt->artist[opt->artist_count - 1] = strdup(optarg);
801 break;
802 case 'c':
803 if(strchr(optarg, '=') == NULL) {
804 fprintf(stderr, _("WARNING: Illegal comment used (\"%s\"), ignoring.\n"), optarg);
805 break;
807 opt->comments = realloc(opt->comments, (++opt->comment_count)*sizeof(char *));
808 opt->comments[opt->comment_count - 1] = strdup(optarg);
809 break;
810 case 'd':
811 opt->dates = realloc(opt->dates, (++opt->date_count)*sizeof(char *));
812 opt->dates[opt->date_count - 1] = strdup(optarg);
813 break;
814 case 'G':
815 opt->genre = realloc(opt->genre, (++opt->genre_count)*sizeof(char *));
816 opt->genre[opt->genre_count - 1] = strdup(optarg);
817 break;
818 case 'h':
819 usage();
820 exit(0);
821 break;
822 case 'l':
823 opt->album = realloc(opt->album, (++opt->album_count)*sizeof(char *));
824 opt->album[opt->album_count - 1] = strdup(optarg);
825 break;
826 case 's':
827 /* Would just use atoi(), but that doesn't deal with unsigned
828 * ints. Damn */
829 if(sscanf(optarg, "%u", &opt->serial) != 1)
830 opt->serial = 0; /* Failed, so just set to zero */
831 else
832 opt->fixedserial = 1;
833 break;
834 case 't':
835 opt->title = realloc(opt->title, (++opt->title_count)*sizeof(char *));
836 opt->title[opt->title_count - 1] = strdup(optarg);
837 break;
838 case 'b':
839 if(sscanf(optarg, "%d", &opt->nominal_bitrate)
840 != 1) {
841 fprintf(stderr, _("WARNING: nominal bitrate \"%s\" not recognised\n"), optarg);
842 opt->nominal_bitrate = -1;
845 break;
846 case 'm':
847 if(sscanf(optarg, "%d", &opt->min_bitrate)
848 != 1) {
849 fprintf(stderr, _("WARNING: minimum bitrate \"%s\" not recognised\n"), optarg);
850 opt->min_bitrate = -1;
852 if(!opt->managed){
853 if(!opt->quiet)
854 fprintf(stderr,
855 _("Enabling bitrate management engine\n"));
856 opt->managed = 1;
858 break;
859 case 'M':
860 if(sscanf(optarg, "%d", &opt->max_bitrate)
861 != 1) {
862 fprintf(stderr, _("WARNING: maximum bitrate \"%s\" not recognised\n"), optarg);
863 opt->max_bitrate = -1;
865 if(!opt->managed){
866 if(!opt->quiet)
867 fprintf(stderr,
868 _("Enabling bitrate management engine\n"));
869 opt->managed = 1;
871 break;
872 case 'q':
873 if(sscanf(optarg, "%f", &opt->quality) != 1) {
874 fprintf(stderr, _("Quality option \"%s\" not recognised, ignoring\n"), optarg);
875 break;
877 opt->quality_set=1;
878 opt->quality *= 0.1;
879 if(opt->quality > 1.0f)
881 opt->quality = 1.0f;
882 fprintf(stderr, _("WARNING: quality setting too high, setting to maximum quality.\n"));
884 break;
885 case 'n':
886 if(opt->namefmt)
888 fprintf(stderr, _("WARNING: Multiple name formats specified, using final\n"));
889 free(opt->namefmt);
891 opt->namefmt = strdup(optarg);
892 break;
893 case 'X':
894 if(opt->namefmt_remove &&
895 strcmp(opt->namefmt_remove, DEFAULT_NAMEFMT_REMOVE))
897 fprintf(stderr, _("WARNING: Multiple name format filters specified, using final\n"));
898 free(opt->namefmt_remove);
900 opt->namefmt_remove = strdup(optarg);
901 break;
902 case 'P':
903 if(opt->namefmt_replace &&
904 strcmp(opt->namefmt_replace, DEFAULT_NAMEFMT_REPLACE))
906 fprintf(stderr, _("WARNING: Multiple name format filter replacements specified, using final\n"));
907 free(opt->namefmt_replace);
909 opt->namefmt_replace = strdup(optarg);
910 break;
911 case 'o':
912 if(opt->outfile)
914 fprintf(stderr, _("WARNING: Multiple output files specified, suggest using -n\n"));
915 free(opt->outfile);
917 opt->outfile = strdup(optarg);
918 break;
919 case 'Q':
920 opt->quiet = 1;
921 break;
922 case 'r':
923 opt->rawmode = 1;
924 break;
925 case 'V':
926 fprintf(stdout, _("oggenc from %s %s\n"), PACKAGE, VERSION);
927 exit(0);
928 break;
929 case 'B':
930 if (opt->rawmode != 1)
932 opt->rawmode = 1;
933 fprintf(stderr, _("WARNING: Raw bits/sample specified for non-raw data. Assuming input is raw.\n"));
935 if(sscanf(optarg, "%u", &opt->raw_samplesize) != 1)
937 opt->raw_samplesize = 16; /* Failed, so just set to 16 */
938 fprintf(stderr, _("WARNING: Invalid bits/sample specified, assuming 16.\n"));
940 if((opt->raw_samplesize != 8) && (opt->raw_samplesize != 16))
942 fprintf(stderr, _("WARNING: Invalid bits/sample specified, assuming 16.\n"));
944 break;
945 case 'C':
946 if (opt->rawmode != 1)
948 opt->rawmode = 1;
949 fprintf(stderr, _("WARNING: Raw channel count specified for non-raw data. Assuming input is raw.\n"));
951 if(sscanf(optarg, "%u", &opt->raw_channels) != 1)
953 opt->raw_channels = 2; /* Failed, so just set to 2 */
954 fprintf(stderr, _("WARNING: Invalid channel count specified, assuming 2.\n"));
956 break;
957 case 'N':
958 opt->tracknum = realloc(opt->tracknum, (++opt->track_count)*sizeof(char *));
959 opt->tracknum[opt->track_count - 1] = strdup(optarg);
960 break;
961 case 'R':
962 if (opt->rawmode != 1)
964 opt->rawmode = 1;
965 fprintf(stderr, _("WARNING: Raw sample rate specified for non-raw data. Assuming input is raw.\n"));
967 if(sscanf(optarg, "%u", &opt->raw_samplerate) != 1)
969 opt->raw_samplerate = 44100; /* Failed, so just set to 44100 */
970 fprintf(stderr, _("WARNING: Invalid sample rate specified, assuming 44100.\n"));
972 break;
973 case 'k':
974 opt->with_skeleton = 1;
975 break;
976 case 'L':
977 #ifdef HAVE_KATE
978 opt->lyrics = realloc(opt->lyrics, (++opt->lyrics_count)*sizeof(char *));
979 opt->lyrics[opt->lyrics_count - 1] = strdup(optarg);
980 opt->with_skeleton = 1;
981 #else
982 fprintf(stderr, _("WARNING: Kate support not compiled in; lyrics will not be included.\n"));
983 #endif
984 break;
985 case 'Y':
986 #ifdef HAVE_KATE
987 opt->lyrics_language = realloc(opt->lyrics_language, (++opt->lyrics_language_count)*sizeof(char *));
988 opt->lyrics_language[opt->lyrics_language_count - 1] = strdup(optarg);
989 if (strlen(opt->lyrics_language[opt->lyrics_language_count - 1]) > 15) {
990 fprintf(stderr, _("WARNING: language can not be longer than 15 characters; truncated.\n"));
991 opt->lyrics_language[opt->lyrics_language_count - 1][15] = 0;
993 #else
994 fprintf(stderr, _("WARNING: Kate support not compiled in; lyrics will not be included.\n"));
995 #endif
996 break;
997 case '?':
998 fprintf(stderr, _("WARNING: Unknown option specified, ignoring->\n"));
999 break;
1000 default:
1001 usage();
1002 exit(0);
1008 static void add_tag(vorbis_comment *vc, oe_options *opt,char *name, char *value)
1010 char *utf8;
1011 if (opt->isutf8)
1013 if (!utf8_validate(value)) {
1014 fprintf(stderr, _("'%s' is not valid UTF-8, cannot add\n"), name?name:"comment");
1015 } else {
1016 if(name == NULL)
1017 vorbis_comment_add(vc, value);
1018 else
1019 vorbis_comment_add_tag(vc, name, value);
1022 else if(utf8_encode(value, &utf8) >= 0)
1024 if(name == NULL)
1025 vorbis_comment_add(vc, utf8);
1026 else
1027 vorbis_comment_add_tag(vc, name, utf8);
1028 free(utf8);
1030 else
1031 fprintf(stderr, _("Couldn't convert comment to UTF-8, cannot add\n"));
1034 static void build_comments(vorbis_comment *vc, oe_options *opt, int filenum,
1035 char **artist, char **album, char **title, char **tracknum,
1036 char **date, char **genre)
1038 int i;
1040 vorbis_comment_init(vc);
1042 for(i = 0; i < opt->comment_count; i++)
1043 add_tag(vc, opt, NULL, opt->comments[i]);
1045 if(opt->title_count)
1047 if(filenum >= opt->title_count)
1049 if(!opt->quiet)
1050 fprintf(stderr, _("WARNING: Insufficient titles specified, defaulting to final title.\n"));
1051 i = opt->title_count-1;
1053 else
1054 i = filenum;
1056 *title = opt->title[i];
1057 add_tag(vc, opt, "title", opt->title[i]);
1060 if(opt->artist_count)
1062 if(filenum >= opt->artist_count)
1063 i = opt->artist_count-1;
1064 else
1065 i = filenum;
1067 *artist = opt->artist[i];
1068 add_tag(vc, opt, "artist", opt->artist[i]);
1071 if(opt->genre_count)
1073 if(filenum >= opt->genre_count)
1074 i = opt->genre_count-1;
1075 else
1076 i = filenum;
1078 *genre = opt->genre[i];
1079 add_tag(vc, opt, "genre", opt->genre[i]);
1082 if(opt->date_count)
1084 if(filenum >= opt->date_count)
1085 i = opt->date_count-1;
1086 else
1087 i = filenum;
1089 *date = opt->dates[i];
1090 add_tag(vc, opt, "date", opt->dates[i]);
1093 if(opt->album_count)
1095 if(filenum >= opt->album_count)
1097 i = opt->album_count-1;
1099 else
1100 i = filenum;
1102 *album = opt->album[i];
1103 add_tag(vc, opt, "album", opt->album[i]);
1106 if(filenum < opt->track_count)
1108 i = filenum;
1109 *tracknum = opt->tracknum[i];
1110 add_tag(vc, opt, "tracknumber", opt->tracknum[i]);