int OggOpusDataEncoder::OggopusEncoderCreate()

in nlsCppSdk/encoder/oggopusEncoder.cpp [169:327]


int OggOpusDataEncoder::OggopusEncoderCreate(
    EncodedDataCallback encoded_data_callback, void *user_data,
    int samplerate) {
  sample_rate_ = samplerate;
  if (ogg_opus_para_) {
    delete ogg_opus_para_;
    ogg_opus_para_ = NULL;
  }
  ogg_opus_para_ = new OggOpusDataEncoderPara();
  if (NULL == ogg_opus_para_) {
    return -(OggOpusCreateFailed);
  }
  is_first_frame_processed_ = false;

  ResetParameters(encoded_data_callback, user_data);  // 初始化ogg_opus_para_

  // OpusTags0007opus_version0000,这个指向ogg_encode_opt.comments
  ogg_opus_para_->InitComment();
  // OpusTags0007opus_version0000ENCODER=opusenc from xxxxx,
  // 继续指向ogg_encode_opt.comments
  ogg_opus_para_->AddComment();

  /* 填充read_func和read_info */
  ogg_opus_para_->audio_functions->open_func(&ogg_opus_para_->ogg_encode_opt);

  SetupPadder(&ogg_opus_para_->ogg_encode_opt,
              &ogg_opus_para_->original_sample_number);

  /* reset opus header */
  ogg_opus_para_->header.version = 0;
  ogg_opus_para_->header.channels = channel_num_;
  ogg_opus_para_->header.nb_streams = 1;
  ogg_opus_para_->header.nb_coupled = 0;
  ogg_opus_para_->header.input_sample_rate = sample_rate_;
  ogg_opus_para_->header.gain = 0;
  ogg_opus_para_->header.channel_mapping = 0;
  memset(ogg_opus_para_->header.stream_map, 0,
         sizeof(ogg_opus_para_->header.stream_map));

  int ret = OPUS_OK;
  ogg_opus_para_->opus_multistream_encoder =
      /* 分配和初始化多流编码器状态 */
      opus_multistream_encoder_create(
          /* 解码的采样率(Hz) */
          sample_rate_,
          /* 输入信号中的通道数 */
          channel_num_,
          /* 输入要编码的数据流的总数,必须不能超过通道数 */
          ogg_opus_para_->header.nb_streams,
          /* 要编码的组对(2通道)数据流的总数,必须不大于数据流的总数 */
          ogg_opus_para_->header.nb_coupled,
          /* 被编码通道与输入通道的映射关系表 */
          ogg_opus_para_->header.stream_map,
          /* 目标编码器应用程序, 偏好与原始输入的正确性 */
          OPUS_APPLICATION_AUDIO, &ret);

  if (ret != OPUS_OK) {
    LOG_ERROR("error cannot create encoder: %s", opus_strerror(ret));
    exit(1);
  } else {
    LOG_DEBUG(
        "opus_multistream_encoder_create success. sample_rate_:%d "
        "channel_num_:%d",
        sample_rate_, channel_num_);
  }

  ogg_opus_para_->packet = reinterpret_cast<unsigned char *>(
      malloc(sizeof(unsigned char) * ogg_opus_para_->max_frame_bytes));
  if (ogg_opus_para_->packet == NULL) {
    LOG_ERROR("error allocating packet buffer.");
    exit(1);
  }
  memset(ogg_opus_para_->packet, 0,
         sizeof(unsigned char) * ogg_opus_para_->max_frame_bytes);

  LOG_INFO("nb_streams %d, nb_coupled %d, bitrate %d, max frame bytes: %d",
           ogg_opus_para_->header.nb_streams, ogg_opus_para_->header.nb_coupled,
           ogg_opus_para_->bitrate, ogg_opus_para_->max_frame_bytes);

  ret = opus_multistream_encoder_ctl(/* 向一个Opus多流编码器执行一个CTL函数 */
                                     ogg_opus_para_->opus_multistream_encoder,
                                     OPUS_SET_BITRATE(ogg_opus_para_->bitrate));
  if (ret != OPUS_OK) {
    LOG_ERROR("error OPUS_SET_BITRATE returned: %s", opus_strerror(ret));
    exit(1);
  }

  ret = opus_multistream_encoder_ctl(ogg_opus_para_->opus_multistream_encoder,
                                     OPUS_SET_VBR(true));
  if (ret != OPUS_OK) {
    LOG_ERROR("error OPUS_SET_VBR returned: %s", opus_strerror(ret));
    exit(1);
  }

  ret = opus_multistream_encoder_ctl(ogg_opus_para_->opus_multistream_encoder,
                                     OPUS_SET_VBR_CONSTRAINT(0));
  if (ret != OPUS_OK) {
    LOG_ERROR("error OPUS_SET_VBR_CONSTRAINT returned: %s", opus_strerror(ret));
    exit(1);
  }

  ret = opus_multistream_encoder_ctl(
      ogg_opus_para_->opus_multistream_encoder,
      OPUS_SET_COMPLEXITY(ogg_opus_para_->complexity));
  if (ret != OPUS_OK) {
    LOG_ERROR("error OPUS_SET_COMPLEXITY returned: %s", opus_strerror(ret));
    exit(1);
  }

  ret = opus_multistream_encoder_ctl(ogg_opus_para_->opus_multistream_encoder,
                                     OPUS_SET_PACKET_LOSS_PERC(0));
  if (ret != OPUS_OK) {
    LOG_ERROR("error OPUS_SET_PACKET_LOSS_PERC returned: %s",
              opus_strerror(ret));
    exit(1);
  }

#ifdef OPUS_SET_LSB_DEPTH
  ret = opus_multistream_encoder_ctl(
      ogg_opus_para_->opus_multistream_encoder,
      OPUS_SET_LSB_DEPTH(ogg_opus_para_->ogg_encode_opt.sample_bits));
  if (ret != OPUS_OK) {
    LOG_ERROR("warning OPUS_SET_LSB_DEPTH returned: %s", opus_strerror(ret));
  }
#endif

  /* get lookahead value */
  ret = opus_multistream_encoder_ctl(
      ogg_opus_para_->opus_multistream_encoder,
      OPUS_GET_LOOKAHEAD(&ogg_opus_para_->lookahead));
  if (ret != OPUS_OK) {
    LOG_ERROR("error OPUS_GET_LOOKAHEAD returned: %s", opus_strerror(ret));
    exit(1);
  }
  ogg_opus_para_->ogg_encode_opt.skip += ogg_opus_para_->lookahead;
  ogg_opus_para_->header.preskip = ogg_opus_para_->ogg_encode_opt.skip * 3.0;
  ogg_opus_para_->ogg_encode_opt.extraout = ogg_opus_para_->header.preskip / 3;

  if (ogg_stream_init(&ogg_opus_para_->os, ogg_opus_para_->serialno) == -1) {
    LOG_ERROR("error: stream init failed");
    exit(1);
  }

  ogg_opus_para_->input = reinterpret_cast<float *>(
      malloc(sizeof(float) * frame_sample_num_ * channel_num_));
  if (ogg_opus_para_->input == NULL) {
    LOG_ERROR("error: couldn't allocate sample buffer.");
    exit(1);
  }
  memset(ogg_opus_para_->input, 0,
         sizeof(float) * frame_sample_num_ * channel_num_);

  // prepare for encoding
  ogg_opus_para_->op.e_o_s = 0;
  ogg_opus_para_->nb_samples = -1;
  is_first_frame_processed_ = false;

  return Success;
}