// FIXME THIS METHOD FAILS IN TEST_OPUS_ENCODE /** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to * minimize space usage. * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the * packet to strip. * @param len <tt>opus_int32</tt>: The size of the packet. * This must be at least 1. * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet. * This must be at least 1. * @returns The new size of the output packet on success, or an error code * on failure. * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. */ public static int UnpadMultistreamPacket(byte[] data, int data_offset, int len, int nb_streams) { int s; byte dummy_toc; short[] size = new short[48]; int packet_offset; int dummy_offset; OpusRepacketizer rp = new OpusRepacketizer(); int dst; int dst_len; if (len < 1) { return(OpusError.OPUS_BAD_ARG); } dst = data_offset; dst_len = 0; /* Unpad all frames */ for (s = 0; s < nb_streams; s++) { int ret; int self_delimited = ((s != nb_streams) ? 1 : 0) - 1; if (len <= 0) { return(OpusError.OPUS_INVALID_PACKET); } rp.Reset(); ret = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, self_delimited, out dummy_toc, null, null, 0, size, 0, out dummy_offset, out packet_offset); if (ret < 0) { return(ret); } ret = rp.opus_repacketizer_cat_impl(data, data_offset, packet_offset, self_delimited); if (ret < 0) { return(ret); } ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, dst, len, self_delimited, 0); if (ret < 0) { return(ret); } else { dst_len += ret; } dst += ret; data_offset += packet_offset; len -= packet_offset; } return(dst_len); }
internal int opus_repacketizer_cat_impl(byte[] data, int data_ptr, int len, int self_delimited) { byte dummy_toc; int dummy_offset; int curr_nb_frames, ret; /* Set of check ToC */ if (len < 1) { return(OpusError.OPUS_INVALID_PACKET); } if (this.nb_frames == 0) { this.toc = data[data_ptr]; this.framesize = OpusPacketInfo.GetNumSamplesPerFrame(data, data_ptr, 8000); } else if ((this.toc & 0xFC) != (data[data_ptr] & 0xFC)) { /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp.toc, data[0]);*/ return(OpusError.OPUS_INVALID_PACKET); } curr_nb_frames = OpusPacketInfo.GetNumFrames(data, data_ptr, len); if (curr_nb_frames < 1) { return(OpusError.OPUS_INVALID_PACKET); } /* Check the 120 ms maximum packet size */ if ((curr_nb_frames + this.nb_frames) * this.framesize > 960) { return(OpusError.OPUS_INVALID_PACKET); } ret = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, out dummy_toc, this.frames, this.frames_ptrs, this.nb_frames, this.len, this.nb_frames, out dummy_offset, out dummy_offset); if (ret < 1) { return(ret); } this.nb_frames += curr_nb_frames; return(OpusError.OPUS_OK); }
/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence). * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the * packet to pad. * @param len <tt>opus_int32</tt>: The size of the packet. * This must be at least 1. * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding. * This must be at least 1. * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet. * This must be at least as large as len. * @returns an error code * @retval #OPUS_OK \a on success. * @retval #OPUS_BAD_ARG \a len was less than 1. * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. */ public static int PadMultistreamPacket(byte[] data, int data_offset, int len, int new_len, int nb_streams) { int s; int count; byte dummy_toc; short[] size = new short[48]; int packet_offset; int dummy_offset; int amount; if (len < 1) { return(OpusError.OPUS_BAD_ARG); } if (len == new_len) { return(OpusError.OPUS_OK); } else if (len > new_len) { return(OpusError.OPUS_BAD_ARG); } amount = new_len - len; /* Seek to last stream */ for (s = 0; s < nb_streams - 1; s++) { if (len <= 0) { return(OpusError.OPUS_INVALID_PACKET); } count = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, 1, out dummy_toc, null, null, 0, size, 0, out dummy_offset, out packet_offset); if (count < 0) { return(count); } data_offset += packet_offset; len -= packet_offset; } return(PadPacket(data, data_offset, len, len + amount)); }
internal static int opus_multistream_packet_validate(byte[] data, int data_ptr, int len, int nb_streams, int Fs) { int s; int count; byte toc; short[] size = new short[48]; int samples = 0; int packet_offset; int dummy; for (s = 0; s < nb_streams; s++) { int tmp_samples; if (len <= 0) { return(OpusError.OPUS_INVALID_PACKET); } count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, (s != nb_streams - 1) ? 1 : 0, out toc, null, null, 0, size, 0, out dummy, out packet_offset); if (count < 0) { return(count); } tmp_samples = OpusPacketInfo.GetNumSamples(data, data_ptr, packet_offset, Fs); if (s != 0 && samples != tmp_samples) { return(OpusError.OPUS_INVALID_PACKET); } samples = tmp_samples; data_ptr += packet_offset; len -= packet_offset; } return(samples); }
internal int opus_decode_native(byte[] data, int data_ptr, int len, short[] pcm_out, int pcm_out_ptr, int frame_size, int decode_fec, int self_delimited, out int packet_offset, int soft_clip) { int i, nb_samples; int count, offset; byte toc; int packet_frame_size, packet_stream_channels; packet_offset = 0; OpusBandwidth packet_bandwidth; OpusMode packet_mode; /* 48 x 2.5 ms = 120 ms */ // fixme: make sure these values can fit in an int16 short[] size = new short[48]; if (decode_fec < 0 || decode_fec > 1) { return(OpusError.OPUS_BAD_ARG); } /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ if ((decode_fec != 0 || len == 0 || data == null) && frame_size % (this.Fs / 400) != 0) { return(OpusError.OPUS_BAD_ARG); } if (len == 0 || data == null) { int pcm_count = 0; do { int ret; ret = opus_decode_frame(null, 0, 0, pcm_out, pcm_out_ptr + (pcm_count * this.channels), frame_size - pcm_count, 0); if (ret < 0) { return(ret); } pcm_count += ret; } while (pcm_count < frame_size); Inlines.OpusAssert(pcm_count == frame_size); this.last_packet_duration = pcm_count; return(pcm_count); } else if (len < 0) { return(OpusError.OPUS_BAD_ARG); } packet_mode = OpusPacketInfo.GetEncoderMode(data, data_ptr); packet_bandwidth = OpusPacketInfo.GetBandwidth(data, data_ptr); packet_frame_size = OpusPacketInfo.GetNumSamplesPerFrame(data, data_ptr, this.Fs); packet_stream_channels = OpusPacketInfo.GetNumEncodedChannels(data, data_ptr); count = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, out toc, null, null, 0, size, 0, out offset, out packet_offset); if (count < 0) { return(count); } data_ptr += offset; if (decode_fec != 0) { int dummy; int duration_copy; int ret; /* If no FEC can be present, run the PLC (recursive call) */ if (frame_size < packet_frame_size || packet_mode == OpusMode.MODE_CELT_ONLY || this.mode == OpusMode.MODE_CELT_ONLY) { return(opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size, 0, 0, out dummy, soft_clip)); } /* Otherwise, run the PLC on everything except the size for which we might have FEC */ duration_copy = this.last_packet_duration; if (frame_size - packet_frame_size != 0) { ret = opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size - packet_frame_size, 0, 0, out dummy, soft_clip); if (ret < 0) { this.last_packet_duration = duration_copy; return(ret); } Inlines.OpusAssert(ret == frame_size - packet_frame_size); } /* Complete with FEC */ this.mode = packet_mode; this.bandwidth = packet_bandwidth; this.frame_size = packet_frame_size; this.stream_channels = packet_stream_channels; ret = opus_decode_frame(data, data_ptr, size[0], pcm_out, pcm_out_ptr + (this.channels * (frame_size - packet_frame_size)), packet_frame_size, 1); if (ret < 0) { return(ret); } else { this.last_packet_duration = frame_size; return(frame_size); } } if (count * packet_frame_size > frame_size) { return(OpusError.OPUS_BUFFER_TOO_SMALL); } /* Update the state as the last step to avoid updating it on an invalid packet */ this.mode = packet_mode; this.bandwidth = packet_bandwidth; this.frame_size = packet_frame_size; this.stream_channels = packet_stream_channels; nb_samples = 0; for (i = 0; i < count; i++) { int ret; ret = opus_decode_frame(data, data_ptr, size[i], pcm_out, pcm_out_ptr + (nb_samples * this.channels), frame_size - nb_samples, 0); if (ret < 0) { return(ret); } Inlines.OpusAssert(ret == packet_frame_size); data_ptr += size[i]; nb_samples += ret; } this.last_packet_duration = nb_samples; return(nb_samples); }