.TH "opus_repacketizer" 3 "Fri Feb 11 2022" "Version 1.3.1" "Opus" \" -*- nroff -*- .ad l .nh .SH NAME opus_repacketizer \- Repacketizer .PP \- The repacketizer can be used to merge multiple Opus packets into a single packet or alternatively to split Opus packets that have previously been merged\&. .SH SYNOPSIS .br .PP .SS "Typedefs" .in +1c .ti -1c .RI "typedef struct \fBOpusRepacketizer\fP \fBOpusRepacketizer\fP" .br .in -1c .SS "Functions" .in +1c .ti -1c .RI "int \fBopus_repacketizer_get_size\fP (void)" .br .RI "Gets the size of an \fCOpusRepacketizer\fP structure\&. " .ti -1c .RI "\fBOpusRepacketizer\fP * \fBopus_repacketizer_init\fP (\fBOpusRepacketizer\fP *rp)" .br .RI "(Re)initializes a previously allocated repacketizer state\&. " .ti -1c .RI "\fBOpusRepacketizer\fP * \fBopus_repacketizer_create\fP (void)" .br .RI "Allocates memory and initializes the new repacketizer with \fBopus_repacketizer_init()\fP\&. " .ti -1c .RI "void \fBopus_repacketizer_destroy\fP (\fBOpusRepacketizer\fP *rp)" .br .RI "Frees an \fCOpusRepacketizer\fP allocated by \fBopus_repacketizer_create()\fP\&. " .ti -1c .RI "int \fBopus_repacketizer_cat\fP (\fBOpusRepacketizer\fP *rp, const unsigned char *data, \fBopus_int32\fP len)" .br .RI "Add a packet to the current repacketizer state\&. " .ti -1c .RI "\fBopus_int32\fP \fBopus_repacketizer_out_range\fP (\fBOpusRepacketizer\fP *rp, int begin, int end, unsigned char *data, \fBopus_int32\fP maxlen)" .br .RI "Construct a new packet from data previously submitted to the repacketizer state via \fBopus_repacketizer_cat()\fP\&. " .ti -1c .RI "int \fBopus_repacketizer_get_nb_frames\fP (\fBOpusRepacketizer\fP *rp)" .br .RI "Return the total number of frames contained in packet data submitted to the repacketizer state so far via \fBopus_repacketizer_cat()\fP since the last call to \fBopus_repacketizer_init()\fP or \fBopus_repacketizer_create()\fP\&. " .ti -1c .RI "\fBopus_int32\fP \fBopus_repacketizer_out\fP (\fBOpusRepacketizer\fP *rp, unsigned char *data, \fBopus_int32\fP maxlen)" .br .RI "Construct a new packet from data previously submitted to the repacketizer state via \fBopus_repacketizer_cat()\fP\&. " .ti -1c .RI "int \fBopus_packet_pad\fP (unsigned char *data, \fBopus_int32\fP len, \fBopus_int32\fP new_len)" .br .RI "Pads a given Opus packet to a larger size (possibly changing the TOC sequence)\&. " .ti -1c .RI "\fBopus_int32\fP \fBopus_packet_unpad\fP (unsigned char *data, \fBopus_int32\fP len)" .br .RI "Remove all padding from a given Opus packet and rewrite the TOC sequence to minimize space usage\&. " .ti -1c .RI "int \fBopus_multistream_packet_pad\fP (unsigned char *data, \fBopus_int32\fP len, \fBopus_int32\fP new_len, int nb_streams)" .br .RI "Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence)\&. " .ti -1c .RI "\fBopus_int32\fP \fBopus_multistream_packet_unpad\fP (unsigned char *data, \fBopus_int32\fP len, int nb_streams)" .br .RI "Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to minimize space usage\&. " .in -1c .SH "Detailed Description" .PP The repacketizer can be used to merge multiple Opus packets into a single packet or alternatively to split Opus packets that have previously been merged\&. Splitting valid Opus packets is always guaranteed to succeed, whereas merging valid packets only succeeds if all frames have the same mode, bandwidth, and frame size, and when the total duration of the merged packet is no more than 120 ms\&. The 120 ms limit comes from the specification and limits decoder memory requirements at a point where framing overhead becomes negligible\&. .PP The repacketizer currently only operates on elementary Opus streams\&. It will not manipualte multistream packets successfully, except in the degenerate case where they consist of data from a single stream\&. .PP The repacketizing process starts with creating a repacketizer state, either by calling \fBopus_repacketizer_create()\fP or by allocating the memory yourself, e\&.g\&., .PP .nf OpusRepacketizer *rp; rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size()); if (rp != NULL) opus_repacketizer_init(rp); .fi .PP .PP Then the application should submit packets with \fBopus_repacketizer_cat()\fP, extract new packets with \fBopus_repacketizer_out()\fP or \fBopus_repacketizer_out_range()\fP, and then reset the state for the next set of input packets via \fBopus_repacketizer_init()\fP\&. .PP For example, to split a sequence of packets into individual frames: .PP .nf unsigned char *data; int len; while (get_next_packet(&data, &len)) { unsigned char out[1276]; opus_int32 out_len; int nb_frames; int err; int i; err = opus_repacketizer_cat(rp, data, len); if (err != OPUS_OK) { release_packet(data); return err; } nb_frames = opus_repacketizer_get_nb_frames(rp); for (i = 0; i < nb_frames; i++) { out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out)); if (out_len < 0) { release_packet(data); return (int)out_len; } output_next_packet(out, out_len); } opus_repacketizer_init(rp); release_packet(data); } .fi .PP .PP Alternatively, to combine a sequence of frames into packets that each contain up to \fCTARGET_DURATION_MS\fP milliseconds of data: .PP .nf // The maximum number of packets with duration TARGET_DURATION_MS occurs // when the frame size is 2\&.5 ms, for a total of (TARGET_DURATION_MS*2/5) // packets\&. unsigned char *data[(TARGET_DURATION_MS*2/5)+1]; opus_int32 len[(TARGET_DURATION_MS*2/5)+1]; int nb_packets; unsigned char out[1277*(TARGET_DURATION_MS*2/2)]; opus_int32 out_len; int prev_toc; nb_packets = 0; while (get_next_packet(data+nb_packets, len+nb_packets)) { int nb_frames; int err; nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]); if (nb_frames < 1) { release_packets(data, nb_packets+1); return nb_frames; } nb_frames += opus_repacketizer_get_nb_frames(rp); // If adding the next packet would exceed our target, or it has an // incompatible TOC sequence, output the packets we already have before // submitting it\&. // N\&.B\&., The nb_packets > 0 check ensures we've submitted at least one // packet since the last call to opus_repacketizer_init()\&. Otherwise a // single packet longer than TARGET_DURATION_MS would cause us to try to // output an (invalid) empty packet\&. It also ensures that prev_toc has // been set to a valid value\&. Additionally, len[nb_packets] > 0 is // guaranteed by the call to opus_packet_get_nb_frames() above, so the // reference to data[nb_packets][0] should be valid\&. if (nb_packets > 0 && ( ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) || opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames > TARGET_DURATION_MS*48)) { out_len = opus_repacketizer_out(rp, out, sizeof(out)); if (out_len < 0) { release_packets(data, nb_packets+1); return (int)out_len; } output_next_packet(out, out_len); opus_repacketizer_init(rp); release_packets(data, nb_packets); data[0] = data[nb_packets]; len[0] = len[nb_packets]; nb_packets = 0; } err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]); if (err != OPUS_OK) { release_packets(data, nb_packets+1); return err; } prev_toc = data[nb_packets][0]; nb_packets++; } // Output the final, partial packet\&. if (nb_packets > 0) { out_len = opus_repacketizer_out(rp, out, sizeof(out)); release_packets(data, nb_packets); if (out_len < 0) return (int)out_len; output_next_packet(out, out_len); } .fi .PP .PP An alternate way of merging packets is to simply call \fBopus_repacketizer_cat()\fP unconditionally until it fails\&. At that point, the merged packet can be obtained with \fBopus_repacketizer_out()\fP and the input packet for which \fBopus_repacketizer_cat()\fP needs to be re-added to a newly reinitialized repacketizer state\&. .SH "Typedef Documentation" .PP .SS "typedef struct \fBOpusRepacketizer\fP \fBOpusRepacketizer\fP" .SH "Function Documentation" .PP .SS "int opus_multistream_packet_pad (unsigned char * data, \fBopus_int32\fP len, \fBopus_int32\fP new_len, int nb_streams)" .PP Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence)\&. .PP \fBParameters\fP .RS 4 \fIdata\fP \fCconst unsigned char*\fP: The buffer containing the packet to pad\&. .br \fIlen\fP \fCopus_int32\fP: The size of the packet\&. This must be at least 1\&. .br \fInew_len\fP \fCopus_int32\fP: The desired size of the packet after padding\&. This must be at least 1\&. .br \fInb_streams\fP \fCopus_int32\fP: The number of streams (not channels) in the packet\&. This must be at least as large as len\&. .RE .PP \fBReturns\fP .RS 4 an error code .RE .PP \fBReturn values\fP .RS 4 \fI\fBOPUS_OK\fP\fP \fIon\fP success\&. .br \fI\fBOPUS_BAD_ARG\fP\fP \fIlen\fP was less than 1\&. .br \fI\fBOPUS_INVALID_PACKET\fP\fP \fIdata\fP did not contain a valid Opus packet\&. .RE .PP .SS "\fBopus_int32\fP opus_multistream_packet_unpad (unsigned char * data, \fBopus_int32\fP len, int nb_streams)" .PP Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to minimize space usage\&. .PP \fBParameters\fP .RS 4 \fIdata\fP \fCconst unsigned char*\fP: The buffer containing the packet to strip\&. .br \fIlen\fP \fCopus_int32\fP: The size of the packet\&. This must be at least 1\&. .br \fInb_streams\fP \fCopus_int32\fP: The number of streams (not channels) in the packet\&. This must be at least 1\&. .RE .PP \fBReturns\fP .RS 4 The new size of the output packet on success, or an error code on failure\&. .RE .PP \fBReturn values\fP .RS 4 \fI\fBOPUS_BAD_ARG\fP\fP \fIlen\fP was less than 1 or new_len was less than len\&. .br \fI\fBOPUS_INVALID_PACKET\fP\fP \fIdata\fP did not contain a valid Opus packet\&. .RE .PP .SS "int opus_packet_pad (unsigned char * data, \fBopus_int32\fP len, \fBopus_int32\fP new_len)" .PP Pads a given Opus packet to a larger size (possibly changing the TOC sequence)\&. .PP \fBParameters\fP .RS 4 \fIdata\fP \fCconst unsigned char*\fP: The buffer containing the packet to pad\&. .br \fIlen\fP \fCopus_int32\fP: The size of the packet\&. This must be at least 1\&. .br \fInew_len\fP \fCopus_int32\fP: The desired size of the packet after padding\&. This must be at least as large as len\&. .RE .PP \fBReturns\fP .RS 4 an error code .RE .PP \fBReturn values\fP .RS 4 \fI\fBOPUS_OK\fP\fP \fIon\fP success\&. .br \fI\fBOPUS_BAD_ARG\fP\fP \fIlen\fP was less than 1 or new_len was less than len\&. .br \fI\fBOPUS_INVALID_PACKET\fP\fP \fIdata\fP did not contain a valid Opus packet\&. .RE .PP .SS "\fBopus_int32\fP opus_packet_unpad (unsigned char * data, \fBopus_int32\fP len)" .PP Remove all padding from a given Opus packet and rewrite the TOC sequence to minimize space usage\&. .PP \fBParameters\fP .RS 4 \fIdata\fP \fCconst unsigned char*\fP: The buffer containing the packet to strip\&. .br \fIlen\fP \fCopus_int32\fP: The size of the packet\&. This must be at least 1\&. .RE .PP \fBReturns\fP .RS 4 The new size of the output packet on success, or an error code on failure\&. .RE .PP \fBReturn values\fP .RS 4 \fI\fBOPUS_BAD_ARG\fP\fP \fIlen\fP was less than 1\&. .br \fI\fBOPUS_INVALID_PACKET\fP\fP \fIdata\fP did not contain a valid Opus packet\&. .RE .PP .SS "int opus_repacketizer_cat (\fBOpusRepacketizer\fP * rp, const unsigned char * data, \fBopus_int32\fP len)" .PP Add a packet to the current repacketizer state\&. This packet must match the configuration of any packets already submitted for repacketization since the last call to \fBopus_repacketizer_init()\fP\&. This means that it must have the same coding mode, audio bandwidth, frame size, and channel count\&. This can be checked in advance by examining the top 6 bits of the first byte of the packet, and ensuring they match the top 6 bits of the first byte of any previously submitted packet\&. The total duration of audio in the repacketizer state also must not exceed 120 ms, the maximum duration of a single packet, after adding this packet\&. .PP The contents of the current repacketizer state can be extracted into new packets using \fBopus_repacketizer_out()\fP or \fBopus_repacketizer_out_range()\fP\&. .PP In order to add a packet with a different configuration or to add more audio beyond 120 ms, you must clear the repacketizer state by calling \fBopus_repacketizer_init()\fP\&. If a packet is too large to add to the current repacketizer state, no part of it is added, even if it contains multiple frames, some of which might fit\&. If you wish to be able to add parts of such packets, you should first use another repacketizer to split the packet into pieces and add them individually\&. .PP \fBSee also\fP .RS 4 \fBopus_repacketizer_out_range\fP .PP \fBopus_repacketizer_out\fP .PP \fBopus_repacketizer_init\fP .RE .PP \fBParameters\fP .RS 4 \fIrp\fP \fCOpusRepacketizer*\fP: The repacketizer state to which to add the packet\&. .br \fIdata\fP \fCconst unsigned char*\fP: The packet data\&. The application must ensure this pointer remains valid until the next call to \fBopus_repacketizer_init()\fP or \fBopus_repacketizer_destroy()\fP\&. .br \fIlen\fP \fCopus_int32\fP: The number of bytes in the packet data\&. .RE .PP \fBReturns\fP .RS 4 An error code indicating whether or not the operation succeeded\&. .RE .PP \fBReturn values\fP .RS 4 \fI\fBOPUS_OK\fP\fP The packet's contents have been added to the repacketizer state\&. .br \fI\fBOPUS_INVALID_PACKET\fP\fP The packet did not have a valid TOC sequence, the packet's TOC sequence was not compatible with previously submitted packets (because the coding mode, audio bandwidth, frame size, or channel count did not match), or adding this packet would increase the total amount of audio stored in the repacketizer state to more than 120 ms\&. .RE .PP .SS "\fBOpusRepacketizer\fP * opus_repacketizer_create (void)" .PP Allocates memory and initializes the new repacketizer with \fBopus_repacketizer_init()\fP\&. .SS "void opus_repacketizer_destroy (\fBOpusRepacketizer\fP * rp)" .PP Frees an \fCOpusRepacketizer\fP allocated by \fBopus_repacketizer_create()\fP\&. .PP \fBParameters\fP .RS 4 \fIrp\fP \fCOpusRepacketizer*\fP: State to be freed\&. .RE .PP .SS "int opus_repacketizer_get_nb_frames (\fBOpusRepacketizer\fP * rp)" .PP Return the total number of frames contained in packet data submitted to the repacketizer state so far via \fBopus_repacketizer_cat()\fP since the last call to \fBopus_repacketizer_init()\fP or \fBopus_repacketizer_create()\fP\&. This defines the valid range of packets that can be extracted with \fBopus_repacketizer_out_range()\fP or \fBopus_repacketizer_out()\fP\&. .PP \fBParameters\fP .RS 4 \fIrp\fP \fCOpusRepacketizer*\fP: The repacketizer state containing the frames\&. .RE .PP \fBReturns\fP .RS 4 The total number of frames contained in the packet data submitted to the repacketizer state\&. .RE .PP .SS "int opus_repacketizer_get_size (void)" .PP Gets the size of an \fCOpusRepacketizer\fP structure\&. .PP \fBReturns\fP .RS 4 The size in bytes\&. .RE .PP .SS "\fBOpusRepacketizer\fP * opus_repacketizer_init (\fBOpusRepacketizer\fP * rp)" .PP (Re)initializes a previously allocated repacketizer state\&. The state must be at least the size returned by \fBopus_repacketizer_get_size()\fP\&. This can be used for applications which use their own allocator instead of malloc()\&. It must also be called to reset the queue of packets waiting to be repacketized, which is necessary if the maximum packet duration of 120 ms is reached or if you wish to submit packets with a different Opus configuration (coding mode, audio bandwidth, frame size, or channel count)\&. Failure to do so will prevent a new packet from being added with \fBopus_repacketizer_cat()\fP\&. .PP \fBSee also\fP .RS 4 \fBopus_repacketizer_create\fP .PP \fBopus_repacketizer_get_size\fP .PP \fBopus_repacketizer_cat\fP .RE .PP \fBParameters\fP .RS 4 \fIrp\fP \fCOpusRepacketizer*\fP: The repacketizer state to (re)initialize\&. .RE .PP \fBReturns\fP .RS 4 A pointer to the same repacketizer state that was passed in\&. .RE .PP .SS "\fBopus_int32\fP opus_repacketizer_out (\fBOpusRepacketizer\fP * rp, unsigned char * data, \fBopus_int32\fP maxlen)" .PP Construct a new packet from data previously submitted to the repacketizer state via \fBopus_repacketizer_cat()\fP\&. This is a convenience routine that returns all the data submitted so far in a single packet\&. It is equivalent to calling .PP .nf opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp), data, maxlen) .fi .PP .PP \fBParameters\fP .RS 4 \fIrp\fP \fCOpusRepacketizer*\fP: The repacketizer state from which to construct the new packet\&. .br \fIdata\fP \fCconst unsigned char*\fP: The buffer in which to store the output packet\&. .br \fImaxlen\fP \fCopus_int32\fP: The maximum number of bytes to store in the output buffer\&. In order to guarantee success, this should be at least \fC1277*opus_repacketizer_get_nb_frames(rp)\fP\&. However, \fC1*opus_repacketizer_get_nb_frames(rp)\fP plus the size of all packet data submitted to the repacketizer since the last call to \fBopus_repacketizer_init()\fP or \fBopus_repacketizer_create()\fP is also sufficient, and possibly much smaller\&. .RE .PP \fBReturns\fP .RS 4 The total size of the output packet on success, or an error code on failure\&. .RE .PP \fBReturn values\fP .RS 4 \fI\fBOPUS_BUFFER_TOO_SMALL\fP\fP \fImaxlen\fP was insufficient to contain the complete output packet\&. .RE .PP .SS "\fBopus_int32\fP opus_repacketizer_out_range (\fBOpusRepacketizer\fP * rp, int begin, int end, unsigned char * data, \fBopus_int32\fP maxlen)" .PP Construct a new packet from data previously submitted to the repacketizer state via \fBopus_repacketizer_cat()\fP\&. .PP \fBParameters\fP .RS 4 \fIrp\fP \fCOpusRepacketizer*\fP: The repacketizer state from which to construct the new packet\&. .br \fIbegin\fP \fCint\fP: The index of the first frame in the current repacketizer state to include in the output\&. .br \fIend\fP \fCint\fP: One past the index of the last frame in the current repacketizer state to include in the output\&. .br \fIdata\fP \fCconst unsigned char*\fP: The buffer in which to store the output packet\&. .br \fImaxlen\fP \fCopus_int32\fP: The maximum number of bytes to store in the output buffer\&. In order to guarantee success, this should be at least \fC1276\fP for a single frame, or for multiple frames, \fC1277*(end-begin)\fP\&. However, \fC1*(end-begin)\fP plus the size of all packet data submitted to the repacketizer since the last call to \fBopus_repacketizer_init()\fP or \fBopus_repacketizer_create()\fP is also sufficient, and possibly much smaller\&. .RE .PP \fBReturns\fP .RS 4 The total size of the output packet on success, or an error code on failure\&. .RE .PP \fBReturn values\fP .RS 4 \fI\fBOPUS_BAD_ARG\fP\fP \fC[begin,end)\fP was an invalid range of frames (begin < 0, begin >= end, or end > \fBopus_repacketizer_get_nb_frames()\fP)\&. .br \fI\fBOPUS_BUFFER_TOO_SMALL\fP\fP \fImaxlen\fP was insufficient to contain the complete output packet\&. .RE .PP .SH "Author" .PP Generated automatically by Doxygen for Opus from the source code\&.