Example #1
0
static result_t
encode_opus_file(char *filename,
                 struct PCMReader *pcmreader,
                 int quality,
                 unsigned original_sample_rate)
{
    const int multichannel = (pcmreader->channels > 2);
    const unsigned channel_mapping = (pcmreader->channels > 8 ? 255 :
                                      pcmreader->channels > 2);
    int stream_count;
    int coupled_stream_count;
    unsigned char stream_map[255];

    int samples[BLOCK_SIZE * pcmreader->channels];
    unsigned pcm_frames;
    result_t result = ENCODE_OK;
    FILE *output_file = NULL;
    ogg_stream_state ogg_stream;
    ogg_page ogg_page;
    OpusEncoder *opus_encoder = NULL;
    OpusMSEncoder *opus_ms_encoder = NULL;
    int error;
    opus_int16 *opus_samples = NULL;
    unsigned char opus_frame[OPUS_FRAME_LEN];
    ogg_int64_t granulepos = 0;
    ogg_int64_t packetno = 0;
    opus_int32 preskip;

    /*open output file for writing*/
    if ((output_file = fopen(filename, "w+b")) == NULL) {
        return ERR_IOERROR;
    }

    if (!multichannel) {
        if ((opus_encoder = opus_encoder_create(48000,
                                                pcmreader->channels,
                                                OPUS_APPLICATION_AUDIO,
                                                &error)) == NULL) {
            fclose(output_file);
            return ERR_ENCODER_INIT;
        }

        opus_encoder_ctl(opus_encoder, OPUS_SET_COMPLEXITY(quality));
        opus_encoder_ctl(opus_encoder, OPUS_GET_LOOKAHEAD(&preskip));
    } else {
        if ((opus_ms_encoder =
             opus_multistream_surround_encoder_create(
                 48000,
                 pcmreader->channels,
                 channel_mapping,
                 &stream_count,
                 &coupled_stream_count,
                 stream_map,
                 OPUS_APPLICATION_AUDIO,
                 &error)) == NULL) {
            fclose(output_file);
            return ERR_ENCODER_INIT;
        }

        opus_multistream_encoder_ctl(opus_ms_encoder,
                                     OPUS_SET_COMPLEXITY(quality));
        opus_multistream_encoder_ctl(opus_ms_encoder,
                                     OPUS_GET_LOOKAHEAD(&preskip));
    }


    srand((unsigned)time(NULL));
    ogg_stream_init(&ogg_stream, rand());

    /*write header and comment packets to Ogg stream*/
    {
        BitstreamRecorder *header =
            bw_open_bytes_recorder(BS_LITTLE_ENDIAN);
        BitstreamWriter *header_w =(BitstreamWriter*)header;
        BitstreamRecorder *comment =
            bw_open_bytes_recorder(BS_LITTLE_ENDIAN);
        BitstreamWriter *comment_w = (BitstreamWriter*)comment;
        int i;

        /*write header packet to Ogg stream*/
        const char opushead[] = "OpusHead";
        const char opuscomment[] = "OpusTags";
        const char *vendor_string = opus_get_version_string();
        const size_t vendor_string_len = strlen(vendor_string);
        ogg_packet packet_head;
        ogg_packet packet_tags;

        header_w->write_bytes(header_w,
                              (uint8_t*)opushead,
                              (unsigned)strlen(opushead));
        header_w->write(header_w, 8, 1);       /*version*/
        header_w->write(header_w, 8, pcmreader->channels);
        header_w->write(header_w, 16, preskip);
        header_w->write(header_w, 32, original_sample_rate);
        header_w->write(header_w, 16, 0);      /*output gain*/
        header_w->write(header_w, 8, channel_mapping);
        if (channel_mapping != 0) {
            header_w->write(header_w, 8, stream_count);
            header_w->write(header_w, 8, coupled_stream_count);
            for (i = 0; i < pcmreader->channels; i++) {
                header_w->write(header_w, 8, stream_map[i]);
            }
        }

        packet_head.packet = malloc(header->bytes_written(header));
        header->data(header, (uint8_t*)packet_head.packet);
        packet_head.bytes = header->bytes_written(header);
        packet_head.b_o_s = 1;
        packet_head.e_o_s = 0;
        packet_head.granulepos = 0;
        packet_head.packetno = packetno++;
        header->close(header);

        ogg_stream_packetin(&ogg_stream, &packet_head);

        for (i = ogg_stream_flush(&ogg_stream, &ogg_page);
             i != 0;
             i = ogg_stream_flush(&ogg_stream, &ogg_page)) {
            fwrite(ogg_page.header, 1, ogg_page.header_len, output_file);
            fwrite(ogg_page.body, 1, ogg_page.body_len, output_file);
        }

        free(packet_head.packet);

        /*write comment packet to Ogg stream*/
        comment_w->write_bytes(comment_w,
                               (uint8_t*)opuscomment,
                               (unsigned)strlen(opuscomment));
        comment_w->write(comment_w, 32, (unsigned)vendor_string_len);
        comment_w->write_bytes(comment_w,
                               (uint8_t*)vendor_string,
                               (unsigned)vendor_string_len);
        comment_w->write(comment_w, 32, 0);

        packet_tags.packet = malloc(comment->bytes_written(comment));
        comment->data(comment, (uint8_t*)packet_tags.packet);
        packet_tags.bytes = comment->bytes_written(comment);
        packet_tags.b_o_s = 0;
        packet_tags.e_o_s = 0;
        packet_tags.granulepos = 0;
        packet_tags.packetno = packetno++;
        comment->close(comment);

        ogg_stream_packetin(&ogg_stream, &packet_tags);

        for (i = ogg_stream_flush(&ogg_stream, &ogg_page);
             i != 0;
             i = ogg_stream_flush(&ogg_stream, &ogg_page)) {
            fwrite(ogg_page.header, 1, ogg_page.header_len, output_file);
            fwrite(ogg_page.body, 1, ogg_page.body_len, output_file);
        }

        free(packet_tags.packet);
    }

    opus_samples = malloc(sizeof(opus_int16) *
                          pcmreader->channels *
                          BLOCK_SIZE);

    pcm_frames = pcmreader->read(pcmreader, BLOCK_SIZE, samples);
    if (!pcm_frames && (pcmreader->status != PCM_OK)) {
        result = ERR_PCMREADER;
        goto cleanup;
    }

    /*for each non-empty FrameList from PCMReader, encode Opus frame*/
    while (pcm_frames) {
        const int short_framelist = (pcm_frames < BLOCK_SIZE);
        unsigned i;
        opus_int32 encoded_size;
        ogg_packet packet;

        granulepos += pcm_frames;

        /*pad FrameList with additional null samples if necessary*/
        memset(samples + pcm_frames * pcmreader->channels,
               0,
               sizeof(int) * (BLOCK_SIZE - pcm_frames) * pcmreader->channels);

        /*rearrange channels to Vorbis order if necessary*/
        reorder_channels(pcmreader->channel_mask, BLOCK_SIZE, samples);

        /*place samples in interleaved buffer*/
        for (i = 0; i < (pcm_frames * pcmreader->channels); i++) {
            opus_samples[i] = (opus_int16)samples[i];
        }

        /*call opus_encode on interleaved buffer to get next packet*/
        if (!multichannel) {
            encoded_size = opus_encode(opus_encoder,
                                       opus_samples,
                                       BLOCK_SIZE,
                                       opus_frame,
                                       OPUS_FRAME_LEN);
        } else {
            encoded_size = opus_multistream_encode(opus_ms_encoder,
                                                   opus_samples,
                                                   BLOCK_SIZE,
                                                   opus_frame,
                                                   OPUS_FRAME_LEN);
        }

        /*get next FrameList to encode*/
        pcm_frames = pcmreader->read(pcmreader, BLOCK_SIZE, samples);
        if (!pcm_frames && (pcmreader->status != PCM_OK)) {
            result = ERR_PCMREADER;
            goto cleanup;
        }

        /*dump Opus packet to Ogg stream*/
        /*do this *after* reading the next FrameList in order to detect
          the end of stream properly based on whether the FrameList
          has no frames*/
        packet.packet = (unsigned char *)opus_frame;
        packet.bytes = encoded_size;
        packet.b_o_s = 0;
        packet.e_o_s = (short_framelist || (pcm_frames == 0));
        packet.granulepos = granulepos;
        packet.packetno = packetno;

        ogg_stream_packetin(&ogg_stream, &packet);
        while (ogg_stream_pageout(&ogg_stream, &ogg_page)) {
            fwrite(ogg_page.header, 1, ogg_page.header_len, output_file);
            fwrite(ogg_page.body, 1, ogg_page.body_len, output_file);
        }
    }

    /*flush any remaining Ogg pages to disk*/
    while (ogg_stream_flush(&ogg_stream, &ogg_page)) {
        fwrite(ogg_page.header, 1, ogg_page.header_len, output_file);
        fwrite(ogg_page.body, 1, ogg_page.body_len, output_file);
    }

cleanup:
    fclose(output_file);
    ogg_stream_clear(&ogg_stream);
    if (!multichannel) {
        opus_encoder_destroy(opus_encoder);
    } else {
        opus_multistream_encoder_destroy(opus_ms_encoder);
    }
    free(opus_samples);
    return result;
}
Example #2
0
File: opus.c Project: MSalmo/vlc
static int OpenEncoder(vlc_object_t *p_this)
{
    encoder_t *enc = (encoder_t *)p_this;

    if (enc->fmt_out.i_codec != VLC_CODEC_OPUS)
        return VLC_EGENERIC;

    encoder_sys_t *sys = malloc(sizeof(*sys));
    if (!sys)
        return VLC_ENOMEM;

    int status = VLC_SUCCESS;
    sys->buffer = NULL;
    sys->enc = NULL;

    enc->pf_encode_audio = Encode;
    enc->fmt_in.i_codec = VLC_CODEC_FL32;
    enc->fmt_in.audio.i_rate = /* Only 48kHz */
    enc->fmt_out.audio.i_rate = 48000;
    enc->fmt_out.audio.i_channels = enc->fmt_in.audio.i_channels;

    OpusHeader header;

    if (opus_prepare_header(enc->fmt_out.audio.i_channels,
            enc->fmt_out.audio.i_rate,
            &header))
    {
        msg_Err(enc, "Failed to prepare header.");
        status = VLC_ENOMEM;
        goto error;
    }

    /* needed for max encoded size calculation */
    sys->nb_streams = header.nb_streams;

    int err;
    sys->enc =
        opus_multistream_surround_encoder_create(enc->fmt_in.audio.i_rate,
                enc->fmt_in.audio.i_channels, header.channel_mapping,
                &header.nb_streams, &header.nb_coupled, header.stream_map,
                OPUS_APPLICATION_AUDIO, &err);

    if (err != OPUS_OK)
    {
        msg_Err(enc, "Could not create encoder: error %d", err);
        sys->enc = NULL;
        status = VLC_EGENERIC;
        goto error;
    }

    /* TODO: vbr, bitrate, fec */

    /* Buffer for incoming audio, since opus only accepts frame sizes that are
       multiples of 2.5ms */
    enc->p_sys = sys;
    sys->buffer = malloc(OPUS_FRAME_SIZE * header.channels * sizeof(float));
    if (!sys->buffer) {
        status = VLC_ENOMEM;
        goto error;
    }

    sys->i_nb_samples = 0;

    sys->i_samples_delay = 0;
    int ret = opus_multistream_encoder_ctl(enc->p_sys->enc,
            OPUS_GET_LOOKAHEAD(&sys->i_samples_delay));
    if (ret != OPUS_OK)
        msg_Err(enc, "Unable to get number of lookahead samples: %s\n",
                opus_strerror(ret));

    header.preskip = sys->i_samples_delay;

    /* Now that we have preskip, we can write the header to extradata */
    if (opus_write_header((uint8_t **) &enc->fmt_out.p_extra,
                          &enc->fmt_out.i_extra, &header))
    {
        msg_Err(enc, "Failed to write header.");
        status = VLC_ENOMEM;
        goto error;
    }

    if (sys->i_samples_delay > 0)
    {
        const unsigned padding_samples = sys->i_samples_delay *
            enc->fmt_out.audio.i_channels;
        sys->padding = block_Alloc(padding_samples * sizeof(float));
        if (!sys->padding) {
            status = VLC_ENOMEM;
            goto error;
        }
        sys->padding->i_nb_samples = sys->i_samples_delay;
        float *pad_ptr = (float *) sys->padding->p_buffer;
        memset(pad_ptr, 0, padding_samples * sizeof(float));
    }
    else
    {
        sys->padding = NULL;
    }

    return status;

error:
    if (sys->enc)
        opus_multistream_encoder_destroy(sys->enc);
    free(sys->buffer);
    free(sys);
    return status;
}
	virtual bool CookSurround(FName Format, const TArray<TArray<uint8> >& SrcBuffers, FSoundQualityInfo& QualityInfo, TArray<uint8>& CompressedDataStore) const override
	{
		check(Format == NAME_OPUS);

		// Get best compatible sample rate
		const uint16 kOpusSampleRate = GetBestOutputSampleRate(QualityInfo.SampleRate);
		// Frame size must be one of 2.5, 5, 10, 20, 40 or 60 ms
		const int32 kOpusFrameSizeMs = 60;
		// Calculate frame size required by Opus
		const int32 kOpusFrameSizeSamples = (kOpusSampleRate * kOpusFrameSizeMs) / 1000;
		const uint32 kSampleStride = SAMPLE_SIZE * QualityInfo.NumChannels;
		const int32 kBytesPerFrame = kOpusFrameSizeSamples * kSampleStride;

		// Check whether source has compatible sample rate
		TArray<TArray<uint8>> SrcBufferCopies;
		if (QualityInfo.SampleRate != kOpusSampleRate)
		{
			for (int32 Index = 0; Index < SrcBuffers.Num(); Index++)
			{
				TArray<uint8>& NewCopy = *new (SrcBufferCopies) TArray<uint8>;
				if (!ResamplePCM(1, SrcBuffers[Index], QualityInfo.SampleRate, NewCopy, kOpusSampleRate))
				{
					return false;
				}
			}
		}
		else
		{
			// Take a copy of the source regardless
			for (int32 Index = 0; Index < SrcBuffers.Num(); Index++)
			{
				SrcBufferCopies[Index] = SrcBuffers[Index];
			}
		}

		// Ensure that all channels are the same length
		int32 SourceSize = -1;
		for (int32 Index = 0; Index < SrcBufferCopies.Num(); Index++)
		{
			if (!Index)
			{
				SourceSize = SrcBufferCopies[Index].Num();
			}
			else
			{
				if (SourceSize != SrcBufferCopies[Index].Num())
				{
					return false;
				}
			}
		}
		if (SourceSize <= 0)
		{
			return false;
		}

		// Initialise the Opus multistream encoder
		OpusMSEncoder* Encoder = NULL;
		int32 EncError = 0;
		int32 streams = 0;
		int32 coupled_streams = 0;
		// mapping_family not documented but figured out: 0 = 1 or 2 channels, 1 = 1 to 8 channel surround sound, 255 = up to 255 channels with no surround processing
		int32 mapping_family = 1;
		TArray<uint8> mapping;
		mapping.AddUninitialized(QualityInfo.NumChannels);
#if USE_UE4_MEM_ALLOC
		int32 EncSize = opus_multistream_surround_encoder_get_size(QualityInfo.NumChannels, mapping_family);
		Encoder = (OpusMSEncoder*)FMemory::Malloc(EncSize);
		EncError = opus_multistream_surround_encoder_init(Encoder, kOpusSampleRate, QualityInfo.NumChannels, mapping_family, &streams, &coupled_streams, mapping.GetData(), OPUS_APPLICATION_AUDIO);
#else
		Encoder = opus_multistream_surround_encoder_create(kOpusSampleRate, QualityInfo.NumChannels, mapping_family, &streams, &coupled_streams, mapping.GetData(), OPUS_APPLICATION_AUDIO, &EncError);
#endif
		if (EncError != OPUS_OK)
		{
			Destroy(Encoder);
			return false;
		}

		int32 BitRate = GetBitRateFromQuality(QualityInfo);
		opus_multistream_encoder_ctl(Encoder, OPUS_SET_BITRATE(BitRate));

		// Create a buffer to store compressed data
		CompressedDataStore.Empty();
		FMemoryWriter CompressedData(CompressedDataStore);
		int32 SrcBufferOffset = 0;

		// Calc frame and sample count
		int32 FramesToEncode = SourceSize / (kOpusFrameSizeSamples * SAMPLE_SIZE);
		uint32 TrueSampleCount = SourceSize / SAMPLE_SIZE;

		// Add another frame if Source does not divide into an equal number of frames
		if (SourceSize % (kOpusFrameSizeSamples * SAMPLE_SIZE) != 0)
		{
			FramesToEncode++;
		}

		check(QualityInfo.NumChannels <= MAX_uint8);
		check(FramesToEncode <= MAX_uint16);
		SerializeHeaderData(CompressedData, kOpusSampleRate, TrueSampleCount, QualityInfo.NumChannels, FramesToEncode);

		// Temporary storage for source data in an interleaved format
		TArray<uint8> TempInterleavedSrc;
		TempInterleavedSrc.AddUninitialized(kBytesPerFrame);

		// Temporary storage with more than enough to store any compressed frame
		TArray<uint8> TempCompressedData;
		TempCompressedData.AddUninitialized(kBytesPerFrame);

		while (SrcBufferOffset < SourceSize)
		{
			// Read a frames worth of data from the source and pack it into interleaved temporary storage
			for (int32 SampleIndex = 0; SampleIndex < kOpusFrameSizeSamples; ++SampleIndex)
			{
				int32 CurrSrcOffset = SrcBufferOffset + SampleIndex*SAMPLE_SIZE;
				int32 CurrInterleavedOffset = SampleIndex*kSampleStride;
				if (CurrSrcOffset < SourceSize)
				{
					for (uint32 ChannelIndex = 0; ChannelIndex < QualityInfo.NumChannels; ++ChannelIndex)
					{
						// Interleave the channels in the Vorbis format, so that the correct channel is used for LFE
						int32 OrderedChannelIndex = VorbisChannelInfo::Order[QualityInfo.NumChannels - 1][ChannelIndex];
						int32 CurrInterleavedIndex = CurrInterleavedOffset + ChannelIndex*SAMPLE_SIZE;

						// Copy both bytes that make up a single sample
						TempInterleavedSrc[CurrInterleavedIndex] = SrcBufferCopies[OrderedChannelIndex][CurrSrcOffset];
						TempInterleavedSrc[CurrInterleavedIndex + 1] = SrcBufferCopies[OrderedChannelIndex][CurrSrcOffset + 1];
					}
				}
				else
				{
					// Zero the rest of the temp buffer to make it an exact frame
					FMemory::Memzero(TempInterleavedSrc.GetData() + CurrInterleavedOffset, kBytesPerFrame - CurrInterleavedOffset);
					SampleIndex = kOpusFrameSizeSamples;
				}
			}

			int32 CompressedLength = opus_multistream_encode(Encoder, (const opus_int16*)(TempInterleavedSrc.GetData()), kOpusFrameSizeSamples, TempCompressedData.GetData(), TempCompressedData.Num());

			if (CompressedLength < 0)
			{
				const char* ErrorStr = opus_strerror(CompressedLength);
				UE_LOG(LogAudio, Warning, TEXT("Failed to encode: [%d] %s"), CompressedLength, ANSI_TO_TCHAR(ErrorStr));

				Destroy(Encoder);

				CompressedDataStore.Empty();
				return false;
			}
			else
			{
				// Store frame length and copy compressed data before incrementing pointers
				check(CompressedLength < MAX_uint16);
				SerialiseFrameData(CompressedData, TempCompressedData.GetData(), CompressedLength);
				SrcBufferOffset += kOpusFrameSizeSamples * SAMPLE_SIZE;
			}
		}

		Destroy(Encoder);

		return CompressedDataStore.Num() > 0;
	}
Example #4
0
/*
 * Create opus writer port.
 */
PJ_DEF(pj_status_t) pjmedia_opus_writer_port_create( pj_pool_t *pool,
						     const char *filename,
						     unsigned sampling_rate,
						     unsigned channel_count,
						     unsigned samples_per_frame,
						     unsigned bits_per_sample,
						     unsigned flags,
						     pj_ssize_t buff_size,
						     pjmedia_port **p_port ) {
  struct opus_port *oport;
  struct opus_tool_param *otp;
  pj_str_t         name;
  pj_status_t      status;
  pjmedia_frame    tempframe;
  int              i,ret;

  /* Check arguments. */
  PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);

  /* Only supports 16bits per sample for now. */
  PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);

  /* Create file port instance. */
  oport = PJ_POOL_ZALLOC_T(pool, struct opus_port);
  PJ_ASSERT_RETURN(oport != NULL, PJ_ENOMEM);

  /* Initialize port info. */
  pj_strdup2(pool, &name, filename);
  pjmedia_port_info_init(&oport->base.info, &name, SIGNATURE,
      sampling_rate, channel_count, bits_per_sample,
      samples_per_frame);

  oport->base.get_frame = &opus_get_frame;
  oport->base.put_frame = &opus_put_frame;
  oport->base.on_destroy = &opus_on_destroy;
  oport->bytes_per_sample = 2;


  /**********************
   * opus-tool Start
   *********************/
  otp = PJ_POOL_ZALLOC_T(pool, struct opus_tool_param);
  PJ_ASSERT_RETURN(otp != NULL, PJ_ENOMEM);

  /* Initialize some default parameters. */
  otp->opt_ctls_ctlval=NULL;
  otp->frange=NULL;
  otp->range_file=NULL;
  otp->inopt.channels=channel_count;
  otp->inopt.rate=otp->coding_rate=otp->rate=sampling_rate;

  /* Some default value */
  otp->frame_size=960;
  otp->bitrate=-1;
  otp->with_hard_cbr=0;
  otp->with_cvbr=0;
  otp->complexity=10;
  otp->expect_loss=0;
  otp->lookahead=0;
  otp->bytes_written=0;
  otp->pages_out=0;
  otp->comment_padding=512;
  otp->eos=0;
  otp->nb_samples=-1;
  otp->id=-1;
  otp->nb_encoded=0;
  otp->enc_granulepos=0;
  otp->total_bytes=0;
  otp->peak_bytes=0;
  otp->max_ogg_delay=48000;

  /* 0 dB gain is recommended unless you know what you're doing */
  otp->inopt.gain=0;
  otp->inopt.samplesize=(oport->bytes_per_sample)*8;
  otp->inopt.endianness=0;
  otp->inopt.rawmode=0;
  otp->inopt.ignorelength=0;
  otp->inopt.copy_comments=1;
  otp->inopt.skip=0;

  otp->start_time = time(NULL);
  srand(((_getpid()&65535)<<15)^(otp->start_time));
  otp->serialno=rand();

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

  otp->outFile=(char *)filename;
  otp->rate=otp->inopt.rate;
  otp->chan=otp->inopt.channels;
  otp->inopt.skip=0;

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

  otp->frame_size=otp->frame_size/(48000/otp->coding_rate);

  /*OggOpus headers*/ /*FIXME: broke forcemono*/
  otp->header.channels=otp->chan;
  otp->header.channel_mapping=otp->header.channels>8?255:otp->chan>2;
  otp->header.input_sample_rate=otp->rate;
  otp->header.gain=otp->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. */
  otp->st=opus_multistream_surround_encoder_create(otp->coding_rate, otp->chan, otp->header.channel_mapping, &otp->header.nb_streams, &otp->header.nb_coupled,
    otp->header.stream_map, otp->frame_size<480/(48000/otp->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));
    exit(1);
  }

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

  if(otp->bitrate<0) {
    /* Lower default rate for sampling rates [8000-44100) by a factor of (rate+16k)/(64k) */
    otp->bitrate=((64000*otp->header.nb_streams+32000*otp->header.nb_coupled)*
        (IMIN(48,IMAX(8,((otp->rate<44100?otp->rate:48000)+1000)/1000))+16)+32)>>6;
  }
Example #5
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;
  }
Example #6
0
void OggOpusFile::Init()
{
    inopt.skip=0;
    //In our case, its 160 samples/frame. Changing rate to anything rather than 8000Hz may require significant change in the way of handle number of samples to fix the encoder
    frame_size=frame_size/(48000/coding_rate);  
    /*OggOpus headers*/ /*FIXME: broke forcemono*/
    header.channels=chan;
    header.channel_mapping= 0;//header.channels>8?255:chan>2;  //=0 for  wav
    header.input_sample_rate=rate;
    header.gain=inopt.gain;   //=0 here

    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));
        exit(1);
    }
    
    max_frame_bytes=(1275*3+7)*header.nb_streams;
    min_bytes=max_frame_bytes;
    m_outBuf = (unsigned char*)malloc(max_frame_bytes);
    if(m_outBuf==NULL){
        fprintf(stderr,"Error allocating m_outBuf buffer.\n");
        exit(1);
    }

    //We would set bitrate configurable as low as 6k
    //Or use the provided formulae to calculate a optimized bitrate
    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;
        bitrate=6000;

    }

    if(bitrate>(1024000*chan)||bitrate<500){
        fprintf(stderr,"Error: Bitrate %d bits/sec is insane.\nDid you mistake bits for kilobits?\n",bitrate);
        fprintf(stderr,"--bitrate values from 6-256 kbit/sec per channel are meaningful.\n");
        exit(1);
    }
    bitrate=IMIN(chan*256000,bitrate);

    ret=opus_multistream_encoder_ctl(st, OPUS_SET_BITRATE(bitrate));
    if(ret!=OPUS_OK){
        fprintf(stderr,"Error OPUS_SET_BITRATE returned: %s\n",opus_strerror(ret));
        exit(1);
    }

    ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR(!with_hard_cbr));
    if(ret!=OPUS_OK){
        fprintf(stderr,"Error OPUS_SET_VBR returned: %s\n",opus_strerror(ret));
        exit(1);
    }

    if(!with_hard_cbr){
        ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR_CONSTRAINT(with_cvbr));
        if(ret!=OPUS_OK){
            fprintf(stderr,"Error OPUS_SET_VBR_CONSTRAINT returned: %s\n",opus_strerror(ret));
            exit(1);
        }
    }
    ret=opus_multistream_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity));
    if(ret!=OPUS_OK){
        fprintf(stderr,"Error OPUS_SET_COMPLEXITY returned: %s\n",opus_strerror(ret));
        exit(1);
    }

    ret=opus_multistream_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(expect_loss));
    if(ret!=OPUS_OK){
        fprintf(stderr,"Error OPUS_SET_PACKET_LOSS_PERC returned: %s\n",opus_strerror(ret));
        exit(1);
    }

#ifdef OPUS_SET_LSB_DEPTH
    ret=opus_multistream_encoder_ctl(st, OPUS_SET_LSB_DEPTH(IMAX(8,IMIN(24,inopt.samplesize))));
    if(ret!=OPUS_OK){
        fprintf(stderr,"Warning OPUS_SET_LSB_DEPTH returned: %s\n",opus_strerror(ret));
    }
#endif

    for(i=0;i<opt_ctls;i++){
    int target=opt_ctls_ctlval[i*3];
    if(target==-1){
        ret=opus_multistream_encoder_ctl(st,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]);
        if(ret!=OPUS_OK){
        fprintf(stderr,"Error opus_multistream_encoder_ctl(st,%d,%d) returned: %s\n",opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret));
        exit(1);
        }
    }else if(target<header.nb_streams){
        OpusEncoder *oe;
        opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(target,&oe));
        ret=opus_encoder_ctl(oe, opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]);
        if(ret!=OPUS_OK){
        fprintf(stderr,"Error opus_encoder_ctl(st[%d],%d,%d) returned: %s\n",target,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret));
        exit(1);
        }
    }else{
        fprintf(stderr,"Error --set-ctl-int target stream %d is higher than the maximum stream number %d.\n",target,header.nb_streams-1);
        exit(1);
    }
    }


    /*We do the lookahead check late so user CTLs can change it*/
    ret=opus_multistream_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&lookahead));
    if(ret!=OPUS_OK){
    fprintf(stderr,"Error OPUS_GET_LOOKAHEAD returned: %s\n",opus_strerror(ret));
    exit(1);
    }
    inopt.skip+=lookahead;
    /*Regardless of the rate we're coding at the ogg timestamping/skip is
    always timed at 48000.*/
    header.preskip=inopt.skip*(48000./coding_rate);
    /* Extra samples that need to be read to compensate for the pre-skip */
    inopt.extraout=(int)header.preskip*(rate/48000.);

    /*Initialize Ogg stream struct*/
    if(ogg_stream_init(&os, serialno)==-1){
    fprintf(stderr,"Error: stream init failed\n");
    exit(1);
    }



    int opus_app;
    fprintf(stderr,"Encoding using 1.1");
    opus_multistream_encoder_ctl(st,OPUS_GET_APPLICATION(&opus_app));
    if(opus_app==OPUS_APPLICATION_VOIP)fprintf(stderr," (VoIP)\n");
    else if(opus_app==OPUS_APPLICATION_AUDIO)fprintf(stderr," (audio)\n");
    else if(opus_app==OPUS_APPLICATION_RESTRICTED_LOWDELAY)fprintf(stderr," (low-delay)\n");
    else fprintf(stderr," (unknown)\n");
    fprintf(stderr,"-----------------------------------------------------\n");
    fprintf(stderr,"   Input: %0.6gkHz %d channel%s\n",
            header.input_sample_rate/1000.,chan,chan<2?"":"s");
    fprintf(stderr,"  Output: %d channel%s (",header.channels,header.channels<2?"":"s");
    if(header.nb_coupled>0)fprintf(stderr,"%d coupled",header.nb_coupled*2);
    if(header.nb_streams-header.nb_coupled>0)fprintf(stderr,
       "%s%d uncoupled",header.nb_coupled>0?", ":"",
       header.nb_streams-header.nb_coupled);
    fprintf(stderr,")\n          %0.2gms packets, %0.6gkbit/sec%s\n",
       frame_size/(coding_rate/1000.), bitrate/1000.,
       with_hard_cbr?" CBR":with_cvbr?" CVBR":" VBR");
    fprintf(stderr," Preskip: %d\n",header.preskip);
  

}
Example #7
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;
	}