in nlsCppSdk/encoder/oggopusEncoder.cpp [329:557]
int OggOpusDataEncoder::OggopusEncode(const char *input_data, int length) {
if (NULL == ogg_opus_para_) {
return -(OggOpusInvalidState);
}
int ret = 0;
char *tmp_buf = NULL;
// short *tmp_2 = (short *)input_data;
int tmp_length = 0;
if (is_first_frame_processed_ && (length > 0)) {
// the first frame has been processed
tmp_length = length;
tmp_buf = reinterpret_cast<char *>(malloc(tmp_length));
// memset(tmp_buf, 0, tmp_length);
memcpy(tmp_buf, input_data, tmp_length);
} else {
// 第一帧
if (length == frame_sample_bytes_) {
unsigned char header_data[276] = {0};
// 将header结构写入header_data中
int packet_size = OpusHeaderToPacket(&ogg_opus_para_->header, header_data,
sizeof(header_data));
ogg_opus_para_->op.packet = header_data; // 填写ogg_packet
ogg_opus_para_->op.bytes = packet_size;
ogg_opus_para_->op.b_o_s = 1;
ogg_opus_para_->op.e_o_s = 0;
ogg_opus_para_->op.granulepos = 0;
ogg_opus_para_->op.packetno = 0;
// 原始数据要封装在ogg_packet中通过ogg_stream_packetin方法
// 写入到ogg_stream_state
ogg_stream_packetin(&ogg_opus_para_->os, &ogg_opus_para_->op);
// os写入og(page的信息),直到写完
while (
(ret = ogg_stream_flush(&ogg_opus_para_->os, &ogg_opus_para_->og))) {
if (!ret) break;
ret = ogg_opus_para_->WritePage(); //把og的header和body送出去
if (ret !=
ogg_opus_para_->og.header_len + ogg_opus_para_->og.body_len) {
LOG_ERROR("error: failed writing header to output stream");
return -(OggOpusEncodeFailed);
}
} // while
// start()函数中已经填充了comments
ogg_opus_para_->op.packet =
(unsigned char *)ogg_opus_para_->ogg_encode_opt.comments;
ogg_opus_para_->op.bytes = ogg_opus_para_->ogg_encode_opt.comments_length;
ogg_opus_para_->op.b_o_s = 0;
ogg_opus_para_->op.packetno = 1;
// 原始数据要封装在ogg_packet中通过ogg_stream_packetin方法
// 写入到ogg_stream_state
ogg_stream_packetin(&ogg_opus_para_->os, &ogg_opus_para_->op);
// os写入og(page的信息),直到写完
while (
(ret = ogg_stream_flush(&ogg_opus_para_->os, &ogg_opus_para_->og))) {
if (!ret) break;
ret = ogg_opus_para_->WritePage(); //把og的header和body送出去
if (ret !=
ogg_opus_para_->og.header_len + ogg_opus_para_->og.body_len) {
LOG_ERROR("error: failed writing header to output stream");
return -(OggOpusEncodeFailed);
}
} // while
tmp_length = length * 2;
tmp_buf = reinterpret_cast<char *>(malloc(tmp_length));
memset(tmp_buf, 0, tmp_length);
memcpy(tmp_buf + length, input_data, length); // 音频数据封入
is_first_frame_processed_ = true;
} else { // input length is invalid
ogg_opus_para_->op.e_o_s = 1;
}
}
int size_segments, cur_frame_size;
ogg_opus_para_->id++;
if (ogg_opus_para_->nb_samples < 0) {
ogg_opus_para_->nb_samples =
ogg_opus_para_->ogg_encode_opt
.read_func(/* WavRead() */
ogg_opus_para_->ogg_encode_opt.read_info,
ogg_opus_para_->input, frame_sample_num_,
/* 将tmp_buf(原始数据)Wav写入到 ogg_opus_para中 */
&tmp_buf, &tmp_length);
}
if (ogg_opus_para_->start_time == 0) {
ogg_opus_para_->start_time = time(NULL);
}
cur_frame_size = frame_sample_num_;
if (ogg_opus_para_->nb_samples < cur_frame_size) {
/*Avoid making the final packet 20ms or more longer than needed.*/
cur_frame_size -=
((cur_frame_size -
(ogg_opus_para_->nb_samples >= 0 ? ogg_opus_para_->nb_samples : 1)) /
320) *
320;
/*No fancy end padding, just fill with zeros for now.*/
for (int i = ogg_opus_para_->nb_samples * channel_num_;
i < cur_frame_size * channel_num_; i++) {
ogg_opus_para_->input[i] = 0;
}
}
if (cur_frame_size <= 0) {
LOG_WARN("cur_frame_size = %d, nb_samples = %d", cur_frame_size,
ogg_opus_para_->nb_samples);
if (tmp_buf) {
free(tmp_buf);
tmp_buf = NULL;
}
return -(OggOpusEncodeFailed);
}
/* 成功,是被编码包的长度(字节数),失败,一个负的错误代码 */
ogg_opus_para_->nbBytes =
/* 根据浮点输入对一个 Opus帧进行编码. */
opus_multistream_encode_float(ogg_opus_para_->opus_multistream_encoder,
ogg_opus_para_->input, cur_frame_size,
ogg_opus_para_->packet,
ogg_opus_para_->max_frame_bytes);
if (ogg_opus_para_->nbBytes < 0) {
LOG_ERROR("encoding failed: %d %s. aborting ...", ogg_opus_para_->nbBytes,
opus_strerror(ogg_opus_para_->nbBytes));
LOG_INFO("cur_frame_size = %d", cur_frame_size);
LOG_INFO("ogg_opus_para_->nbBytes = %d", ogg_opus_para_->nbBytes);
if (tmp_buf) {
free(tmp_buf);
tmp_buf = NULL;
}
return -(OggOpusEncodeFailed);
}
ogg_opus_para_->enc_granulepos += FRAME_SAMPLE_NUM * 3;
size_segments = (ogg_opus_para_->nbBytes + 255) / 255;
/*Flush early if adding this packet would make us end up with a
continued page which we wouldn't have otherwise.*/
while ((((size_segments <= 255) &&
(ogg_opus_para_->last_segments + size_segments > 255)) ||
(ogg_opus_para_->enc_granulepos - ogg_opus_para_->last_granulepos >
ogg_opus_para_->max_ogg_delay)) &&
ogg_stream_flush_fill(&ogg_opus_para_->os, &ogg_opus_para_->og,
255 * 255)) {
if (ogg_page_packets(&ogg_opus_para_->og) != 0) {
ogg_opus_para_->last_granulepos =
ogg_page_granulepos(&ogg_opus_para_->og);
}
ogg_opus_para_->last_segments -= ogg_opus_para_->og.header[26];
ret = ogg_opus_para_->WritePage();
if (ret != ogg_opus_para_->og.header_len + ogg_opus_para_->og.body_len) {
LOG_ERROR("error: failed writing data to output stream");
if (tmp_buf) {
free(tmp_buf);
tmp_buf = NULL;
}
return -(OggOpusEncodeFailed);
}
}
if ((!ogg_opus_para_->op.e_o_s) && ogg_opus_para_->max_ogg_delay > 5760) {
ogg_opus_para_->nb_samples =
ogg_opus_para_->ogg_encode_opt
.read_func(/* WavRead() */
ogg_opus_para_->ogg_encode_opt.read_info,
ogg_opus_para_->input, frame_sample_num_,
/* 将tmp_buf(原始数据)Wav写入到 ogg_opus_para中 */
&tmp_buf, &tmp_length);
if (ogg_opus_para_->nb_samples == 0) {
LOG_INFO("nb_samples = %d, max_ogg_delay = %d",
ogg_opus_para_->nb_samples, ogg_opus_para_->max_ogg_delay);
ogg_opus_para_->op.e_o_s = 1;
}
} else {
ogg_opus_para_->nb_samples = -1;
}
ogg_opus_para_->op.packet = (unsigned char *)ogg_opus_para_->packet;
ogg_opus_para_->op.bytes = ogg_opus_para_->nbBytes;
ogg_opus_para_->op.b_o_s = 0;
ogg_opus_para_->op.granulepos = ogg_opus_para_->enc_granulepos;
if (ogg_opus_para_->op.e_o_s) {
ogg_opus_para_->op.granulepos =
((ogg_opus_para_->original_sample_number * 48000 + sample_rate_ - 1) /
sample_rate_) +
ogg_opus_para_->header.preskip;
}
ogg_opus_para_->op.packetno = 2 + ogg_opus_para_->id;
ogg_stream_packetin(&ogg_opus_para_->os, &ogg_opus_para_->op);
ogg_opus_para_->last_segments += size_segments;
/*If the stream is over or we're sure that the delayed flush will fire,
go ahead and flush now to avoid adding delay.*/
while ((ogg_opus_para_->op.e_o_s ||
(ogg_opus_para_->enc_granulepos + (FRAME_SAMPLE_NUM * 3) -
ogg_opus_para_->last_granulepos >
ogg_opus_para_->max_ogg_delay) ||
(ogg_opus_para_->last_segments >= 255))
? ogg_stream_flush_fill(&ogg_opus_para_->os, &ogg_opus_para_->og,
255 * 255)
: ogg_stream_pageout_fill(&ogg_opus_para_->os, &ogg_opus_para_->og,
255 * 255)) {
if (ogg_page_packets(&ogg_opus_para_->og) != 0) {
ogg_opus_para_->last_granulepos =
ogg_page_granulepos(&ogg_opus_para_->og);
}
ogg_opus_para_->last_segments -= ogg_opus_para_->og.header[26];
ret = ogg_opus_para_->WritePage();
if (ret != ogg_opus_para_->og.header_len + ogg_opus_para_->og.body_len) {
LOG_ERROR("error: failed writing data to output stream");
if (tmp_buf) {
free(tmp_buf);
tmp_buf = NULL;
}
return -(OggOpusEncodeFailed);
}
}
if (tmp_buf) {
free(tmp_buf);
tmp_buf = NULL;
}
return Success;
}