Skip to main content

rusty_opus/
multistream.rs

1//! Opus multistream (surround) — port of the core of
2//! `src/opus_multistream_{encoder,decoder}.c`. Wraps N mono/coupled Opus
3//! coders behind a channel-mapping layout so >2-channel audio (quad, 5.1,
4//! 7.1) can be coded as a set of standard Opus streams concatenated with the
5//! self-delimited framing.
6//!
7//! The channel bitrate allocation here is a simple even split across streams
8//! (coupled streams get 2x a mono stream's share) — libopus adds a
9//! surround-masking analysis on top, a quality refinement, not a conformance
10//! requirement. The bitstream layout, mapping, and per-stream Opus coding are
11//! standard, so streams interoperate with libopus.
12
13use crate::Error;
14use crate::repacketizer::{Repacketizer, parse_frames};
15use crate::{Application, Bandwidth, OpusDecoder, OpusEncoder};
16
17/// Vorbis channel layout for mapping family 1, channels 1..=8:
18/// (nb_streams, nb_coupled_streams, channel_mapping).
19const VORBIS_MAPPINGS: [(usize, usize, &[u8]); 8] = [
20    (1, 0, &[0]),                      // mono
21    (1, 1, &[0, 1]),                   // stereo
22    (2, 1, &[0, 2, 1]),                // 1-d (3.0)
23    (2, 2, &[0, 1, 2, 3]),             // quad
24    (3, 2, &[0, 4, 1, 2, 3]),          // 5.0
25    (4, 2, &[0, 4, 1, 2, 3, 5]),       // 5.1
26    (4, 3, &[0, 4, 1, 2, 3, 5, 6]),    // 6.1
27    (5, 3, &[0, 6, 1, 2, 3, 4, 5, 7]), // 7.1
28];
29
30/// How the channels of a multistream signal map onto mono and stereo
31/// (coupled) Opus streams (RFC 7845 channel mapping).
32#[derive(Clone)]
33pub struct ChannelLayout {
34    /// Total output channels.
35    pub nb_channels: usize,
36    /// Number of Opus streams in each packet.
37    pub nb_streams: usize,
38    /// How many of those streams are stereo (coupled); they come first.
39    pub nb_coupled_streams: usize,
40    /// For each output channel, the decoded channel index it takes.
41    pub mapping: Vec<u8>,
42}
43
44impl ChannelLayout {
45    /// Standard layout for a channel count + mapping family (0 = mono/stereo,
46    /// 1 = Vorbis surround for 1..=8 channels).
47    ///
48    /// # Errors
49    ///
50    /// [`Error::BadArg`] if `mapping_family` is not 0 or 1, or `channels` is out
51    /// of range for it (1–2 for family 0, 1–8 for family 1).
52    pub fn surround(channels: usize, mapping_family: i32) -> Result<Self, Error> {
53        match mapping_family {
54            0 => {
55                if channels == 1 {
56                    Ok(Self {
57                        nb_channels: 1,
58                        nb_streams: 1,
59                        nb_coupled_streams: 0,
60                        mapping: vec![0],
61                    })
62                } else if channels == 2 {
63                    Ok(Self {
64                        nb_channels: 2,
65                        nb_streams: 1,
66                        nb_coupled_streams: 1,
67                        mapping: vec![0, 1],
68                    })
69                } else {
70                    Err(Error::BadArg("family 0 supports only 1-2 channels"))
71                }
72            }
73            1 => {
74                if !(1..=8).contains(&channels) {
75                    return Err(Error::BadArg("family 1 supports 1-8 channels"));
76                }
77                let (ns, nc, m) = VORBIS_MAPPINGS[channels - 1];
78                Ok(Self {
79                    nb_channels: channels,
80                    nb_streams: ns,
81                    nb_coupled_streams: nc,
82                    mapping: m.to_vec(),
83                })
84            }
85            _ => Err(Error::BadArg("unsupported mapping family")),
86        }
87    }
88
89    fn left_channel(&self, stream_id: usize, prev: i32) -> i32 {
90        let start = if prev < 0 { 0 } else { prev as usize + 1 };
91        for (i, &m) in self.mapping.iter().enumerate().skip(start) {
92            if m as usize == stream_id * 2 {
93                return i as i32;
94            }
95        }
96        -1
97    }
98    fn right_channel(&self, stream_id: usize, prev: i32) -> i32 {
99        let start = if prev < 0 { 0 } else { prev as usize + 1 };
100        for (i, &m) in self.mapping.iter().enumerate().skip(start) {
101            if m as usize == stream_id * 2 + 1 {
102                return i as i32;
103            }
104        }
105        -1
106    }
107    fn mono_channel(&self, stream_id: usize, prev: i32) -> i32 {
108        let start = if prev < 0 { 0 } else { prev as usize + 1 };
109        for (i, &m) in self.mapping.iter().enumerate().skip(start) {
110            if m as usize == stream_id + self.nb_coupled_streams {
111                return i as i32;
112            }
113        }
114        -1
115    }
116}
117
118/// Multistream encoder: one Opus encoder per stream (coupled = stereo, the
119/// rest mono), coded per the channel layout and concatenated self-delimited.
120pub struct OpusMSEncoder {
121    layout: ChannelLayout,
122    encoders: Vec<OpusEncoder>,
123    sample_rate: i32,
124    /// Total target bitrate across all streams (split evenly, coupled=2x mono).
125    pub bitrate_bps: i32,
126}
127
128impl OpusMSEncoder {
129    /// A surround encoder for `channels` channels with the standard layout of
130    /// `mapping_family` (see [`ChannelLayout::surround`]).
131    ///
132    /// # Errors
133    ///
134    /// [`Error::BadArg`] for an unsupported channel count / mapping family, or any
135    /// error from creating the per-stream encoders.
136    pub fn new(
137        sample_rate: i32,
138        channels: usize,
139        mapping_family: i32,
140        application: Application,
141    ) -> Result<Self, Error> {
142        let layout = ChannelLayout::surround(channels, mapping_family)?;
143        let mut encoders = Vec::with_capacity(layout.nb_streams);
144        for s in 0..layout.nb_streams {
145            let ch = if s < layout.nb_coupled_streams { 2 } else { 1 };
146            encoders.push(OpusEncoder::new(sample_rate, ch, application)?);
147        }
148        let mut enc = Self {
149            layout,
150            encoders,
151            sample_rate,
152            bitrate_bps: 64000 * channels as i32,
153        };
154        enc.set_bitrate(enc.bitrate_bps);
155        Ok(enc)
156    }
157
158    /// Split the total bitrate across streams (each coupled stream gets 2x a
159    /// mono stream's share, matching its 2 channels).
160    pub fn set_bitrate(&mut self, total: i32) {
161        self.bitrate_bps = total;
162        let units = self.layout.nb_coupled_streams * 2
163            + (self.layout.nb_streams - self.layout.nb_coupled_streams);
164        let per_unit = if units > 0 {
165            total / units as i32
166        } else {
167            total
168        };
169        for (s, e) in self.encoders.iter_mut().enumerate() {
170            e.bitrate_bps = if s < self.layout.nb_coupled_streams {
171                per_unit * 2
172            } else {
173                per_unit
174            };
175        }
176    }
177
178    /// Number of Opus streams in each multistream packet.
179    pub fn nb_streams(&self) -> usize {
180        self.layout.nb_streams
181    }
182
183    /// Encode one frame of interleaved `input` (nb_channels per sample) into a
184    /// multistream packet. `scratch` output is returned as a Vec.
185    ///
186    /// # Errors
187    ///
188    /// Any error from the per-stream [`crate::OpusEncoder::encode`] calls or from
189    /// assembling the self-delimited multistream packet.
190    pub fn encode(&mut self, input: &[f32], frame_size: usize) -> Result<Vec<u8>, Error> {
191        let nch = self.layout.nb_channels;
192        let mut out: Vec<u8> = Vec::new();
193        let mut stream_buf = vec![0f32; frame_size * 2];
194        let mut pkt = vec![0u8; 1500 + frame_size];
195
196        for s in 0..self.layout.nb_streams {
197            let coupled = s < self.layout.nb_coupled_streams;
198            let sch = if coupled { 2 } else { 1 };
199            // Gather this stream's channels from the interleaved input.
200            if coupled {
201                let l = self.layout.left_channel(s, -1);
202                let r = self.layout.right_channel(s, -1);
203                for i in 0..frame_size {
204                    stream_buf[i * 2] = if l >= 0 {
205                        input[i * nch + l as usize]
206                    } else {
207                        0.0
208                    };
209                    stream_buf[i * 2 + 1] = if r >= 0 {
210                        input[i * nch + r as usize]
211                    } else {
212                        0.0
213                    };
214                }
215            } else {
216                let m = self.layout.mono_channel(s, -1);
217                for i in 0..frame_size {
218                    stream_buf[i] = if m >= 0 {
219                        input[i * nch + m as usize]
220                    } else {
221                        0.0
222                    };
223                }
224            }
225            let n =
226                self.encoders[s].encode(&stream_buf[..frame_size * sch], frame_size, &mut pkt)?;
227            // All streams but the last are self-delimited so the decoder can
228            // find each stream's boundary.
229            if s != self.layout.nb_streams - 1 {
230                let mut rp = Repacketizer::new();
231                rp.cat(&pkt[..n])?;
232                out.extend_from_slice(&rp.out_self_delimited()?);
233            } else {
234                out.extend_from_slice(&pkt[..n]);
235            }
236        }
237        Ok(out)
238    }
239
240    /// Input sampling rate in Hz.
241    pub fn sample_rate(&self) -> i32 {
242        self.sample_rate
243    }
244}
245
246/// Multistream decoder: decode each stream and remux to the output channels.
247pub struct OpusMSDecoder {
248    layout: ChannelLayout,
249    decoders: Vec<OpusDecoder>,
250}
251
252impl OpusMSDecoder {
253    /// A surround decoder for `channels` channels with the standard layout of
254    /// `mapping_family` (see [`ChannelLayout::surround`]).
255    ///
256    /// # Errors
257    ///
258    /// [`Error::BadArg`] for an unsupported channel count / mapping family, or any
259    /// error from creating the per-stream decoders.
260    pub fn new(sample_rate: i32, channels: usize, mapping_family: i32) -> Result<Self, Error> {
261        let layout = ChannelLayout::surround(channels, mapping_family)?;
262        let mut decoders = Vec::with_capacity(layout.nb_streams);
263        for s in 0..layout.nb_streams {
264            let ch = if s < layout.nb_coupled_streams { 2 } else { 1 };
265            decoders.push(OpusDecoder::new(sample_rate, ch)?);
266        }
267        Ok(Self { layout, decoders })
268    }
269
270    /// Decode a multistream packet into interleaved `output` (nb_channels per
271    /// sample). Returns the number of samples per channel.
272    ///
273    /// # Errors
274    ///
275    /// [`Error::InvalidPacket`] if the multistream framing is malformed, or any
276    /// error from the per-stream [`crate::OpusDecoder::decode`] calls.
277    pub fn decode(
278        &mut self,
279        packet: &[u8],
280        frame_size: usize,
281        output: &mut [f32],
282    ) -> Result<usize, Error> {
283        let nch = self.layout.nb_channels;
284        let mut buf = vec![0f32; frame_size * 2];
285        let mut data = packet;
286        let mut produced = frame_size;
287
288        for s in 0..self.layout.nb_streams {
289            let coupled = s < self.layout.nb_coupled_streams;
290            let last = s == self.layout.nb_streams - 1;
291            // Determine this stream's byte slice.
292            let (stream_slice, advance) = if last {
293                (data, data.len())
294            } else {
295                let off = parse_frames(data, true)?.end;
296                (&data[..off], off)
297            };
298            let n = self.decoders[s].decode(stream_slice, frame_size, &mut buf)?;
299            produced = n;
300            // Remux this stream's channel(s) to the output.
301            if coupled {
302                let mut prev = -1;
303                loop {
304                    let chan = self.layout.left_channel(s, prev);
305                    if chan == -1 {
306                        break;
307                    }
308                    for i in 0..n {
309                        output[i * nch + chan as usize] = buf[i * 2];
310                    }
311                    prev = chan;
312                }
313                let mut prev = -1;
314                loop {
315                    let chan = self.layout.right_channel(s, prev);
316                    if chan == -1 {
317                        break;
318                    }
319                    for i in 0..n {
320                        output[i * nch + chan as usize] = buf[i * 2 + 1];
321                    }
322                    prev = chan;
323                }
324            } else {
325                let mut prev = -1;
326                loop {
327                    let chan = self.layout.mono_channel(s, prev);
328                    if chan == -1 {
329                        break;
330                    }
331                    for i in 0..n {
332                        output[i * nch + chan as usize] = buf[i];
333                    }
334                    prev = chan;
335                }
336            }
337            if !last {
338                data = &data[advance..];
339            }
340        }
341        // Unmapped channels (mapping == 255) are silenced.
342        for c in 0..nch {
343            if self.layout.mapping.get(c).copied() == Some(255) {
344                for i in 0..produced {
345                    output[i * nch + c] = 0.0;
346                }
347            }
348        }
349        Ok(produced)
350    }
351}
352
353impl OpusMSEncoder {
354    /// Cap the audio bandwidth of every stream at once.
355    pub fn set_max_bandwidth(&mut self, bw: Bandwidth) {
356        for e in &mut self.encoders {
357            e.max_bandwidth = bw;
358        }
359    }
360}