Skip to main content

opus_pure/
repacketizer.rs

1//! Port of libopus `src/repacketizer.c` + the packet helpers from `src/opus.c`:
2//! split Opus packets into frames and recombine/re-frame/pad them WITHOUT
3//! re-encoding. Used to merge several packets into a longer one, split a
4//! multi-frame packet, or pad a packet to a target size (e.g. for CBR
5//! transport). All frames in a repacketizer must share the same TOC config
6//! (mode/bandwidth/frame-size); only the code (0..3) and framing change.
7
8use crate::packet::frame_count;
9use crate::{Error, Result};
10
11/// opus_packet_get_samples_per_frame(toc, Fs).
12pub(crate) fn samples_per_frame(toc: u8, fs: i32) -> i32 {
13    if toc & 0x80 != 0 {
14        let a = ((toc >> 3) & 0x3) as i32;
15        (fs << a) / 400
16    } else if toc & 0x60 == 0x60 {
17        if toc & 0x08 != 0 { fs / 50 } else { fs / 100 }
18    } else {
19        let a = ((toc >> 3) & 0x3) as i32;
20        if a == 3 {
21            fs * 60 / 1000
22        } else {
23            (fs << a) / 100
24        }
25    }
26}
27
28/// Decode one frame-length field (libopus `parse_size`).
29///
30/// Returns `(bytes_consumed, size)`; a negative `size` means the field is
31/// malformed.
32fn parse_size(data: &[u8]) -> (i32, i32) {
33    if data.is_empty() {
34        (-1, -1)
35    } else if data[0] < 252 {
36        (1, data[0] as i32)
37    } else if data.len() < 2 {
38        (-1, -1)
39    } else {
40        (2, data[1] as i32 * 4 + data[0] as i32)
41    }
42}
43
44fn encode_size(size: i32, out: &mut Vec<u8>) {
45    if size < 252 {
46        out.push(size as u8);
47    } else {
48        let b0 = 252 + (size & 0x3);
49        out.push(b0 as u8);
50        out.push(((size - b0) >> 2) as u8);
51    }
52}
53
54/// Most frames one packet can hold: 120 ms of 2.5 ms frames (RFC 6716 ยง3.2.5).
55/// `parse_packet` refuses a packet claiming more.
56pub(crate) const MAX_FRAMES: usize = 48;
57
58// `parse_packet` enforces the bound as 5760 samples of frames at least 120
59// samples long (2.5 ms at 48 kHz).
60const _: () = assert!(5760 / 120 == MAX_FRAMES);
61
62/// Up to [`MAX_FRAMES`] values held inline, so parsing a packet on the decode
63/// path allocates nothing.
64#[derive(Clone, Copy)]
65pub(crate) struct FrameList<T: Copy> {
66    items: [T; MAX_FRAMES],
67    len: usize,
68}
69
70impl<T: Copy + Default> FrameList<T> {
71    fn new() -> Self {
72        Self {
73            items: [T::default(); MAX_FRAMES],
74            len: 0,
75        }
76    }
77
78    /// Append `item`. Every caller pushes at most the frame count
79    /// `parse_packet` has already bounded by [`MAX_FRAMES`].
80    fn push(&mut self, item: T) {
81        self.items[self.len] = item;
82        self.len += 1;
83    }
84
85    fn clear(&mut self) {
86        self.len = 0;
87    }
88}
89
90impl<T: Copy> std::ops::Deref for FrameList<T> {
91    type Target = [T];
92
93    fn deref(&self) -> &[T] {
94        &self.items[..self.len]
95    }
96}
97
98/// Split `data` into its frames. Returns (toc, frames, packet_offset).
99/// `self_delimited` parses the trailing length prefix used by multistream.
100pub(crate) fn parse_packet(
101    data: &[u8],
102    self_delimited: bool,
103) -> Result<(u8, FrameList<&[u8]>, usize)> {
104    if data.is_empty() {
105        return Err(Error::InvalidPacket("invalid packet"));
106    }
107    let framesize = samples_per_frame(data[0], 48000);
108    let toc = data[0];
109    let mut pos = 1usize; // cursor into data
110    let mut len = data.len() as i32 - 1;
111    let mut cbr = false;
112    let mut last_size = len;
113    let mut sizes = FrameList::<i32>::new();
114
115    let count: usize = match toc & 0x3 {
116        0 => 1,
117        1 => {
118            cbr = true;
119            if !self_delimited {
120                if len & 1 != 0 {
121                    return Err(Error::InvalidPacket("invalid packet"));
122                }
123                last_size = len / 2;
124                sizes.push(last_size);
125            }
126            2
127        }
128        2 => {
129            let (bytes, sz) = parse_size(&data[pos..]);
130            if bytes < 0 {
131                return Err(Error::InvalidPacket("invalid packet"));
132            }
133            len -= bytes;
134            if sz < 0 || sz > len {
135                return Err(Error::InvalidPacket("invalid packet"));
136            }
137            pos += bytes as usize;
138            sizes.push(sz);
139            last_size = len - sz;
140            2
141        }
142        _ => {
143            if len < 1 {
144                return Err(Error::InvalidPacket("invalid packet"));
145            }
146            let ch = data[pos];
147            pos += 1;
148            len -= 1;
149            let count = (ch & 0x3f) as usize;
150            if count == 0 || framesize * count as i32 > 5760 {
151                return Err(Error::InvalidPacket("invalid packet"));
152            }
153            if ch & 0x40 != 0 {
154                // padding
155                loop {
156                    if len <= 0 {
157                        return Err(Error::InvalidPacket("invalid packet"));
158                    }
159                    let p = data[pos];
160                    pos += 1;
161                    len -= 1;
162                    let tmp = if p == 255 { 254 } else { p as i32 };
163                    len -= tmp;
164                    if p != 255 {
165                        break;
166                    }
167                }
168            }
169            if len < 0 {
170                return Err(Error::InvalidPacket("invalid packet"));
171            }
172            cbr = ch & 0x80 == 0;
173            if !cbr {
174                last_size = len;
175                for _ in 0..count - 1 {
176                    let (bytes, sz) = parse_size(&data[pos..]);
177                    if bytes < 0 {
178                        return Err(Error::InvalidPacket("invalid packet"));
179                    }
180                    len -= bytes;
181                    if sz < 0 || sz > len {
182                        return Err(Error::InvalidPacket("invalid packet"));
183                    }
184                    pos += bytes as usize;
185                    sizes.push(sz);
186                    last_size -= bytes + sz;
187                }
188                if last_size < 0 {
189                    return Err(Error::InvalidPacket("invalid packet"));
190                }
191            } else if !self_delimited {
192                last_size = len / count as i32;
193                if last_size * count as i32 != len {
194                    return Err(Error::InvalidPacket("invalid packet"));
195                }
196                for _ in 0..count - 1 {
197                    sizes.push(last_size);
198                }
199            }
200            count
201        }
202    };
203
204    if self_delimited {
205        let (bytes, sz) = parse_size(&data[pos..]);
206        if bytes < 0 {
207            return Err(Error::InvalidPacket("invalid packet"));
208        }
209        len -= bytes;
210        if sz < 0 || sz > len {
211            return Err(Error::InvalidPacket("invalid packet"));
212        }
213        pos += bytes as usize;
214        if cbr {
215            if sz * count as i32 > len {
216                return Err(Error::InvalidPacket("invalid packet"));
217            }
218            sizes.clear();
219            for _ in 0..count - 1 {
220                sizes.push(sz);
221            }
222            sizes.push(sz);
223        } else {
224            if bytes + sz > last_size {
225                return Err(Error::InvalidPacket("invalid packet"));
226            }
227            sizes.push(sz);
228        }
229    } else {
230        if last_size > 1275 {
231            return Err(Error::InvalidPacket("invalid packet"));
232        }
233        sizes.push(last_size);
234    }
235
236    // Frames start at `pos`.
237    let mut frames = FrameList::new();
238    let mut off = pos;
239    for &s in sizes.iter() {
240        if off + s as usize > data.len() {
241            return Err(Error::InvalidPacket("invalid packet"));
242        }
243        frames.push(&data[off..off + s as usize]);
244        off += s as usize;
245    }
246    let packet_offset = off; // for self-delimited multistream advancement
247    Ok((toc, frames, packet_offset))
248}
249
250/// Take one self-delimited packet from the front of `data` and re-emit it as a
251/// normal Opus packet into `out`, returning how many bytes of `data` it
252/// consumed.
253///
254/// A multistream packet concatenates its streams in self-delimited form
255/// (RFC 6716 Appendix B): every stream but the last carries an explicit length
256/// for its final frame. [`OpusDecoder`](crate::OpusDecoder) parses only normal
257/// packets, so that prefix has to be removed โ€” handing the self-delimited bytes
258/// straight through makes the decoder read the length as payload.
259///
260/// The frames are copied once, from `data` into `out`, which is cleared first;
261/// the multistream decoder keeps one `out` and reuses it across streams.
262pub(crate) fn take_self_delimited_into(data: &[u8], out: &mut Vec<u8>) -> Result<usize> {
263    let (toc, frames, consumed) = parse_packet(data, true)?;
264    out.clear();
265    emit_packet(toc, frames.iter().copied(), None, false, out)?;
266    Ok(consumed)
267}
268
269/// opus_repacketizer: accumulate frames from one or more same-config packets,
270/// then emit them as a single re-framed packet.
271#[derive(Default)]
272pub struct Repacketizer {
273    toc: u8,
274    framesize: i32,
275    frames: Vec<Vec<u8>>,
276    /// Frame buffers [`clear`](Repacketizer::clear) has taken back, ready for
277    /// [`cat`](Repacketizer::cat) to fill again. A repacketizer reused per
278    /// packet โ€” which is what a jitter buffer and the multistream encoder both
279    /// do โ€” would otherwise allocate one `Vec` per frame, for ever.
280    spare: Vec<Vec<u8>>,
281}
282
283/// Shows what the repacketizer holds without printing the frames themselves,
284/// which are compressed audio and unreadable either way.
285impl std::fmt::Debug for Repacketizer {
286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287        f.debug_struct("Repacketizer")
288            .field("nb_frames", &self.frames.len())
289            .field("toc", &format_args!("{:#04x}", self.toc))
290            .field("framesize", &self.framesize)
291            .field("bytes", &self.frames.iter().map(Vec::len).sum::<usize>())
292            .finish()
293    }
294}
295
296impl Repacketizer {
297    /// An empty repacketizer, holding no frames.
298    pub fn new() -> Self {
299        Repacketizer::default()
300    }
301
302    /// Drop every frame, keeping the buffers that held them.
303    ///
304    /// This is what makes one repacketizer reusable across packets. Building a
305    /// fresh [`Repacketizer::new`] per packet is correct but allocates a buffer
306    /// per frame every time; clearing and refilling one reuses them.
307    pub fn clear(&mut self) {
308        self.spare.append(&mut self.frames);
309        self.toc = 0;
310        self.framesize = 0;
311    }
312
313    /// Frames accumulated so far by [`cat`](Self::cat).
314    ///
315    /// Also the upper bound for [`out_range`](Self::out_range), which is how a
316    /// packet is split rather than joined.
317    pub fn nb_frames(&self) -> usize {
318        self.frames.len()
319    }
320
321    /// Append the frames of `data` (opus_repacketizer_cat). Errors if the TOC
322    /// config differs from frames already held, or the 120 ms cap is exceeded.
323    pub fn cat(&mut self, data: &[u8]) -> Result<()> {
324        self.cat_impl(data, false)
325    }
326
327    fn cat_impl(&mut self, data: &[u8], self_delimited: bool) -> Result<()> {
328        if data.is_empty() {
329            return Err(Error::InvalidPacket("cat: the packet is empty"));
330        }
331        if self.frames.is_empty() {
332            self.toc = data[0];
333            self.framesize = samples_per_frame(data[0], 8000);
334        } else if self.toc & 0xfc != data[0] & 0xfc {
335            return Err(Error::InvalidPacket("toc mismatch"));
336        }
337        let curr = frame_count(data)?;
338        if (curr + self.frames.len()) as i32 * self.framesize > 960 {
339            return Err(Error::InvalidPacket("packet exceeds 120 ms"));
340        }
341        let (_toc, frames, _off) = parse_packet(data, self_delimited)?;
342        for &f in frames.iter() {
343            let mut frame = self.spare.pop().unwrap_or_default();
344            frame.clear();
345            frame.extend_from_slice(f);
346            self.frames.push(frame);
347        }
348        Ok(())
349    }
350
351    /// Emit frames [begin, end) as one packet (opus_repacketizer_out_range).
352    pub fn out_range(&self, begin: usize, end: usize) -> Result<Vec<u8>> {
353        self.out_range_impl(begin, end, None)
354    }
355
356    /// Emit all held frames (opus_repacketizer_out).
357    pub fn out(&self) -> Result<Vec<u8>> {
358        self.out_range_impl(0, self.frames.len(), None)
359    }
360
361    /// [`out`](Self::out), appended to `out` instead of allocating.
362    ///
363    /// The `_into` forms exist because every other one hands back a fresh
364    /// `Vec`, which is an allocation per packet a caller in a steady loop can
365    /// do without. They append, so one buffer can accumulate several packets.
366    pub fn out_into(&self, out: &mut Vec<u8>) -> Result<()> {
367        self.out_range_full(0, self.frames.len(), None, false, out)
368    }
369
370    /// [`out_range`](Self::out_range), appended to `out`.
371    pub fn out_range_into(&self, begin: usize, end: usize, out: &mut Vec<u8>) -> Result<()> {
372        self.out_range_full(begin, end, None, false, out)
373    }
374
375    /// [`out_self_delimited`](Self::out_self_delimited), appended to `out`.
376    pub fn out_self_delimited_into(&self, out: &mut Vec<u8>) -> Result<()> {
377        self.out_range_full(0, self.frames.len(), None, true, out)
378    }
379
380    /// `opus_repacketizer_out_range_impl`. `pad_to` is C's `pad` flag plus its
381    /// `maxlen`: padding forces the code 3 framing that can carry it.
382    pub(crate) fn out_range_impl(
383        &self,
384        begin: usize,
385        end: usize,
386        pad_to: Option<usize>,
387    ) -> Result<Vec<u8>> {
388        let mut out = Vec::new();
389        self.out_range_full(begin, end, pad_to, false, &mut out)?;
390        Ok(out)
391    }
392
393    /// Emit all frames with the self-delimited framing multistream uses (the
394    /// last frame's length is coded so the packet's total size is derivable).
395    pub fn out_self_delimited(&self) -> Result<Vec<u8>> {
396        let mut out = Vec::new();
397        self.out_range_full(0, self.frames.len(), None, true, &mut out)?;
398        Ok(out)
399    }
400
401    fn out_range_full(
402        &self,
403        begin: usize,
404        end: usize,
405        pad_to: Option<usize>,
406        self_delimited: bool,
407        out: &mut Vec<u8>,
408    ) -> Result<()> {
409        if begin >= end || end > self.frames.len() {
410            return Err(Error::InvalidArgument(
411                "frame range must satisfy begin < end <= nb_frames",
412            ));
413        }
414        emit_packet(
415            self.toc,
416            self.frames[begin..end].iter().map(Vec::as_slice),
417            pad_to,
418            self_delimited,
419            out,
420        )
421    }
422}
423
424/// Emit `frames` under `toc` as one packet, using the shortest code that fits:
425/// 0 for one frame, 1 for two of equal length, 2 for two unequal, 3 for more
426/// or whenever padding is wanted. This is the single place a packet's framing
427/// is written, shared by the repacketizer and the multistream un-delimiter.
428///
429/// Appends, so `out` may already hold something; `start` is where this packet
430/// begins inside it, and every length below is measured from there.
431fn emit_packet<'f>(
432    toc: u8,
433    frames: impl ExactSizeIterator<Item = &'f [u8]> + Clone,
434    pad_to: Option<usize>,
435    self_delimited: bool,
436    out: &mut Vec<u8>,
437) -> Result<()> {
438    let count = frames.len();
439    if count == 0 {
440        return Err(Error::InvalidArgument("a packet needs at least one frame"));
441    }
442    let lens = || frames.clone().map(<[u8]>::len);
443    let first_len = lens().next().unwrap_or(0);
444    let last_len = lens().last().unwrap_or(0);
445    let vbr = lens().any(|l| l != first_len);
446    let start = out.len();
447
448    if count == 1 {
449        out.push(toc & 0xfc); // code 0
450    } else if count == 2 && !vbr {
451        out.push((toc & 0xfc) | 0x1); // code 1
452    } else if count == 2 {
453        out.push((toc & 0xfc) | 0x2); // code 2
454        encode_size(first_len as i32, out);
455    }
456
457    if count > 2 || pad_to.is_some() {
458        // Code 3 (needed for >2 frames, or to carry padding). Discards
459        // whatever the branch above wrote for *this* packet, not anything
460        // already in the caller's buffer.
461        out.truncate(start);
462        out.push((toc & 0xfc) | 0x3);
463        out.push(if vbr {
464            (count as u8) | 0x80
465        } else {
466            count as u8
467        });
468        // Compute current size to know the padding amount.
469        let mut tot = 2usize;
470        if vbr {
471            for l in lens().take(count - 1) {
472                tot += 1 + usize::from(l >= 252) + l;
473            }
474            tot += last_len;
475        } else {
476            tot += count * first_len;
477        }
478        let pad_amount = pad_to.map(|n| n.saturating_sub(tot)).unwrap_or(0);
479        if pad_amount != 0 {
480            out[start + 1] |= 0x40; // padding flag
481            let nb_255s = (pad_amount - 1) / 255;
482            out.extend(std::iter::repeat_n(255u8, nb_255s));
483            out.push((pad_amount - 255 * nb_255s - 1) as u8);
484        }
485        if vbr {
486            for l in lens().take(count - 1) {
487                encode_size(l as i32, out);
488            }
489        }
490        if self_delimited {
491            encode_size(last_len as i32, out);
492        }
493        for f in frames.clone() {
494            out.extend_from_slice(f);
495        }
496        if let Some(n) = pad_to {
497            while out.len() - start < n {
498                out.push(0);
499            }
500        }
501        return Ok(());
502    }
503
504    if self_delimited {
505        encode_size(last_len as i32, out);
506    }
507    for f in frames.clone() {
508        out.extend_from_slice(f);
509    }
510    Ok(())
511}
512
513/// opus_packet_pad: grow `packet` in place to `new_len` bytes by adding opus
514/// padding (no re-encode). No-op if already `new_len`; errors if `new_len` is
515/// smaller.
516pub fn pad_packet(packet: &mut Vec<u8>, new_len: usize) -> Result<()> {
517    if packet.is_empty() {
518        return Err(Error::InvalidArgument("pad_packet: the packet is empty"));
519    }
520    if packet.len() == new_len {
521        return Ok(());
522    }
523    if packet.len() > new_len {
524        return Err(Error::InvalidArgument(
525            "pad_packet: new_len is smaller than the packet",
526        ));
527    }
528    let mut rp = Repacketizer::new();
529    rp.cat(packet)?;
530    let padded = rp.out_range_impl(0, rp.nb_frames(), Some(new_len))?;
531    *packet = padded;
532    Ok(())
533}
534
535/// opus_packet_unpad: strip opus padding, returning the minimal packet.
536pub fn unpad_packet(packet: &[u8]) -> Result<Vec<u8>> {
537    if packet.is_empty() {
538        return Err(Error::InvalidArgument("unpad_packet: the packet is empty"));
539    }
540    let mut rp = Repacketizer::new();
541    rp.cat(packet)?;
542    rp.out_range_impl(0, rp.nb_frames(), None)
543}
544
545#[cfg(test)]
546mod tests {
547    use super::*;
548
549    // Build a synthetic code-3 VBR packet with 3 frames of distinct lengths,
550    // split via out_range, and re-merge -> byte-identical (round-trip fidelity).
551    #[test]
552    fn split_merge_roundtrip() {
553        // toc config 12 (hybrid SWB 10ms) stereo bit off, code 3.
554        let toc = 12u8 << 3;
555        let mut pkt = vec![toc | 0x3, 3 | 0x80]; // code 3, vbr, count 3
556        let f0 = vec![0xAAu8; 3];
557        let f1 = vec![0xBBu8; 5];
558        let f2 = vec![0xCCu8; 4];
559        encode_size(3, &mut pkt);
560        encode_size(5, &mut pkt);
561        pkt.extend_from_slice(&f0);
562        pkt.extend_from_slice(&f1);
563        pkt.extend_from_slice(&f2);
564
565        let mut rp = Repacketizer::new();
566        rp.cat(&pkt).unwrap();
567        assert_eq!(rp.nb_frames(), 3);
568        // out() must reproduce the exact same packet.
569        assert_eq!(rp.out().unwrap(), pkt);
570        // Splitting single frames yields code-0 packets with the frame bytes.
571        let s0 = rp.out_range(0, 1).unwrap();
572        assert_eq!(s0[0] & 0x3, 0);
573        assert_eq!(&s0[1..], &f0[..]);
574        let s1 = rp.out_range(1, 2).unwrap();
575        assert_eq!(&s1[1..], &f1[..]);
576    }
577
578    // The multistream un-delimiter must produce exactly what the repacketizer
579    // does for the same frames, in every packet code, and must not keep
580    // whatever `out` held before.
581    #[test]
582    fn take_self_delimited_matches_the_repacketizer() {
583        let toc = 12u8 << 3; // hybrid SWB 10 ms, so three frames fit in 120 ms
584        let cases: &[&[usize]] = &[&[3], &[4, 4], &[3, 5], &[4, 4, 4], &[3, 5, 4], &[300, 2]];
585        for lens in cases {
586            let mut rp = Repacketizer::new();
587            for (i, &l) in lens.iter().enumerate() {
588                let mut pkt = vec![toc];
589                pkt.extend(std::iter::repeat_n(i as u8 + 1, l));
590                rp.cat(&pkt).unwrap();
591            }
592            let mut sd = rp.out_self_delimited().unwrap();
593            let trailer = [0xEEu8; 7]; // the next stream, which must be left alone
594            sd.extend_from_slice(&trailer);
595
596            let mut out = vec![0xFF; 3];
597            let consumed = take_self_delimited_into(&sd, &mut out).unwrap();
598            assert_eq!(consumed, sd.len() - trailer.len(), "lens {lens:?}");
599            assert_eq!(out, rp.out().unwrap(), "lens {lens:?}");
600        }
601    }
602
603    #[test]
604    fn pad_unpad_identity() {
605        let toc = 8u8 << 3; // silk WB code 0
606        let mut pkt = vec![toc];
607        pkt.extend_from_slice(&[1, 2, 3, 4, 5]);
608        let orig = pkt.clone();
609        pad_packet(&mut pkt, orig.len() + 10).unwrap();
610        assert_eq!(pkt.len(), orig.len() + 10);
611        let back = unpad_packet(&pkt).unwrap();
612        // frame bytes recovered
613        let (_t, f, _) = parse_packet(&back, false).unwrap();
614        assert_eq!(f[0], &orig[1..]);
615    }
616
617    #[test]
618    fn cbr_merge_code1() {
619        // Two equal-length frames merge to code 1.
620        let toc = 8u8 << 3;
621        let p = vec![toc, 9, 9, 9]; // code 0, 3-byte frame
622        let mut rp = Repacketizer::new();
623        rp.cat(&p).unwrap();
624        rp.cat(&p).unwrap();
625        let out = rp.out().unwrap();
626        assert_eq!(out[0] & 0x3, 1); // code 1 (equal sizes)
627        assert_eq!(rp.nb_frames(), 2);
628    }
629}
630
631#[cfg(test)]
632mod sd_tests {
633    use super::*;
634    #[test]
635    fn self_delimited_roundtrip() {
636        // 3-frame vbr packet -> self-delimited -> parse(self_delimited) recovers frames.
637        let toc = 12u8 << 3;
638        let mut rp = Repacketizer::new();
639        let mut p = vec![toc | 0x3, 3 | 0x80];
640        encode_size(3, &mut p);
641        encode_size(5, &mut p);
642        p.extend_from_slice(&[1u8; 3]);
643        p.extend_from_slice(&[2u8; 5]);
644        p.extend_from_slice(&[3u8; 4]);
645        rp.cat(&p).unwrap();
646        let sd = rp.out_self_delimited().unwrap();
647        // append trailing bytes to simulate concatenation; parse must stop at packet_offset
648        let mut stream = sd.clone();
649        stream.extend_from_slice(&[0xEE; 7]);
650        let (t, frames, off) = parse_packet(&stream, true).unwrap();
651        assert_eq!(t, toc | 0x3);
652        assert_eq!(frames.len(), 3);
653        assert_eq!(frames[0], &[1, 1, 1]);
654        assert_eq!(frames[2], &[3, 3, 3, 3]);
655        assert_eq!(off, sd.len()); // packet ends exactly at the SD boundary
656    }
657}