Beispiel #1
0
int opusEncoder(int argc, char **argv)
{
  static const input_format raw_format = {NULL, 0, raw_open, wav_close, "raw",N_("RAW file reader")};
  int option_index=0;
  struct option long_options[] =
  {
    {"quiet", no_argument, NULL, 0},
    {"bitrate", required_argument, NULL, 0},
    {"hard-cbr",no_argument,NULL, 0},
    {"vbr",no_argument,NULL, 0},
    {"cvbr",no_argument,NULL, 0},
    {"comp", required_argument, NULL, 0},
    {"complexity", required_argument, NULL, 0},
    {"framesize", required_argument, NULL, 0},
    {"expect-loss", required_argument, NULL, 0},
    {"downmix-mono",no_argument,NULL, 0},
    {"downmix-stereo",no_argument,NULL, 0},
    {"no-downmix",no_argument,NULL, 0},
    {"max-delay", required_argument, NULL, 0},
    {"serial", required_argument, NULL, 0},
    {"save-range", required_argument, NULL, 0},
    {"set-ctl-int", required_argument, NULL, 0},
    {"help", no_argument, NULL, 0},
    {"raw", no_argument, NULL, 0},
    {"raw-bits", required_argument, NULL, 0},
    {"raw-rate", required_argument, NULL, 0},
    {"raw-chan", required_argument, NULL, 0},
    {"raw-endianness", required_argument, NULL, 0},
    {"ignorelength", no_argument, NULL, 0},
    {"rate", required_argument, NULL, 0},
    {"version", no_argument, NULL, 0},
    {"version-short", no_argument, NULL, 0},
    {"comment", required_argument, NULL, 0},
    {"artist", required_argument, NULL, 0},
    {"title", required_argument, NULL, 0},
    {"album", required_argument, NULL, 0},
    {"date", required_argument, NULL, 0},
    {"genre", required_argument, NULL, 0},
    {"picture", required_argument, NULL, 0},
    {"padding", required_argument, NULL, 0},
    {"discard-comments", no_argument, NULL, 0},
    {"discard-pictures", no_argument, NULL, 0},
    {0, 0, 0, 0}
  };
  int i, ret;
  int                cline_size;
  OpusMSEncoder      *st;
  const char         *opus_version;
  unsigned char      *packet;
  float              *input;
  /*I/O*/
  oe_enc_opt         inopt;
  const input_format *in_format;
  char               *inFile;
  char               *outFile;
  char               *range_file;
  FILE               *fin;
  FILE               *fout;
  FILE               *frange;
  ogg_stream_state   os;
  ogg_page           og;
  ogg_packet         op;
  ogg_int64_t        last_granulepos=0;
  ogg_int64_t        enc_granulepos=0;
  ogg_int64_t        original_samples=0;
  ogg_int32_t        id=-1;
  int                last_segments=0;
  int                eos=0;
  OpusHeader         header;
  char               ENCODER_string[1024];
  /*Counters*/
  opus_int64         nb_encoded=0;
  opus_int64         bytes_written=0;
  opus_int64         pages_out=0;
  opus_int64         total_bytes=0;
  opus_int64         total_samples=0;
  opus_int32         nbBytes;
  opus_int32         nb_samples;
  opus_int32         peak_bytes=0;
  opus_int32         min_bytes;
  time_t             start_time;
  time_t             stop_time;
  time_t             last_spin=0;
  int                last_spin_len=0;
  /*Settings*/
  int                quiet=0;
  int                max_frame_bytes;
  opus_int32         bitrate=-1;
  opus_int32         rate=48000;
  opus_int32         coding_rate=48000;
  opus_int32         frame_size=960;
  int                chan=2;
  int                with_hard_cbr=0;
  int                with_cvbr=0;
  int                expect_loss=0;
  int                complexity=10;
  int                downmix=0;
  int                *opt_ctls_ctlval;
  int                opt_ctls=0;
  int                max_ogg_delay=48000; /*48kHz samples*/
  int                seen_file_icons=0;
  int                comment_padding=512;
  int                serialno;
  opus_int32         lookahead=0;
#ifdef WIN_UNICODE
   int argc_utf8;
   char **argv_utf8;
#endif

   if(query_cpu_support()){
     fprintf(stderr,"\n\n** WARNING: This program was compiled with SSE%s\n",query_cpu_support()>1?"2":"");
     fprintf(stderr,"            but this CPU claims to lack these instructions. **\n\n");
   }

#ifdef WIN_UNICODE
   (void)argc;
   (void)argv;

   init_commandline_arguments_utf8(&argc_utf8, &argv_utf8);
#endif

  opt_ctls_ctlval=NULL;
  frange=NULL;
  range_file=NULL;
  in_format=NULL;
  inopt.channels=chan;
  inopt.rate=coding_rate=rate;
  /* 0 dB gain is recommended unless you know what you're doing */
  inopt.gain=0;
  inopt.samplesize=16;
  inopt.endianness=0;
  inopt.rawmode=0;
  inopt.ignorelength=0;
  inopt.copy_comments=1;
  inopt.copy_pictures=1;

  start_time = time(NULL);
  srand(((getpid()&65535)<<15)^start_time);
  serialno=rand();

  opus_version=opus_get_version_string();
  /*Vendor string should just be the encoder library,
    the ENCODER comment specifies the tool used.*/
  comment_init(&inopt.comments, &inopt.comments_length, opus_version);
//  snprintf(ENCODER_string, sizeof(ENCODER_string), "opusenc from %s %s",PACKAGE_NAME,PACKAGE_VERSION);
  comment_add(&inopt.comments, &inopt.comments_length, "ENCODER", ENCODER_string);

  /*Process command-line options*/
  cline_size=0;
  while(1){
    int c;
    int save_cmd=1;
    c=getopt_long(argc_utf8, argv_utf8, "hV",
                  long_options, &option_index);
    if(c==-1)
       break;

    switch(c){
      case 0:
        if(strcmp(long_options[option_index].name,"quiet")==0){
          quiet=1;
        }else if(strcmp(long_options[option_index].name,"bitrate")==0){
          bitrate=atof(optarg)*1000.;
        }else if(strcmp(long_options[option_index].name,"hard-cbr")==0){
          with_hard_cbr=1;
          with_cvbr=0;
        }else if(strcmp(long_options[option_index].name,"cvbr")==0){
          with_cvbr=1;
          with_hard_cbr=0;
        }else if(strcmp(long_options[option_index].name,"vbr")==0){
          with_cvbr=0;
          with_hard_cbr=0;
        }else if(strcmp(long_options[option_index].name,"help")==0){
          usage();
          return 0;//exit(0);
        }else if(strcmp(long_options[option_index].name,"version")==0){
          opustoolsversion(opus_version);
          return 0;//exit(0);
        }else if(strcmp(long_options[option_index].name,"version-short")==0){
          opustoolsversion_short(opus_version);
          return 0;//exit(0);
        }else if(strcmp(long_options[option_index].name,"ignorelength")==0){
          inopt.ignorelength=1;
        }else if(strcmp(long_options[option_index].name,"raw")==0){
          inopt.rawmode=1;
          save_cmd=0;
        }else if(strcmp(long_options[option_index].name,"raw-bits")==0){
          inopt.rawmode=1;
          inopt.samplesize=atoi(optarg);
          save_cmd=0;
          if(inopt.samplesize!=8&&inopt.samplesize!=16&&inopt.samplesize!=24){
            fprintf(stderr,"Invalid bit-depth: %s\n",optarg);
            fprintf(stderr,"--raw-bits must be one of 8,16, or 24\n");
            return 0;//exit(1);
          }
        }else if(strcmp(long_options[option_index].name,"raw-rate")==0){
          inopt.rawmode=1;
          inopt.rate=atoi(optarg);
          save_cmd=0;
        }else if(strcmp(long_options[option_index].name,"raw-chan")==0){
          inopt.rawmode=1;
          inopt.channels=atoi(optarg);
          save_cmd=0;
        }else if(strcmp(long_options[option_index].name,"raw-endianness")==0){
          inopt.rawmode=1;
          inopt.endianness=atoi(optarg);
          save_cmd=0;
        }else if(strcmp(long_options[option_index].name,"downmix-mono")==0){
          downmix=1;
        }else if(strcmp(long_options[option_index].name,"downmix-stereo")==0){
          downmix=2;
        }else if(strcmp(long_options[option_index].name,"no-downmix")==0){
          downmix=-1;
        }else if(strcmp(long_options[option_index].name,"expect-loss")==0){
          expect_loss=atoi(optarg);
          if(expect_loss>100||expect_loss<0){
            fprintf(stderr,"Invalid expect-loss: %s\n",optarg);
            fprintf(stderr,"Expected loss is a percent and must be 0-100.\n");
            return 0;//exit(1);
          }
        }else if(strcmp(long_options[option_index].name,"comp")==0 ||
                 strcmp(long_options[option_index].name,"complexity")==0){
          complexity=atoi(optarg);
          if(complexity>10||complexity<0){
            fprintf(stderr,"Invalid complexity: %s\n",optarg);
            fprintf(stderr,"Complexity must be 0-10.\n");
            return 0;//exit(1);
          }
        }else if(strcmp(long_options[option_index].name,"framesize")==0){
          if(strcmp(optarg,"2.5")==0)frame_size=120;
          else if(strcmp(optarg,"5")==0)frame_size=240;
          else if(strcmp(optarg,"10")==0)frame_size=480;
          else if(strcmp(optarg,"20")==0)frame_size=960;
          else if(strcmp(optarg,"40")==0)frame_size=1920;
          else if(strcmp(optarg,"60")==0)frame_size=2880;
          else{
            fprintf(stderr,"Invalid framesize: %s\n",optarg);
            fprintf(stderr,"Framesize must be 2.5, 5, 10, 20, 40, or 60.\n");
            return 0;//exit(1);
          }
        }else if(strcmp(long_options[option_index].name,"max-delay")==0){
          max_ogg_delay=floor(atof(optarg)*48.);
          if(max_ogg_delay<0||max_ogg_delay>48000){
            fprintf(stderr,"Invalid max-delay: %s\n",optarg);
            fprintf(stderr,"max-delay 0-1000 ms.\n");
            return 0;//exit(1);
          }
        }else if(strcmp(long_options[option_index].name,"serial")==0){
          serialno=atoi(optarg);
        }else if(strcmp(long_options[option_index].name,"set-ctl-int")==0){
          int len=strlen(optarg),target;
          char *spos,*tpos;
          spos=strchr(optarg,'=');
          if(len<3||spos==NULL||(spos-optarg)<1||(spos-optarg)>=len){
            fprintf(stderr, "Invalid set-ctl-int: %s\n", optarg);
            fprintf(stderr, "Syntax is --set-ctl-int intX=intY or\n");
            fprintf(stderr, "Syntax is --set-ctl-int intS:intX=intY\n");
            return 0;//exit(1);
          }
          tpos=strchr(optarg,':');
          if(tpos==NULL){
            target=-1;
            tpos=optarg-1;
          }else target=atoi(optarg);
          if((atoi(tpos+1)&1)!=0){
            fprintf(stderr, "Invalid set-ctl-int: %s\n", optarg);
            fprintf(stderr, "libopus set CTL values are even.\n");
            return 0;//exit(1);
          }
          if(opt_ctls==0)opt_ctls_ctlval=malloc(sizeof(int)*3);
          else opt_ctls_ctlval=realloc(opt_ctls_ctlval,sizeof(int)*(opt_ctls+1)*3);
          opt_ctls_ctlval[opt_ctls*3]=target;
          opt_ctls_ctlval[opt_ctls*3+1]=atoi(tpos+1);
          opt_ctls_ctlval[opt_ctls*3+2]=atoi(spos+1);
          opt_ctls++;
        }else if(strcmp(long_options[option_index].name,"save-range")==0){
          frange=fopen_utf8(optarg,"w");
          save_cmd=0;
          if(frange==NULL){
            perror(optarg);
            fprintf(stderr,"Could not open save-range file: %s\n",optarg);
            fprintf(stderr,"Must provide a writable file name.\n");
            return 0;//exit(1);
          }
          range_file=optarg;
        }else if(strcmp(long_options[option_index].name,"comment")==0){
          save_cmd=0;
          if(!strchr(optarg,'=')){
            fprintf(stderr, "Invalid comment: %s\n", optarg);
            fprintf(stderr, "Comments must be of the form name=value\n");
            return 0;//exit(1);
          }
          comment_add(&inopt.comments, &inopt.comments_length, NULL, optarg);
        }else if(strcmp(long_options[option_index].name,"artist")==0){
          save_cmd=0;
          comment_add(&inopt.comments, &inopt.comments_length, "artist", optarg);
        } else if(strcmp(long_options[option_index].name,"title")==0){
          save_cmd=0;
          comment_add(&inopt.comments, &inopt.comments_length, "title", optarg);
        } else if(strcmp(long_options[option_index].name,"album")==0){
          save_cmd=0;
          comment_add(&inopt.comments, &inopt.comments_length, "album", optarg);
        } else if(strcmp(long_options[option_index].name,"date")==0){
          save_cmd=0;
          comment_add(&inopt.comments, &inopt.comments_length, "date", optarg);
        } else if(strcmp(long_options[option_index].name,"genre")==0){
          save_cmd=0;
          comment_add(&inopt.comments, &inopt.comments_length, "genre", optarg);
        } else if(strcmp(long_options[option_index].name,"picture")==0){
          const char *error_message;
          char       *picture_data;
          save_cmd=0;
          picture_data=parse_picture_specification(optarg,&error_message,
                                                   &seen_file_icons);
          if(picture_data==NULL){
            fprintf(stderr,"Error parsing picture option: %s\n",error_message);
            return 0;//exit(1);
          }
          comment_add(&inopt.comments,&inopt.comments_length,
                      "METADATA_BLOCK_PICTURE",picture_data);
          free(picture_data);
        } else if(strcmp(long_options[option_index].name,"padding")==0){
          comment_padding=atoi(optarg);
        } else if(strcmp(long_options[option_index].name,"discard-comments")==0){
          inopt.copy_comments=0;
          inopt.copy_pictures=0;
        } else if(strcmp(long_options[option_index].name,"discard-pictures")==0){
          inopt.copy_pictures=0;
        }
        /*Commands whos arguments would leak file paths or just end up as metadata
           should have save_cmd=0; to prevent them from being saved in the
           command-line tag.*/
        break;
      case 'h':
        usage();
        return 0;//exit(0);
        break;
      case 'V':
        opustoolsversion(opus_version);
        return 0;//exit(0);
        break;
      case '?':
        usage();
        return 0;//exit(1);
        break;
    }
    if(save_cmd && cline_size<(int)sizeof(ENCODER_string)){
      ret=snprintf(&ENCODER_string[cline_size], sizeof(ENCODER_string)-cline_size, "%s--%s",cline_size==0?"":" ",long_options[option_index].name);
      if(ret<0||ret>=((int)sizeof(ENCODER_string)-cline_size)){
        cline_size=sizeof(ENCODER_string);
      } else {
        cline_size+=ret;
        if(optarg){
          ret=snprintf(&ENCODER_string[cline_size], sizeof(ENCODER_string)-cline_size, " %s",optarg);
          if(ret<0||ret>=((int)sizeof(ENCODER_string)-cline_size)){
            cline_size=sizeof(ENCODER_string);
          } else {
            cline_size+=ret;
          }
        }
      }
    }
  }
  if(argc_utf8-optind!=2){
    usage();
    return 0;//exit(1);
  }
  inFile=argv_utf8[optind];
  outFile=argv_utf8[optind+1];

  if(cline_size>0)comment_add(&inopt.comments, &inopt.comments_length, "ENCODER_OPTIONS", ENCODER_string);

  if(strcmp(inFile, "-")==0){
#if defined WIN32 || defined _WIN32
    _setmode(_fileno(stdin), _O_BINARY);
#elif defined OS2
    _fsetmode(stdin,"b");
#endif
    fin=stdin;
  }else{
    fin=fopen_utf8(inFile, "rb");
    if(!fin){
      perror(inFile);
      return 0;//exit(1);
    }
  }

  if(inopt.rawmode){
    in_format = &raw_format;
    in_format->open_func(fin, &inopt, NULL, 0);
  }else in_format=open_audio_file(fin,&inopt);

  if(!in_format){
    fprintf(stderr,"Error parsing input file: %s\n",inFile);
    return 0;//exit(1);
  }

  if(downmix==0&&inopt.channels>2&&bitrate>0&&bitrate<(16000*inopt.channels)){
    if(!quiet)fprintf(stderr,"Notice: Surround bitrate less than 16kbit/sec/channel, downmixing.\n");
    downmix=inopt.channels>8?1:2;
  }

  if(downmix>0&&downmix<inopt.channels)downmix=setup_downmix(&inopt,downmix);
  else downmix=0;

  rate=inopt.rate;
  chan=inopt.channels;
  inopt.skip=0;

  /*In order to code the complete length we'll need to do a little padding*/
  setup_padder(&inopt,&original_samples);

  if(rate>24000)coding_rate=48000;
  else if(rate>16000)coding_rate=24000;
  else if(rate>12000)coding_rate=16000;
  else if(rate>8000)coding_rate=12000;
  else coding_rate=8000;

  frame_size=frame_size/(48000/coding_rate);

  /*Scale the resampler complexity, but only for 48000 output because
    the near-cutoff behavior matters a lot more at lower rates.*/
  //if(rate!=coding_rate)setup_resample(&inopt,coding_rate==48000?(complexity+1)/2:5,coding_rate);

  if(rate!=coding_rate&&complexity!=10&&!quiet){
    fprintf(stderr,"Notice: Using resampling with complexity<10.\n");
    fprintf(stderr,"Opusenc is fastest with 48, 24, 16, 12, or 8kHz input.\n\n");
  }

  /*OggOpus headers*/ /*FIXME: broke forcemono*/
  header.channels=chan;
  header.channel_mapping=header.channels>8?255:chan>2;
  header.input_sample_rate=rate;
  header.gain=inopt.gain;

  /*Initialize OPUS encoder*/
  /*Framesizes <10ms can only use the MDCT modes, so we switch on RESTRICTED_LOWDELAY
    to save the extra 2.5ms of codec lookahead when we'll be using only small frames.*/
  st=opus_multistream_surround_encoder_create(coding_rate, chan, header.channel_mapping, &header.nb_streams, &header.nb_coupled,
     header.stream_map, frame_size<480/(48000/coding_rate)?OPUS_APPLICATION_RESTRICTED_LOWDELAY:OPUS_APPLICATION_AUDIO, &ret);
  if(ret!=OPUS_OK){
    fprintf(stderr, "Error cannot create encoder: %s\n", opus_strerror(ret));
    return 0;//exit(1);
  }

  min_bytes=max_frame_bytes=(1275*3+7)*header.nb_streams;
  packet=malloc(sizeof(unsigned char)*max_frame_bytes);
  if(packet==NULL){
    fprintf(stderr,"Error allocating packet buffer.\n");
    return 0;//exit(1);
  }

  if(bitrate<0){
    /*Lower default rate for sampling rates [8000-44100) by a factor of (rate+16k)/(64k)*/
    bitrate=((64000*header.nb_streams+32000*header.nb_coupled)*
             (IMIN(48,IMAX(8,((rate<44100?rate:48000)+1000)/1000))+16)+32)>>6;
  }
Beispiel #2
0
int main(int argc, char **argv)
{
    /* Default values */
    oe_options opt = {
              NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
              NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
              1, 0, 0, 0,
              16,44100,2, 0,
              NULL, DEFAULT_NAMEFMT_REMOVE, DEFAULT_NAMEFMT_REPLACE,
              NULL,
              0, -1,-1,-1,
              .3,-1,
              0,0,0.f,
              0, 0, 0, 0, 0};
    input_format raw_format = {NULL, 0, raw_open, wav_close, "raw", 
      N_("RAW file reader")};

    int i;

    char **infiles;
    int numfiles;
    int errors=0;

    get_args_from_ucs16(&argc, &argv);

    setlocale(LC_ALL, "");
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);

    parse_options(argc, argv, &opt);

    if(optind >= argc)
    {
        fprintf(stderr, _("ERROR: No input files specified. Use -h for help.\n"));
        return 1;
    }
    else
    {
        infiles = argv + optind;
        numfiles = argc - optind;
    }

    /* Now, do some checking for illegal argument combinations */

    for(i = 0; i < numfiles; i++)
    {
        if(!strcmp(infiles[i], "-") && numfiles > 1)
        {
            fprintf(stderr, _("ERROR: Multiple files specified when using stdin\n"));
            exit(1);
        }
    }

    if(numfiles > 1 && opt.outfile)
    {
        fprintf(stderr, _("ERROR: Multiple input files with specified output filename: suggest using -n\n"));
        exit(1);
    }

    if(!opt.fixedserial)
    {
                /* We randomly pick a serial number. This is then incremented for each
                   file. The random seed includes the PID so two copies of oggenc that
                   start in the same second will generate different serial numbers. */
                srand(time(NULL) ^ getpid());
        opt.serial = rand();
    }
    opt.skeleton_serial = opt.serial + numfiles;
    opt.kate_serial = opt.skeleton_serial + numfiles;

    for(i = 0; i < numfiles; i++)
    {
        /* Once through the loop for each file */

        oe_enc_opt      enc_opts;
        vorbis_comment  vc;
        char *out_fn = NULL;
        FILE *in, *out = NULL;
        int foundformat = 0;
        int closeout = 0, closein = 0;
        char *artist=NULL, *album=NULL, *title=NULL, *track=NULL;
        char *date=NULL, *genre=NULL;
        char *lyrics=NULL, *lyrics_language=NULL;
        input_format *format;
        int resampled = 0;

        /* Set various encoding defaults */

        enc_opts.serialno = opt.serial++;
        enc_opts.skeleton_serialno = opt.skeleton_serial++;
        enc_opts.kate_serialno = opt.kate_serial++;
        enc_opts.progress_update = update_statistics_full;
        enc_opts.start_encode = start_encode_full;
        enc_opts.end_encode = final_statistics;
        enc_opts.error = encode_error;
        enc_opts.comments = &vc;
        enc_opts.copy_comments = opt.copy_comments;
        enc_opts.with_skeleton = opt.with_skeleton;
        enc_opts.ignorelength = opt.ignorelength;

        /* OK, let's build the vorbis_comments structure */
        build_comments(&vc, &opt, i, &artist, &album, &title, &track,
                &date, &genre);

        if(opt.lyrics_count)
        {
            if(i >= opt.lyrics_count)
            {
                lyrics = NULL;
            }
            else
                lyrics = opt.lyrics[i];
        }

        if(opt.lyrics_language_count)
        {
            if(i >= opt.lyrics_language_count)
            {
                if(!opt.quiet)
                    fprintf(stderr, _("WARNING: Insufficient lyrics languages specified, defaulting to final lyrics language.\n"));
                lyrics_language = opt.lyrics_language[opt.lyrics_language_count-1];
            }
            else
                lyrics_language = opt.lyrics_language[i];
        }

        if(!strcmp(infiles[i], "-"))
        {
            setbinmode(stdin);
            in = stdin;
            infiles[i] = NULL;
            if(!opt.outfile)
            {
                setbinmode(stdout);
                out = stdout;
            }
        }
        else
        {
            in = oggenc_fopen(infiles[i], "rb", opt.isutf8);

            if(in == NULL)
            {
                fprintf(stderr, _("ERROR: Cannot open input file \"%s\": %s\n"), infiles[i], strerror(errno));
                free(out_fn);
                errors++;
                continue;
            }

            closein = 1;
        }

        /* Now, we need to select an input audio format - we do this before opening
           the output file so that we don't end up with a 0-byte file if the input
           file can't be read */

        if(opt.rawmode)
        {

            enc_opts.rate=opt.raw_samplerate;
            enc_opts.channels=opt.raw_channels;
            enc_opts.samplesize=opt.raw_samplesize;
            enc_opts.endianness=opt.raw_endianness;

            format = &raw_format;
            format->open_func(in, &enc_opts, NULL, 0);
            foundformat=1;
        }
        else
        {
            format = open_audio_file(in, &enc_opts);
            if(format)
            {
                if(!opt.quiet)
                    fprintf(stderr, _("Opening with %s module: %s\n"),
                            format->format, format->description);
                foundformat=1;
            }

        }

        if(!foundformat)
        {
            fprintf(stderr, _("ERROR: Input file \"%s\" is not a supported format\n"), infiles[i]?infiles[i]:"(stdin)");
            if(closein)
                fclose(in);
            errors++;
            continue;
        }
        
        if(enc_opts.rate <= 0)
        {
            fprintf(stderr, _("ERROR: Input file \"%s\" has invalid sampling rate\n"), infiles[i]?infiles[i]:"(stdin)");
            if(closein)
                fclose(in);
            errors++;
            continue;
        }

        /* Ok. We can read the file - so now open the output file */

        if(opt.outfile && !strcmp(opt.outfile, "-"))
        {
            setbinmode(stdout);
            out = stdout;
        }
        else if(out == NULL)
        {
            if(opt.outfile)
            {
                out_fn = strdup(opt.outfile);
            }
            else if(opt.namefmt)
            {
                out_fn = generate_name_string(opt.namefmt, opt.namefmt_remove, 
                        opt.namefmt_replace, artist, title, album, track,date,
                        genre);
            }
            /* This bit was widely derided in mid-2002, so it's been removed */
            /*
            else if(opt.title)
            {
                out_fn = malloc(strlen(title) + 5);
                strcpy(out_fn, title);
                strcat(out_fn, ".ogg");
            }
            */
            else if(infiles[i])
            {
                /* Create a filename from existing filename, replacing extension with .ogg or .oga */
                char *start, *end;
                char *extension;

                /* if adding Skeleton or Kate, we're not Vorbis I anymore */
                extension = (opt.with_skeleton || opt.lyrics_count>0) ? ".oga" : ".ogg";

                start = infiles[i];
                end = strrchr(infiles[i], '.');
                end = end?end:(start + strlen(infiles[i])+1);

                out_fn = malloc(end - start + 5);
                strncpy(out_fn, start, end-start);
                out_fn[end-start] = 0;
                strcat(out_fn, extension);
            }
            else {
                /* if adding skeleton or kate, we're not Vorbis I anymore */
                if (opt.with_skeleton || opt.lyrics_count>0)
                    out_fn = strdup("default.oga");
                else
                    out_fn = strdup("default.ogg");
                fprintf(stderr, _("WARNING: No filename, defaulting to \"%s\"\n"), out_fn);
            }

            /* Create any missing subdirectories, if possible */
            if(create_directories(out_fn, opt.isutf8)) {
                if(closein)
                    fclose(in);
                fprintf(stderr, _("ERROR: Could not create required subdirectories for output filename \"%s\"\n"), out_fn);
                errors++;
                free(out_fn);
                continue;
            }

            if(infiles[i] && !strcmp(infiles[i], out_fn)) {
                fprintf(stderr, _("ERROR: Input filename is the same as output filename \"%s\"\n"), out_fn);
                errors++;
                free(out_fn);
                continue;
            }

            out = oggenc_fopen(out_fn, "wb", opt.isutf8);
            if(out == NULL)
            {
                if(closein)
                    fclose(in);
                fprintf(stderr, _("ERROR: Cannot open output file \"%s\": %s\n"), out_fn, strerror(errno));
                errors++;
                free(out_fn);
                continue;
            }
            closeout = 1;
        }

        /* Now, set the rest of the options */
        enc_opts.out = out;
        enc_opts.comments = &vc;
#ifdef _WIN32
        enc_opts.filename = NULL;
        enc_opts.infilename = NULL;

        if (opt.isutf8) {
            if (out_fn) {
                utf8_decode(out_fn, &enc_opts.filename);
            }
            if (infiles[i]) {
                utf8_decode(infiles[i], &enc_opts.infilename);
            }
        } else {
            if (out_fn) {
                enc_opts.filename = strdup(out_fn);
            }
            if (infiles[i]) {
                enc_opts.infilename = strdup(infiles[i]);
            }
        }
#else
        enc_opts.filename = out_fn;
        enc_opts.infilename = infiles[i];
#endif
        enc_opts.managed = opt.managed;
        enc_opts.bitrate = opt.nominal_bitrate; 
        enc_opts.min_bitrate = opt.min_bitrate;
        enc_opts.max_bitrate = opt.max_bitrate;
        enc_opts.quality = opt.quality;
        enc_opts.quality_set = opt.quality_set;
        enc_opts.advopt = opt.advopt;
        enc_opts.advopt_count = opt.advopt_count;
        enc_opts.lyrics = lyrics;
        enc_opts.lyrics_language = lyrics_language;

        if(opt.resamplefreq && opt.resamplefreq != enc_opts.rate) {
            int fromrate = enc_opts.rate;

            resampled = 1;
            enc_opts.resamplefreq = opt.resamplefreq;
            if(setup_resample(&enc_opts)) {
                errors++;
                goto clear_all;
            }
            else if(!opt.quiet) {
                fprintf(stderr, _("Resampling input from %d Hz to %d Hz\n"), fromrate, opt.resamplefreq);
            }
        }

        if(opt.downmix) {
            if(enc_opts.channels == 2) {
                setup_downmix(&enc_opts);
                if(!opt.quiet) {
                    fprintf(stderr, _("Downmixing stereo to mono\n"));
                }
            }
            else {
                fprintf(stderr, _("WARNING: Can't downmix except from stereo to mono\n"));
                opt.downmix = 0;
            }
        }

        if(opt.scale > 0.f) {
            setup_scaler(&enc_opts, opt.scale);
            if(!opt.quiet) {
                fprintf(stderr, _("Scaling input to %f\n"), opt.scale);
            }
        }


        if(enc_opts.total_samples_per_channel <= 0) {
            enc_opts.progress_update = update_statistics_notime;
        }

        if(opt.quiet)
        {
            enc_opts.start_encode = start_encode_null;
            enc_opts.progress_update = update_statistics_null;
            enc_opts.end_encode = final_statistics_null;
        }

        if(oe_encode(&enc_opts)) {
            errors++;
        }

        if(opt.scale > 0) {
            clear_scaler(&enc_opts);
        }
        if(opt.downmix) {
            clear_downmix(&enc_opts);
        }
        if(resampled) {
            clear_resample(&enc_opts);
        }
clear_all:

        if(out_fn) free(out_fn);
        if(opt.outfile) free(opt.outfile);
#ifdef _WIN32
        if(enc_opts.filename) free(enc_opts.filename);
        if(enc_opts.infilename) free(enc_opts.infilename);
#endif
        vorbis_comment_clear(&vc);
        format->close_func(enc_opts.readdata);

        if(closein) {
            fclose(in);
        }
        if(closeout) {
            fclose(out);
        }
    }/* Finished this file, loop around to next... */

    return errors?1:0;

}
Beispiel #3
0
int convert( const char* source_path, const char* target_path, int bitRate, int quality) {
	static const input_format raw_format = {NULL, 0, raw_open, wav_close, "raw",N_("RAW file reader")};
	int i, ret;
	int                cline_size;
	OpusMSEncoder      *st;
	const char         *opus_version;
	unsigned char      *packet;
#ifdef FIXED_POINT
	opus_int16         *input;
#else
	float              *input;
#endif
	/*I/O*/
	oe_enc_opt         inopt;
	const input_format *in_format;
	char               *range_file;
	FILE               *fin;
	FILE               *fout;
	FILE               *frange;
	ogg_stream_state   os;
	ogg_page           og;
	ogg_packet         op;
	ogg_int64_t        last_granulepos=0;
	ogg_int64_t        enc_granulepos=0;
	ogg_int64_t        original_samples=0;
	ogg_int32_t        id=-1;
	int                last_segments=0;
	int                eos=0;
	OpusHeader         header;
	char               ENCODER_string[1024];
	/*Counters*/
	opus_int64         nb_encoded=0;
	opus_int64         bytes_written=0;
	opus_int64         pages_out=0;
	opus_int64         total_bytes=0;
	opus_int64         total_samples=0;
	opus_int32         nbBytes;
	opus_int32         nb_samples;
	opus_int32         peak_bytes=0;
	opus_int32         min_bytes;
	time_t             start_time;
	time_t             stop_time;
	time_t             last_spin=0;
	int                last_spin_len=0;
	/*Settings*/
	int                quiet=0;
	int                max_frame_bytes;
	opus_int32         bitrate=bitRate * 1000;
	opus_int32         rate=48000;
	opus_int32         coding_rate=48000;
	opus_int32         frame_size=960;
	int                chan=2;
	int                with_hard_cbr=0;
	int                with_cvbr=0;
	int                expect_loss=0;
	int                complexity=10 - quality;	// 10 -- best
	int                downmix=0;
	int                *opt_ctls_ctlval;
	int                opt_ctls=0;
	int                max_ogg_delay=48000; // 48kHz samples
	int                seen_file_icons=0;
	int                comment_padding=512;
	int                serialno;
	opus_int32         lookahead=0;

	opt_ctls_ctlval=NULL;
	frange=NULL;
	range_file=NULL;
	in_format=NULL;
	inopt.channels=chan;
	inopt.rate=coding_rate=rate;
	// 0 dB gain is recommended unless you know what you're doing
	inopt.gain=0;
	inopt.samplesize=16;
	inopt.endianness=0;
	inopt.rawmode=0;
	inopt.ignorelength=0;
	inopt.copy_comments=1;

	start_time = time(NULL);
	srand(((getpid()&65535)<<15)^start_time);
	serialno=rand();

	opus_version= "libopus 1.1.1";	//opus_get_version_string();
	// Vendor string should just be the encoder library, the ENCODER comment specifies the tool used.
	if( comment_init(&inopt.comments, &inopt.comments_length, opus_version) ) {
		return 1;	// failed
	}
	snprintf(ENCODER_string, sizeof(ENCODER_string), "%s %s",PACKAGE_NAME,PACKAGE_VERSION);
	if( comment_add(&inopt.comments, &inopt.comments_length, "ENCODER", ENCODER_string) ) {
		return 1;	// failed
	}

	if(cline_size>0){
		if( comment_add(&inopt.comments, &inopt.comments_length, "ENCODER_OPTIONS", ENCODER_string) ) {
			return 1;	// failed
		}
	}

	fin=fopen_utf8(source_path, "rb");
	if(!fin){
		perror(source_path);
		return 1;
	}

	if(inopt.rawmode){
		in_format = &raw_format;
		in_format->open_func(fin, &inopt, NULL, 0);
	}else in_format=open_audio_file(fin,&inopt);

	if(!in_format){
		LOGD("Error parsing input file: %s\n",source_path);
		return 1;
	}

	if(downmix==0&&inopt.channels>2&&bitrate>0&&bitrate<(16000*inopt.channels)){
		if(!quiet)LOGD("Notice: Surround bitrate less than 16kbit/sec/channel, downmixing.\n");
		downmix=inopt.channels>8?1:2;
	}

	if(downmix>0&&downmix<inopt.channels)downmix=setup_downmix(&inopt,downmix);
	else downmix=0;

	rate=inopt.rate;
	chan=inopt.channels;
	inopt.skip=0;

	// In order to code the complete length we'll need to do a little padding
	setup_padder(&inopt,&original_samples);

	if(rate>24000)coding_rate=48000;
	else if(rate>16000)coding_rate=24000;
	else if(rate>12000)coding_rate=16000;
	else if(rate>8000)coding_rate=12000;
	else coding_rate=8000;

	frame_size=frame_size/(48000/coding_rate);

	// Scale the resampler complexity, but only for 48000 output because
    // the near-cutoff behavior matters a lot more at lower rates.
//	if(rate!=coding_rate)setup_resample(&inopt,coding_rate==48000?(complexity+1)/2:5,coding_rate);

	if(rate!=coding_rate&&complexity!=10&&!quiet){
		LOGD("Notice: Using resampling with complexity<10.\n");
		LOGD("Opusenc is fastest with 48, 24, 16, 12, or 8kHz input.\n\n");
	}

	// OggOpus headers // FIXME: broke forcemono
	header.channels=chan;
	header.channel_mapping=header.channels>8?255:chan>2;
	header.input_sample_rate=rate;
	header.gain=inopt.gain;

	// Initialize OPUS encoder
	st=opus_multistream_surround_encoder_create(coding_rate, chan, header.channel_mapping, &header.nb_streams, &header.nb_coupled,
			header.stream_map, OPUS_APPLICATION_AUDIO, &ret);
	if(ret!=OPUS_OK){
		LOGD( "Error cannot create encoder: %s\n", opus_strerror(ret));
		return 1;
	}

	min_bytes=max_frame_bytes=(1275*3+7)*header.nb_streams;
	packet=malloc(sizeof(unsigned char)*max_frame_bytes);
	if(packet==NULL){
		LOGD("Error allocating packet buffer.\n");
		return 1;
	}

	if(bitrate<0){
		// Lower default rate for sampling rates [8000-44100) by a factor of (rate+16k)/(64k)
		bitrate=((64000*header.nb_streams+32000*header.nb_coupled)*
				(IMIN(48,IMAX(8,((rate<44100?rate:48000)+1000)/1000))+16)+32)>>6;
	}