cros_codecs/
utils.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Utility functions used by several parts of this crate.
6//!
7//! This module is for anything that doesn't fit into the other top-level modules. Try not to add
8//! new code here unless it really doesn't belong anywhere else.
9
10use std::borrow::Cow;
11use std::io::Cursor;
12use std::io::Seek;
13use std::io::Write;
14use std::marker::PhantomData;
15use std::os::fd::OwnedFd;
16
17use byteorder::ReadBytesExt;
18use byteorder::LE;
19use bytes::Buf;
20use thiserror::Error;
21
22use crate::codec::h264::parser::Nalu as H264Nalu;
23use crate::codec::h265::parser::Nalu as H265Nalu;
24use crate::decoder::stateless::DecodeError;
25use crate::decoder::stateless::PoolLayer;
26use crate::decoder::stateless::StatelessVideoDecoder;
27use crate::decoder::BlockingMode;
28use crate::decoder::DecodedHandle;
29use crate::decoder::DecoderEvent;
30use crate::decoder::FramePool;
31use crate::decoder::StreamInfo;
32use crate::DecodedFormat;
33use crate::Fourcc;
34use crate::FrameLayout;
35use crate::PlaneLayout;
36use crate::Resolution;
37
38/// Iterator over IVF packets.
39pub struct IvfIterator<'a> {
40    cursor: Cursor<&'a [u8]>,
41}
42
43impl<'a> IvfIterator<'a> {
44    pub fn new(data: &'a [u8]) -> Self {
45        let mut cursor = Cursor::new(data);
46
47        // Skip the IVH header entirely.
48        cursor.seek(std::io::SeekFrom::Start(32)).unwrap();
49
50        Self { cursor }
51    }
52}
53
54impl<'a> Iterator for IvfIterator<'a> {
55    type Item = &'a [u8];
56
57    fn next(&mut self) -> Option<Self::Item> {
58        // Make sure we have a header.
59        if self.cursor.remaining() < 12 {
60            return None;
61        }
62
63        let len = self.cursor.read_u32::<LE>().ok()? as usize;
64        // Skip PTS.
65        let _ = self.cursor.read_u64::<LE>().ok()?;
66
67        if self.cursor.remaining() < len {
68            return None;
69        }
70
71        let start = self.cursor.position() as usize;
72        let _ = self.cursor.seek(std::io::SeekFrom::Current(len as i64));
73        let end = self.cursor.position() as usize;
74
75        Some(&self.cursor.get_ref()[start..end])
76    }
77}
78
79/// Helper struct for synthesizing IVF file header
80pub struct IvfFileHeader {
81    pub magic: [u8; 4],
82    pub version: u16,
83    pub header_size: u16,
84    pub codec: [u8; 4],
85    pub width: u16,
86    pub height: u16,
87    pub framerate: u32,
88    pub timescale: u32,
89    pub frame_count: u32,
90    pub unused: u32,
91}
92
93impl Default for IvfFileHeader {
94    fn default() -> Self {
95        Self {
96            magic: Self::MAGIC,
97            version: 0,
98            header_size: 32,
99            codec: Self::CODEC_VP9,
100            width: 320,
101            height: 240,
102            framerate: 1,
103            timescale: 1000,
104            frame_count: 1,
105            unused: Default::default(),
106        }
107    }
108}
109
110impl IvfFileHeader {
111    pub const MAGIC: [u8; 4] = *b"DKIF";
112    pub const CODEC_VP8: [u8; 4] = *b"VP80";
113    pub const CODEC_VP9: [u8; 4] = *b"VP90";
114    pub const CODEC_AV1: [u8; 4] = *b"AV01";
115
116    pub fn new(codec: [u8; 4], width: u16, height: u16, framerate: u32, frame_count: u32) -> Self {
117        let default = Self::default();
118
119        Self {
120            codec,
121            width,
122            height,
123            framerate: framerate * default.timescale,
124            frame_count,
125            ..default
126        }
127    }
128}
129
130impl IvfFileHeader {
131    /// Writes header into writer
132    pub fn writo_into(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
133        writer.write_all(&self.magic)?;
134        writer.write_all(&self.version.to_le_bytes())?;
135        writer.write_all(&self.header_size.to_le_bytes())?;
136        writer.write_all(&self.codec)?;
137        writer.write_all(&self.width.to_le_bytes())?;
138        writer.write_all(&self.height.to_le_bytes())?;
139        writer.write_all(&self.framerate.to_le_bytes())?;
140        writer.write_all(&self.timescale.to_le_bytes())?;
141        writer.write_all(&self.frame_count.to_le_bytes())?;
142        writer.write_all(&self.unused.to_le_bytes())?;
143
144        Ok(())
145    }
146}
147
148/// Helper struct for synthesizing IVF frame header
149pub struct IvfFrameHeader {
150    pub frame_size: u32,
151    pub timestamp: u64,
152}
153
154impl IvfFrameHeader {
155    /// Writes header into writer
156    pub fn writo_into(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
157        writer.write_all(&self.frame_size.to_le_bytes())?;
158        writer.write_all(&self.timestamp.to_le_bytes())?;
159        Ok(())
160    }
161}
162
163/// Iterator NALUs in a bitstream.
164pub struct NalIterator<'a, Nalu>(Cursor<&'a [u8]>, PhantomData<Nalu>);
165
166impl<'a, Nalu> NalIterator<'a, Nalu> {
167    pub fn new(stream: &'a [u8]) -> Self {
168        Self(Cursor::new(stream), PhantomData)
169    }
170}
171
172impl<'a> Iterator for NalIterator<'a, H264Nalu<'a>> {
173    type Item = Cow<'a, [u8]>;
174
175    fn next(&mut self) -> Option<Self::Item> {
176        H264Nalu::next(&mut self.0).map(|n| n.data).ok()
177    }
178}
179
180impl<'a> Iterator for NalIterator<'a, H265Nalu<'a>> {
181    type Item = Cow<'a, [u8]>;
182
183    fn next(&mut self) -> Option<Self::Item> {
184        H265Nalu::next(&mut self.0).map(|n| n.data).ok()
185    }
186}
187
188#[derive(Error, Debug)]
189pub enum BitWriterError {
190    #[error("invalid bit count")]
191    InvalidBitCount,
192    #[error(transparent)]
193    Io(#[from] std::io::Error),
194}
195
196pub type BitWriterResult<T> = std::result::Result<T, BitWriterError>;
197
198pub struct BitWriter<W: Write> {
199    out: W,
200    nth_bit: u8,
201    curr_byte: u8,
202}
203
204impl<W: Write> BitWriter<W> {
205    pub fn new(writer: W) -> Self {
206        Self {
207            out: writer,
208            curr_byte: 0,
209            nth_bit: 0,
210        }
211    }
212
213    /// Writes fixed bit size integer (up to 32 bit)
214    pub fn write_f<T: Into<u32>>(&mut self, bits: usize, value: T) -> BitWriterResult<usize> {
215        let value = value.into();
216
217        if bits > 32 {
218            return Err(BitWriterError::InvalidBitCount);
219        }
220
221        let mut written = 0;
222        for bit in (0..bits).rev() {
223            let bit = (1 << bit) as u32;
224
225            self.write_bit((value & bit) == bit)?;
226            written += 1;
227        }
228
229        Ok(written)
230    }
231
232    /// Takes a single bit that will be outputed to [`std::io::Write`]
233    pub fn write_bit(&mut self, bit: bool) -> BitWriterResult<()> {
234        self.curr_byte |= (bit as u8) << (7u8 - self.nth_bit);
235        self.nth_bit += 1;
236
237        if self.nth_bit == 8 {
238            self.out.write_all(&[self.curr_byte])?;
239            self.nth_bit = 0;
240            self.curr_byte = 0;
241        }
242
243        Ok(())
244    }
245
246    /// Immediately outputs any cached bits to [`std::io::Write`]
247    pub fn flush(&mut self) -> BitWriterResult<()> {
248        if self.nth_bit != 0 {
249            self.out.write_all(&[self.curr_byte])?;
250            self.nth_bit = 0;
251            self.curr_byte = 0;
252        }
253
254        self.out.flush()?;
255        Ok(())
256    }
257
258    /// Returns `true` if ['Self`] hold data that wasn't written to [`std::io::Write`]
259    pub fn has_data_pending(&self) -> bool {
260        self.nth_bit != 0
261    }
262
263    pub(crate) fn inner(&self) -> &W {
264        &self.out
265    }
266
267    pub(crate) fn inner_mut(&mut self) -> &mut W {
268        &mut self.out
269    }
270}
271
272impl<W: Write> Drop for BitWriter<W> {
273    fn drop(&mut self) {
274        if let Err(e) = self.flush() {
275            log::error!("Unable to flush bits {e:?}");
276        }
277    }
278}
279
280/// Simple decoding loop that plays the stream once from start to finish.
281#[allow(clippy::type_complexity)]
282pub fn simple_playback_loop<D, R, I, H, FP>(
283    decoder: &mut D,
284    stream_iter: I,
285    on_new_frame: &mut dyn FnMut(H),
286    allocate_new_frames: &mut dyn FnMut(&StreamInfo, usize) -> anyhow::Result<Vec<H::Descriptor>>,
287    output_format: DecodedFormat,
288    blocking_mode: BlockingMode,
289) -> anyhow::Result<()>
290where
291    H: DecodedHandle,
292    FP: FramePool<Descriptor = H::Descriptor> + ?Sized,
293    D: StatelessVideoDecoder<Handle = H, FramePool = FP> + ?Sized,
294    R: AsRef<[u8]>,
295    I: Iterator<Item = R>,
296{
297    // Closure that drains all pending decoder events and calls `on_new_frame` on each
298    // completed frame.
299    let mut check_events = |decoder: &mut D| -> anyhow::Result<()> {
300        while let Some(event) = decoder.next_event() {
301            match event {
302                DecoderEvent::FrameReady(frame) => {
303                    on_new_frame(frame);
304                }
305                DecoderEvent::FormatChanged(mut format_setter) => {
306                    format_setter.try_format(output_format).unwrap();
307                    let stream_info = format_setter.stream_info().clone();
308                    let min_num_frames = stream_info.min_num_frames;
309                    /* we need to account for multiple layers if applicable for
310                     * the stream */
311                    let pools = format_setter.frame_pool(PoolLayer::All);
312                    let nb_pools = pools.len();
313                    for pool in pools {
314                        // Allocate the missing number of buffers in our pool for decoding to succeed.
315                        let pool_num_frames = pool.num_managed_frames();
316                        if pool_num_frames < (min_num_frames / nb_pools) {
317                            let frames = allocate_new_frames(
318                                &stream_info,
319                                min_num_frames - pool_num_frames,
320                            )?;
321                            pool.add_frames(frames).unwrap();
322                        }
323                    }
324                }
325            }
326        }
327
328        Ok(())
329    };
330
331    for (frame_num, packet) in stream_iter.enumerate() {
332        let mut bitstream = packet.as_ref();
333        loop {
334            match decoder.decode(frame_num as u64, bitstream) {
335                Ok(bytes_decoded) => {
336                    bitstream = &bitstream[bytes_decoded..];
337
338                    if blocking_mode == BlockingMode::Blocking {
339                        check_events(decoder)?;
340                    }
341
342                    if bitstream.is_empty() {
343                        // Break the loop so we can process the next NAL if we sent the current one
344                        // successfully.
345                        break;
346                    }
347                }
348                Err(DecodeError::CheckEvents) | Err(DecodeError::NotEnoughOutputBuffers(_)) => {
349                    check_events(decoder)?
350                }
351                Err(e) => anyhow::bail!(e),
352            }
353        }
354    }
355
356    decoder.flush()?;
357    check_events(decoder)
358}
359
360/// Frame allocation callback that results in self-allocated memory.
361pub fn simple_playback_loop_owned_frames(
362    _: &StreamInfo,
363    nb_frames: usize,
364) -> anyhow::Result<Vec<()>> {
365    Ok(vec![(); nb_frames])
366}
367
368/// Frame allocation callback that returns user-allocated memory for the frames.
369pub fn simple_playback_loop_userptr_frames(
370    stream_info: &StreamInfo,
371    nb_frames: usize,
372) -> anyhow::Result<Vec<UserPtrFrame>> {
373    let alloc_function = match stream_info.format {
374        DecodedFormat::I420 | DecodedFormat::NV12 => &UserPtrFrame::new_nv12,
375        _ => anyhow::bail!(
376            "{:?} format is unsupported with user memory",
377            stream_info.format
378        ),
379    };
380
381    Ok((0..nb_frames)
382        .map(|_| alloc_function(stream_info.coded_resolution))
383        .collect::<Vec<_>>())
384}
385
386/// A structure that holds user-allocated memory for a frame as well as its layout.
387#[derive(Debug)]
388pub struct UserPtrFrame {
389    pub buffers: Vec<*mut u8>,
390    pub mem_layout: std::alloc::Layout,
391    pub layout: FrameLayout,
392}
393
394impl UserPtrFrame {
395    /// Allocate enough memory to back a NV12 frame of `size` dimension.
396    pub fn new_nv12(size: Resolution) -> Self {
397        /// Add what is needed to a value in order to make it a multiple of some alignment.
398        macro_rules! align {
399            ($n:expr, $r:expr) => {
400                ($n + ($r - 1)) & !($r - 1)
401            };
402        }
403
404        // Align according to VAAPI constraints.
405        let width = align!(size.width, 16) as usize;
406        let height = align!(size.height, 4) as usize;
407        let stride = align!(width, 64);
408        let uv_start = height * stride;
409        let uv_size = (height / 2) * stride;
410
411        Self::alloc(
412            FrameLayout {
413                format: (Fourcc::from(b"NV12"), 0),
414                size: Resolution::from((width as u32, height as u32)),
415                planes: vec![
416                    PlaneLayout {
417                        buffer_index: 0,
418                        offset: 0,
419                        stride,
420                    },
421                    PlaneLayout {
422                        buffer_index: 0,
423                        offset: uv_start,
424                        stride,
425                    },
426                ],
427            },
428            uv_start.max(uv_size),
429        )
430    }
431
432    pub fn alloc(layout: FrameLayout, buffer_size: usize) -> Self {
433        let buffer_count = layout
434            .planes
435            .iter()
436            .map(|plane| plane.buffer_index)
437            .collect::<std::collections::HashSet<usize>>()
438            .len();
439
440        // SAFETY: the invariants of `Layout` are respected.
441        let mem_layout =
442            unsafe { std::alloc::Layout::from_size_align_unchecked(buffer_size, 4096) };
443
444        let buffers = (0..buffer_count)
445            .map(|_| {
446                // SAFETY: the invariants of `Layout` are respected.
447                unsafe { std::alloc::alloc(mem_layout) }
448            })
449            .collect();
450
451        Self {
452            buffers,
453            mem_layout,
454            layout,
455        }
456    }
457}
458
459#[derive(Debug)]
460pub struct DmabufFrame {
461    pub fds: Vec<OwnedFd>,
462    pub layout: FrameLayout,
463}
464
465impl Drop for UserPtrFrame {
466    fn drop(&mut self) {
467        for buffer in std::mem::take(&mut self.buffers).into_iter() {
468            // Safe because we allocated the memory using `std::alloc::alloc`.
469            unsafe { std::alloc::dealloc(buffer, self.mem_layout) }
470        }
471    }
472}
473
474#[cfg(test)]
475mod tests {
476    use super::*;
477
478    #[test]
479    fn test_ivf_file_header() {
480        let mut hdr = IvfFileHeader {
481            version: 0,
482            codec: IvfFileHeader::CODEC_VP9,
483            width: 256,
484            height: 256,
485            framerate: 30_000,
486            timescale: 1_000,
487            frame_count: 1,
488
489            ..Default::default()
490        };
491
492        let mut buf = Vec::new();
493        hdr.writo_into(&mut buf).unwrap();
494
495        const EXPECTED: [u8; 32] = [
496            0x44, 0x4b, 0x49, 0x46, 0x00, 0x00, 0x20, 0x00, 0x56, 0x50, 0x39, 0x30, 0x00, 0x01,
497            0x00, 0x01, 0x30, 0x75, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
498            0x00, 0x00, 0x00, 0x00,
499        ];
500
501        assert_eq!(&buf, &EXPECTED);
502
503        hdr.width = 1920;
504        hdr.height = 800;
505        hdr.framerate = 24;
506        hdr.timescale = 1;
507        hdr.frame_count = 100;
508
509        buf.clear();
510        hdr.writo_into(&mut buf).unwrap();
511
512        const EXPECTED2: [u8; 32] = [
513            0x44, 0x4b, 0x49, 0x46, 0x00, 0x00, 0x20, 0x00, 0x56, 0x50, 0x39, 0x30, 0x80, 0x07,
514            0x20, 0x03, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
515            0x00, 0x00, 0x00, 0x00,
516        ];
517
518        assert_eq!(&buf, &EXPECTED2);
519    }
520
521    #[test]
522    fn test_ivf_frame_header() {
523        let mut hdr = IvfFrameHeader {
524            frame_size: 199249,
525            timestamp: 0,
526        };
527
528        let mut buf = Vec::new();
529        hdr.writo_into(&mut buf).unwrap();
530
531        const EXPECTED: [u8; 12] = [
532            0x51, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
533        ];
534
535        assert_eq!(&buf, &EXPECTED);
536
537        hdr.timestamp = 1;
538        hdr.frame_size = 52;
539
540        buf.clear();
541        hdr.writo_into(&mut buf).unwrap();
542
543        const EXPECTED2: [u8; 12] = [
544            0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545        ];
546
547        assert_eq!(&buf, &EXPECTED2);
548    }
549
550    #[test]
551    fn test_bitwriter_f1() {
552        let mut buf = Vec::<u8>::new();
553        {
554            let mut writer = BitWriter::new(&mut buf);
555            writer.write_f(1, true).unwrap();
556            writer.write_f(1, false).unwrap();
557            writer.write_f(1, false).unwrap();
558            writer.write_f(1, false).unwrap();
559            writer.write_f(1, true).unwrap();
560            writer.write_f(1, true).unwrap();
561            writer.write_f(1, true).unwrap();
562            writer.write_f(1, true).unwrap();
563        }
564        assert_eq!(buf, vec![0b10001111u8]);
565    }
566
567    #[test]
568    fn test_bitwriter_f3() {
569        let mut buf = Vec::<u8>::new();
570        {
571            let mut writer = BitWriter::new(&mut buf);
572            writer.write_f(3, 0b100u8).unwrap();
573            writer.write_f(3, 0b101u8).unwrap();
574            writer.write_f(3, 0b011u8).unwrap();
575        }
576        assert_eq!(buf, vec![0b10010101u8, 0b10000000u8]);
577    }
578
579    #[test]
580    fn test_bitwriter_f4() {
581        let mut buf = Vec::<u8>::new();
582        {
583            let mut writer = BitWriter::new(&mut buf);
584            writer.write_f(4, 0b1000u8).unwrap();
585            writer.write_f(4, 0b1011u8).unwrap();
586        }
587        assert_eq!(buf, vec![0b10001011u8]);
588    }
589}