void save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams){ int i, parsed_size; const unsigned char *subpkt; static const char *bw_strings[5]={"NB","MB","WB","SWB","FB"}; static const char *mode_strings[3]={"LP","HYB","MDCT"}; fprintf(frange,"%d, %d, ",frame_size,nbBytes); subpkt=packet; parsed_size=nbBytes; for(i=0;i<nb_streams;i++){ int j,payload_offset,nf; const unsigned char *frames[48]; unsigned char toc; short size[48]; payload_offset=0; nf=opus_packet_parse_impl(subpkt,parsed_size,i+1!=nb_streams, &toc,frames,size,&payload_offset); fprintf(frange,"[[%d",(int)(frames[0]-subpkt)); for(j=0;j<nf;j++)fprintf(frange,", %d",size[j]); fprintf(frange,"], %s, %s, %c, %d", mode_strings[((((subpkt[0]>>3)+48)&92)+4)>>5], bw_strings[opus_packet_get_bandwidth(subpkt)-OPUS_BANDWIDTH_NARROWBAND], subpkt[0]&4?'S':'M',opus_packet_get_samples_per_frame(subpkt,48000)); fprintf(frange,", %" I64uFORMAT "]%s",(unsigned long long)rngs[i],i+1==nb_streams?"\n":", "); parsed_size-=payload_offset; subpkt+=payload_offset; } }
JNIEXPORT jbyteArray JNICALL Java_aopus_OpusLibrary_decoderDecode (JNIEnv *env, jobject obj, jlong state, jbyteArray encodedData) { Decoder *decoder = (Decoder *)state; // copy managed to unmanaged int encodedLength = (* env)->GetArrayLength(env, encodedData); unsigned char *encodedDataBytes = malloc(encodedLength); (* env)->GetByteArrayRegion(env, encodedData, 0, encodedLength, encodedDataBytes); int numSamplesDecoded; int bandwidth = opus_packet_get_bandwidth(encodedDataBytes); if (bandwidth == OPUS_INVALID_PACKET) { numSamplesDecoded = opus_decode(decoder->dec, 0, 0, (opus_int16 *)decoder->buffer, decoder->frameSizePerChannel, 0); decoder->previousPacketInvalid = 1; } else { numSamplesDecoded = opus_decode(decoder->dec, encodedDataBytes, encodedLength, (opus_int16 *)decoder->buffer, decoder->frameSizePerChannel, decoder->previousPacketInvalid); decoder->previousPacketInvalid = 0; } free(encodedDataBytes); if (numSamplesDecoded > 0) { // copy unmanaged to managed int frameLength = numSamplesDecoded * decoder->channels * 2; jbyteArray frame = (* env)->NewByteArray(env, frameLength); // 2 bytes per sample (* env)->SetByteArrayRegion(env, frame, 0, frameLength, decoder->buffer); return frame; } return NULL; }
int opus_decode_native(OpusDecoder *st, const unsigned char *data, int len, opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, int *packet_offset) { int i, nb_samples; int count, offset; unsigned char toc; int tot_offset; /* 48 x 2.5 ms = 120 ms */ short size[48]; if (decode_fec<0 || decode_fec>1) return OPUS_BAD_ARG; if (len==0 || data==NULL) return opus_decode_frame(st, NULL, 0, pcm, frame_size, 0); else if (len<0) return OPUS_BAD_ARG; tot_offset = 0; st->mode = opus_packet_get_mode(data); st->bandwidth = opus_packet_get_bandwidth(data); st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs); st->stream_channels = opus_packet_get_nb_channels(data); count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset); if (count < 0) return count; data += offset; tot_offset += offset; if (count*st->frame_size > frame_size) return OPUS_BUFFER_TOO_SMALL; nb_samples=0; for (i=0;i<count;i++) { int ret; ret = opus_decode_frame(st, data, size[i], pcm, frame_size-nb_samples, decode_fec); if (ret<0) return ret; data += size[i]; tot_offset += size[i]; pcm += ret*st->channels; nb_samples += ret; } if (packet_offset != NULL) *packet_offset = tot_offset; return nb_samples; }
static pj_status_t opus_codec_parse(pjmedia_codec *codec, void *pkt, pj_size_t pkt_size, const pj_timestamp *ts, unsigned *frame_cnt, pjmedia_frame frames[]) { struct opus_private *opus; unsigned char toc; const unsigned char *raw_frames[48]; short size[48]; int payload_offset, samples_per_frame; unsigned i; PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL); opus = (struct opus_private *)codec->codec_data; *frame_cnt = opus_packet_parse(pkt, pkt_size, &toc, raw_frames, size, &payload_offset); samples_per_frame = opus_packet_get_samples_per_frame(pkt, opus->externalFs); #if _TRACE_OPUS PJ_LOG(4, (THIS_FILE, "Pkt info : bw -> %d , spf -> %d, offset %d, packet_size %d", opus_packet_get_bandwidth(pkt), samples_per_frame, payload_offset, pkt_size)); #endif for (i = 0; i < *frame_cnt; i++) { frames[i].type = PJMEDIA_FRAME_TYPE_AUDIO; frames[i].bit_info = (((unsigned)ts->u64 & 0xFFFF) << 16) | (((unsigned)pkt & 0xFF) << 8) | i; frames[i].buf = pkt; frames[i].size = pkt_size; frames[i].timestamp.u64 = ts->u64 * opus->externalFs / OPUS_CLOCK_RATE + i * samples_per_frame; #if _TRACE_OPUS PJ_LOG(4, (THIS_FILE, "parsed %d of %d", frames[i].size, *frame_cnt)); #endif } return PJ_SUCCESS; }
JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_packet_1get_1bandwidth (JNIEnv *env, jclass clazz, jbyteArray data, jint offset) { int ret; if (data) { jbyte *data_ = (*env)->GetPrimitiveArrayCritical(env, data, NULL); if (data_) { ret = opus_packet_get_bandwidth((unsigned char *) (data_ + offset)); (*env)->ReleasePrimitiveArrayCritical(env, data, data_, JNI_ABORT); } else ret = OPUS_ALLOC_FAIL; } else ret = OPUS_BAD_ARG; return ret; }
/** * Output debug information regarding the state of a single Opus packet */ void DebugFrameInfoInternal(const uint8* PacketData, uint32 PacketLength, uint32 SampleRate, bool bEncode) { int32 NumFrames = opus_packet_get_nb_frames(PacketData, PacketLength); if (NumFrames == OPUS_BAD_ARG || NumFrames == OPUS_INVALID_PACKET) { UE_LOG(LogVoice, Warning, TEXT("opus_packet_get_nb_frames: Invalid voice packet data!")); } int32 NumSamples = opus_packet_get_nb_samples(PacketData, PacketLength, SampleRate); if (NumSamples == OPUS_BAD_ARG || NumSamples == OPUS_INVALID_PACKET) { UE_LOG(LogVoice, Warning, TEXT("opus_packet_get_nb_samples: Invalid voice packet data!")); } int32 NumSamplesPerFrame = opus_packet_get_samples_per_frame(PacketData, SampleRate); int32 Bandwidth = opus_packet_get_bandwidth(PacketData); const TCHAR* BandwidthStr = NULL; switch (Bandwidth) { case OPUS_BANDWIDTH_NARROWBAND: // Narrowband (4kHz bandpass) BandwidthStr = TEXT("NB"); break; case OPUS_BANDWIDTH_MEDIUMBAND: // Mediumband (6kHz bandpass) BandwidthStr = TEXT("MB"); break; case OPUS_BANDWIDTH_WIDEBAND: // Wideband (8kHz bandpass) BandwidthStr = TEXT("WB"); break; case OPUS_BANDWIDTH_SUPERWIDEBAND: // Superwideband (12kHz bandpass) BandwidthStr = TEXT("SWB"); break; case OPUS_BANDWIDTH_FULLBAND: // Fullband (20kHz bandpass) BandwidthStr = TEXT("FB"); break; case OPUS_INVALID_PACKET: default: BandwidthStr = TEXT("Invalid"); break; } /* * 0 * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * | config |s| c | * +-+-+-+-+-+-+-+-+ */ uint8 TOC; // (max 48 x 2.5ms frames in a packet = 120ms) const uint8* frames[48]; int16 size[48]; int32 payload_offset = 0; int32 NumFramesParsed = opus_packet_parse(PacketData, PacketLength, &TOC, frames, size, &payload_offset); // Frame Encoding see http://tools.ietf.org/html/rfc6716#section-3.1 int32 TOCEncoding = (TOC & 0xf8) >> 3; // Number of channels bool TOCStereo = (TOC & 0x4) != 0 ? true : false; // Number of frames and their configuration // 0: 1 frame in the packet // 1: 2 frames in the packet, each with equal compressed size // 2: 2 frames in the packet, with different compressed sizes // 3: an arbitrary number of frames in the packet int32 TOCMode = TOC & 0x3; if (bEncode) { UE_LOG(LogVoiceEncode, Verbose, TEXT("PacketLength: %d NumFrames: %d NumSamples: %d Bandwidth: %s Encoding: %d Stereo: %d FrameDesc: %d"), PacketLength, NumFrames, NumSamples, BandwidthStr, TOCEncoding, TOCStereo, TOCMode); } else { UE_LOG(LogVoiceDecode, Verbose, TEXT("PacketLength: %d NumFrames: %d NumSamples: %d Bandwidth: %s Encoding: %d Stereo: %d FrameDesc: %d"), PacketLength, NumFrames, NumSamples, BandwidthStr, TOCEncoding, TOCStereo, TOCMode); } }
void ac_iterate(ACSession *ac) { if (!ac) { return; } /* TODO(mannol): fix this and jitter buffering */ /* Enough space for the maximum frame size (120 ms 48 KHz stereo audio) */ int16_t tmp[5760 * 2]; struct RTPMessage *msg; int rc = 0; pthread_mutex_lock(ac->queue_mutex); while ((msg = jbuf_read((struct JitterBuffer *)ac->j_buf, &rc)) || rc == 2) { pthread_mutex_unlock(ac->queue_mutex); if (rc == 2) { LOGGER_DEBUG(ac->log, "OPUS correction"); int fs = (ac->lp_sampling_rate * ac->lp_frame_duration) / 1000; rc = opus_decode(ac->decoder, NULL, 0, tmp, fs, 1); } else { /* Get values from packet and decode. */ /* NOTE: This didn't work very well */ #if 0 rc = convert_bw_to_sampling_rate(opus_packet_get_bandwidth(msg->data)); if (rc != -1) { cs->last_packet_sampling_rate = rc; } else { LOGGER_WARNING(ac->log, "Failed to load packet values!"); rtp_free_msg(msg); continue; } #endif /* Pick up sampling rate from packet */ memcpy(&ac->lp_sampling_rate, msg->data, 4); ac->lp_sampling_rate = net_ntohl(ac->lp_sampling_rate); ac->lp_channel_count = opus_packet_get_nb_channels(msg->data + 4); /** NOTE: even though OPUS supports decoding mono frames with stereo decoder and vice versa, * it didn't work quite well. */ if (!reconfigure_audio_decoder(ac, ac->lp_sampling_rate, ac->lp_channel_count)) { LOGGER_WARNING(ac->log, "Failed to reconfigure decoder!"); free(msg); continue; } rc = opus_decode(ac->decoder, msg->data + 4, msg->len - 4, tmp, 5760, 0); free(msg); } if (rc < 0) { LOGGER_WARNING(ac->log, "Decoding error: %s", opus_strerror(rc)); } else if (ac->acb.first) { ac->lp_frame_duration = (rc * 1000) / ac->lp_sampling_rate; ac->acb.first(ac->av, ac->friend_number, tmp, rc, ac->lp_channel_count, ac->lp_sampling_rate, ac->acb.second); } return; } pthread_mutex_unlock(ac->queue_mutex); }
int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, opus_int32 *packet_offset, int soft_clip) { int i, nb_samples; int count, offset; unsigned char toc; int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; /* 48 x 2.5 ms = 120 ms */ opus_int16 size[48]; if (decode_fec<0 || decode_fec>1) return OPUS_BAD_ARG; /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) return OPUS_BAD_ARG; if (len==0 || data==NULL) { int pcm_count=0; do { int ret; ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0); if (ret<0) return ret; pcm_count += ret; } while (pcm_count < frame_size); celt_assert(pcm_count == frame_size); if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels)) OPUS_PRINT_INT(pcm_count); st->last_packet_duration = pcm_count; return pcm_count; } else if (len<0) return OPUS_BAD_ARG; packet_mode = opus_packet_get_mode(data); packet_bandwidth = opus_packet_get_bandwidth(data); packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); packet_stream_channels = opus_packet_get_nb_channels(data); count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset, packet_offset); if (count<0) return count; data += offset; if (decode_fec) { int duration_copy; int ret; /* If no FEC can be present, run the PLC (recursive call) */ if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); /* Otherwise, run the PLC on everything except the size for which we might have FEC */ duration_copy = st->last_packet_duration; if (frame_size-packet_frame_size!=0) { ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); if (ret<0) { st->last_packet_duration = duration_copy; return ret; } celt_assert(ret==frame_size-packet_frame_size); } /* Complete with FEC */ st->mode = packet_mode; st->bandwidth = packet_bandwidth; st->frame_size = packet_frame_size; st->stream_channels = packet_stream_channels; ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), packet_frame_size, 1); if (ret<0) return ret; else { if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels)) OPUS_PRINT_INT(frame_size); st->last_packet_duration = frame_size; return frame_size; } } if (count*packet_frame_size > frame_size) return OPUS_BUFFER_TOO_SMALL; /* Update the state as the last step to avoid updating it on an invalid packet */ st->mode = packet_mode; st->bandwidth = packet_bandwidth; st->frame_size = packet_frame_size; st->stream_channels = packet_stream_channels; nb_samples=0; for (i=0; i<count; i++) { int ret; ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0); if (ret<0) return ret; celt_assert(ret==packet_frame_size); data += size[i]; nb_samples += ret; } st->last_packet_duration = nb_samples; if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels)) OPUS_PRINT_INT(nb_samples); #ifndef FIXED_POINT if (soft_clip) opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem); else st->softclip_mem[0]=st->softclip_mem[1]=0; #endif return nb_samples; }
static GstFlowReturn opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf, GstClockTime timestamp, GstClockTime duration) { GstFlowReturn res = GST_FLOW_OK; gint size; guint8 *data; GstBuffer *outbuf; gint16 *out_data; int n; if (timestamp != -1) { dec->segment.last_stop = timestamp; dec->granulepos = -1; } if (dec->state == NULL) { GstCaps *caps; dec->state = opus_decoder_create (dec->sample_rate, dec->n_channels); /* set caps */ caps = gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, dec->sample_rate, "channels", G_TYPE_INT, dec->n_channels, "signed", G_TYPE_BOOLEAN, TRUE, "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL); GST_DEBUG_OBJECT (dec, "rate=%d channels=%d frame-size=%d", dec->sample_rate, dec->n_channels, dec->frame_size); if (!gst_pad_set_caps (dec->srcpad, caps)) GST_ERROR ("nego failure"); gst_caps_unref (caps); } if (buf) { data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); GST_DEBUG_OBJECT (dec, "received buffer of size %u", size); /* copy timestamp */ } else { /* concealment data, pass NULL as the bits parameters */ GST_DEBUG_OBJECT (dec, "creating concealment data"); data = NULL; size = 0; } GST_DEBUG ("bandwidth %d", opus_packet_get_bandwidth (data)); GST_DEBUG ("samples_per_frame %d", opus_packet_get_samples_per_frame (data, 48000)); GST_DEBUG ("channels %d", opus_packet_get_nb_channels (data)); res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE, dec->frame_samples * dec->n_channels * 2, GST_PAD_CAPS (dec->srcpad), &outbuf); if (res != GST_FLOW_OK) { GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res)); return res; } out_data = (gint16 *) GST_BUFFER_DATA (outbuf); GST_LOG_OBJECT (dec, "decoding frame"); n = opus_decode (dec->state, data, size, out_data, dec->frame_samples, TRUE); if (n < 0) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Decoding error: %d", n), (NULL)); return GST_FLOW_ERROR; } if (!GST_CLOCK_TIME_IS_VALID (timestamp)) { timestamp = gst_util_uint64_scale_int (dec->granulepos - dec->frame_size, GST_SECOND, dec->sample_rate); } GST_DEBUG_OBJECT (dec, "timestamp=%" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf); if (dec->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); dec->discont = 0; } dec->segment.last_stop += dec->frame_duration; GST_LOG_OBJECT (dec, "pushing buffer with ts=%" GST_TIME_FORMAT ", dur=%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), GST_TIME_ARGS (dec->frame_duration)); res = gst_pad_push (dec->srcpad, outbuf); if (res != GST_FLOW_OK) GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res)); return res; }
int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, int *packet_offset) { int i, nb_samples; int count, offset; unsigned char toc; int tot_offset; int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; /* 48 x 2.5 ms = 120 ms */ short size[48]; if (decode_fec<0 || decode_fec>1) return OPUS_BAD_ARG; /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) return OPUS_BAD_ARG; if (len==0 || data==NULL) { int pcm_count=0; do { int ret; ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-pcm_count, 0); if (ret<0) return ret; pcm += st->channels*ret; pcm_count += ret; } while (pcm_count < frame_size); st->last_packet_duration = pcm_count; return pcm_count; } else if (len<0) return OPUS_BAD_ARG; packet_mode = opus_packet_get_mode(data); packet_bandwidth = opus_packet_get_bandwidth(data); packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); packet_stream_channels = opus_packet_get_nb_channels(data); count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset); data += offset; if (decode_fec) { int duration_copy; int ret; /* If no FEC can be present, run the PLC (recursive call) */ if (frame_size <= packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL); /* Otherwise, run the PLC on everything except the size for which we might have FEC */ duration_copy = st->last_packet_duration; ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL); if (ret<0) { st->last_packet_duration = duration_copy; return ret; } /* Complete with FEC */ st->mode = packet_mode; st->bandwidth = packet_bandwidth; st->frame_size = packet_frame_size; st->stream_channels = packet_stream_channels; ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), packet_frame_size, 1); if (ret<0) return ret; st->last_packet_duration = frame_size; return frame_size; } tot_offset = 0; if (count < 0) return count; tot_offset += offset; if (count*packet_frame_size > frame_size) return OPUS_BUFFER_TOO_SMALL; /* Update the state as the last step to avoid updating it on an invalid packet */ st->mode = packet_mode; st->bandwidth = packet_bandwidth; st->frame_size = packet_frame_size; st->stream_channels = packet_stream_channels; nb_samples=0; for (i=0;i<count;i++) { int ret; ret = opus_decode_frame(st, data, size[i], pcm, frame_size-nb_samples, decode_fec); if (ret<0) return ret; data += size[i]; tot_offset += size[i]; pcm += ret*st->channels; nb_samples += ret; } if (packet_offset != NULL) *packet_offset = tot_offset; st->last_packet_duration = nb_samples; return nb_samples; }