/* * Get frames in the packet. */ static pj_status_t codec_parse( pjmedia_codec *codec, void *pkt, pj_size_t pkt_size, const pj_timestamp *ts, unsigned *frame_cnt, pjmedia_frame frames[] ) { struct opus_data *opus_data = (struct opus_data *)codec->codec_data; unsigned char tmp_buf[MAX_ENCODED_PACKET_SIZE]; int i, num_frames; int size, out_pos; unsigned samples_per_frame; #if (USE_INCOMING_WORSE_SETTINGS) int bw; #endif pj_mutex_lock (opus_data->mutex); if (pkt_size > sizeof(tmp_buf)) { PJ_LOG(5, (THIS_FILE, "Encoded size bigger than buffer")); pj_mutex_unlock (opus_data->mutex); return PJMEDIA_CODEC_EFRMTOOSHORT; } samples_per_frame = (opus_data->cfg.sample_rate * opus_data->ptime) / 1000; pj_memcpy(tmp_buf, pkt, pkt_size); opus_repacketizer_init(opus_data->dec_packer); opus_repacketizer_cat(opus_data->dec_packer, tmp_buf, pkt_size); num_frames = opus_repacketizer_get_nb_frames(opus_data->dec_packer); out_pos = 0; for (i = 0; i < num_frames; ++i) { size = opus_repacketizer_out_range(opus_data->dec_packer, i, i+1, ((unsigned char*)pkt) + out_pos, sizeof(tmp_buf)); if (size < 0) { PJ_LOG(5, (THIS_FILE, "Parse failed! (%d)", pkt_size)); pj_mutex_unlock (opus_data->mutex); return PJMEDIA_CODEC_EFAILED; } frames[i].type = PJMEDIA_FRAME_TYPE_AUDIO; frames[i].buf = ((char*)pkt) + out_pos; frames[i].size = size; frames[i].timestamp.u64 = ts->u64 + i * samples_per_frame; out_pos += size; } *frame_cnt = num_frames; pj_mutex_unlock (opus_data->mutex); return PJ_SUCCESS; }
/* * Encode frame. */ static pj_status_t codec_encode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, struct pjmedia_frame *output ) { struct opus_data *opus_data = (struct opus_data *)codec->codec_data; opus_int32 size = 0; unsigned in_pos = 0; unsigned out_pos = 0; unsigned frame_size; unsigned samples_per_frame; unsigned char tmp_buf[MAX_ENCODED_PACKET_SIZE]; unsigned tmp_bytes_left = sizeof(tmp_buf); pj_mutex_lock (opus_data->mutex); samples_per_frame = (opus_data->cfg.sample_rate * opus_data->ptime) / 1000; frame_size = samples_per_frame * opus_data->cfg.channel_cnt * sizeof(opus_int16); opus_repacketizer_init(opus_data->enc_packer); while (input->size - in_pos >= frame_size) { size = opus_encode(opus_data->enc, (const opus_int16*)(((char*)input->buf) + in_pos), samples_per_frame, tmp_buf + out_pos, (tmp_bytes_left < frame_size ? tmp_bytes_left : frame_size)); if (size < 0) { PJ_LOG(4, (THIS_FILE, "Encode failed! (%d)", size)); pj_mutex_unlock (opus_data->mutex); return PJMEDIA_CODEC_EFAILED; } else if (size > 0) { /* Only add packets containing more than the TOC */ opus_repacketizer_cat(opus_data->enc_packer, tmp_buf + out_pos, size); out_pos += size; tmp_bytes_left -= size; } in_pos += frame_size; } if (!opus_repacketizer_get_nb_frames(opus_data->enc_packer)) { /* Empty packet */ output->size = 0; output->type = PJMEDIA_FRAME_TYPE_NONE; output->timestamp = input->timestamp; } if (size) { size = opus_repacketizer_out(opus_data->enc_packer, output->buf, output_buf_len); if (size < 0) { PJ_LOG(4, (THIS_FILE, "Encode failed! (%d), out_size: %u", size, output_buf_len)); pj_mutex_unlock (opus_data->mutex); return PJMEDIA_CODEC_EFAILED; } } output->size = (unsigned)size; output->type = PJMEDIA_FRAME_TYPE_AUDIO; output->timestamp = input->timestamp; pj_mutex_unlock (opus_data->mutex); return PJ_SUCCESS; }
int opus_multistream_encode_float( #endif OpusMSEncoder *st, const opus_val16 *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes ) { int coupled_size; int mono_size; int s, i; char *ptr; int tot_size; VARDECL(opus_val16, buf); unsigned char tmp_data[MS_FRAME_TMP]; OpusRepacketizer rp; ALLOC_STACK; ALLOC(buf, 2*frame_size, opus_val16); ptr = (char*)st + align(sizeof(OpusMSEncoder)); coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); if (max_data_bytes < 4*st->layout.nb_streams-1) { RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; } /* Counting ToC */ tot_size = 0; for (s=0;s<st->layout.nb_streams;s++) { OpusEncoder *enc; int len; int curr_max; opus_repacketizer_init(&rp); enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams) { int left, right; left = get_left_channel(&st->layout, s, -1); right = get_right_channel(&st->layout, s, -1); for (i=0;i<frame_size;i++) { buf[2*i] = pcm[st->layout.nb_channels*i+left]; buf[2*i+1] = pcm[st->layout.nb_channels*i+right]; } ptr += align(coupled_size); } else { int chan = get_mono_channel(&st->layout, s, -1); for (i=0;i<frame_size;i++) buf[i] = pcm[st->layout.nb_channels*i+chan]; ptr += align(mono_size); } /* number of bytes left (+Toc) */ curr_max = max_data_bytes - tot_size; /* Reserve three bytes for the last stream and four for the others */ curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1); curr_max = IMIN(curr_max,MS_FRAME_TMP); len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max); if (len<0) { RESTORE_STACK; return len; } /* We need to use the repacketizer to add the self-delimiting lengths while taking into account the fact that the encoder can now return more than one frame at a time (e.g. 60 ms CELT-only) */ opus_repacketizer_cat(&rp, tmp_data, len); len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), data, max_data_bytes-tot_size, s != st->layout.nb_streams-1); data += len; tot_size += len; } RESTORE_STACK; return tot_size; }