├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── src ├── av1.rs ├── bitio.rs ├── ivf.rs ├── lib.rs ├── main.rs ├── mkv.rs ├── mp4.rs └── obu.rs └── streams ├── aom_cx_set_ref_av1.ivf ├── av1.annexb.obu ├── av1.ivf ├── av1.webm ├── av1_lag5_frames10.webm ├── av1_obu_test.ivf ├── av1_test.webm ├── cdf_mode_0.webm ├── cdf_mode_1.webm ├── cdf_mode_2.webm ├── download.py ├── fetchmpd.py ├── metadata_hdr_cll_mdcv.ivf ├── note.txt ├── parkjoy-audio.mp4 ├── parkjoy.ivf ├── parkjoy.mp4 ├── parkjoy.obu ├── parkjoy.webm ├── parkjoy_error-resilient.ivf ├── requirements.txt ├── set_maps_av1.ivf ├── simple_encoder_av1.ivf ├── test_encode.ivf ├── twopass_encoder_av1.ivf └── vase_tile_list.ivf /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | 8 | # test vectors 9 | streams/* 10 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ansi_term" 7 | version = "0.11.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 10 | dependencies = [ 11 | "winapi", 12 | ] 13 | 14 | [[package]] 15 | name = "atty" 16 | version = "0.2.14" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 19 | dependencies = [ 20 | "hermit-abi", 21 | "libc", 22 | "winapi", 23 | ] 24 | 25 | [[package]] 26 | name = "av1parser" 27 | version = "0.2.1" 28 | dependencies = [ 29 | "byteorder", 30 | "clap", 31 | "hex", 32 | ] 33 | 34 | [[package]] 35 | name = "bitflags" 36 | version = "1.3.2" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 39 | 40 | [[package]] 41 | name = "byteorder" 42 | version = "1.4.3" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 45 | 46 | [[package]] 47 | name = "clap" 48 | version = "2.33.3" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 51 | dependencies = [ 52 | "ansi_term", 53 | "atty", 54 | "bitflags", 55 | "strsim", 56 | "textwrap", 57 | "unicode-width", 58 | "vec_map", 59 | ] 60 | 61 | [[package]] 62 | name = "hermit-abi" 63 | version = "0.1.19" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 66 | dependencies = [ 67 | "libc", 68 | ] 69 | 70 | [[package]] 71 | name = "hex" 72 | version = "0.4.3" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 75 | 76 | [[package]] 77 | name = "libc" 78 | version = "0.2.101" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" 81 | 82 | [[package]] 83 | name = "strsim" 84 | version = "0.8.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 87 | 88 | [[package]] 89 | name = "textwrap" 90 | version = "0.11.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 93 | dependencies = [ 94 | "unicode-width", 95 | ] 96 | 97 | [[package]] 98 | name = "unicode-width" 99 | version = "0.1.8" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 102 | 103 | [[package]] 104 | name = "vec_map" 105 | version = "0.8.2" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 108 | 109 | [[package]] 110 | name = "winapi" 111 | version = "0.3.9" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 114 | dependencies = [ 115 | "winapi-i686-pc-windows-gnu", 116 | "winapi-x86_64-pc-windows-gnu", 117 | ] 118 | 119 | [[package]] 120 | name = "winapi-i686-pc-windows-gnu" 121 | version = "0.4.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 124 | 125 | [[package]] 126 | name = "winapi-x86_64-pc-windows-gnu" 127 | version = "0.4.0" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 130 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "av1parser" 3 | version = "0.2.1" 4 | authors = ["yoh "] 5 | description = "AV1 Bitstream Parser" 6 | 7 | [dependencies] 8 | byteorder = "1.2" 9 | clap = "2.32" 10 | hex = "0.4" 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 yoh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # av1parser 2 | [![Build Status](https://github.com/yohhoy/av1parser/actions/workflows/rust.yml/badge.svg)](https://github.com/yohhoy/av1parser/actions/workflows/rust.yml) 3 | [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) 4 | 5 | [AOM(Alliance of Open Media)][aom]'s [AV1 video codec bitstream][av1-spec] parser. 6 | 7 | The program reads AV1 bitstreams, parses header-level syntax elements, and analyzes the high-level structure of the coded video sequence. 8 | 9 | This project is not intended to decode video frames. 10 | 11 | [aom]: https://aomedia.org/ 12 | [av1-spec]: https://aomedia.org/av1/specification/ 13 | 14 | 15 | ## Usage (Example) 16 | Run with maximum verbose output: 17 | ``` 18 | $ cargo run streams/parkjoy.webm -vvv 19 | ... 20 | ``` 21 | 22 | (The semantics of each syntax element are defined in AV1 specification. Enjoy it! :P) 23 | 24 | 25 | ## Details 26 | Supported file formats: 27 | - Raw bitstream (Low overhead bitstream format) 28 | - [IVF format][ivf] 29 | - [WebM format][webm] ("V_AV1" codec) 30 | - [MP4 format][isobmff] ("av01" codec) 31 | 32 | [ivf]: https://wiki.multimedia.cx/index.php/IVF 33 | [webm]: https://www.webmproject.org/ 34 | [isobmff]: https://en.wikipedia.org/wiki/ISO/IEC_base_media_file_format 35 | 36 | Supported OBU types: 37 | - OBU_SEQUENCE_HEADER 38 | - OBU_TEMPORAL_DELIMITER (no payload) 39 | - OBU_FRAME_HEADER 40 | - OBU_FRAME (header part only) 41 | - OBU_TILE_LIST 42 | - OBU_METADATA 43 | 44 | 45 | ## License 46 | MIT License 47 | -------------------------------------------------------------------------------- /src/av1.rs: -------------------------------------------------------------------------------- 1 | // 2 | // https://aomedia.org/av1-bitstream-and-decoding-process-specification/ 3 | // 4 | use crate::obu; 5 | 6 | use crate::obu::NUM_REF_FRAMES; 7 | 8 | pub const INTRA_FRAME: usize = 0; 9 | pub const LAST_FRAME: usize = 1; 10 | pub const LAST2_FRAME: usize = 2; 11 | pub const LAST3_FRAME: usize = 3; 12 | pub const GOLDEN_FRAME: usize = 4; 13 | pub const BWDREF_FRAME: usize = 5; 14 | pub const ALTREF2_FRAME: usize = 6; 15 | pub const ALTREF_FRAME: usize = 7; 16 | 17 | /// 18 | /// Sequence 19 | /// 20 | #[derive(Debug)] 21 | pub struct Sequence { 22 | pub sh: Option, 23 | pub rfman: RefFrameManager, 24 | } 25 | 26 | impl Sequence { 27 | pub fn new() -> Self { 28 | Sequence { 29 | sh: None, 30 | rfman: RefFrameManager::new(), 31 | } 32 | } 33 | } 34 | 35 | /// 36 | /// Reference frame manager 37 | /// 38 | #[derive(Debug)] 39 | pub struct RefFrameManager { 40 | pub ref_valid: [bool; NUM_REF_FRAMES], // RefValid[i] 41 | pub ref_frame_id: [u16; NUM_REF_FRAMES], // RefFrameId[i] 42 | pub ref_frame_type: [u8; NUM_REF_FRAMES], // RefFrameType[i] 43 | pub ref_order_hint: [u8; NUM_REF_FRAMES], // RefOrderHint[i] 44 | pub saved_gm_params: [[[i32; 6]; NUM_REF_FRAMES]; NUM_REF_FRAMES], // SavedGmParams[i][ref][j] 45 | // user data 46 | pub decode_order: i64, // frame decoding oreder 47 | pub present_order: i64, // frame presentation order 48 | pub frame_buf: [i64; NUM_REF_FRAMES], 49 | } 50 | 51 | impl RefFrameManager { 52 | pub fn new() -> Self { 53 | RefFrameManager { 54 | ref_valid: [false; NUM_REF_FRAMES], 55 | ref_frame_id: [0; NUM_REF_FRAMES], 56 | ref_frame_type: [0; NUM_REF_FRAMES], 57 | ref_order_hint: [0; NUM_REF_FRAMES], 58 | saved_gm_params: [[[0; 6]; NUM_REF_FRAMES]; NUM_REF_FRAMES], 59 | decode_order: 0, 60 | present_order: 0, 61 | frame_buf: [i64::min_value(); NUM_REF_FRAMES], 62 | } 63 | } 64 | 65 | /// Reference frame marking function 66 | pub fn mark_ref_frames( 67 | &mut self, 68 | id_len: usize, 69 | sh: &obu::SequenceHeader, 70 | fh: &obu::FrameHeader, 71 | ) { 72 | let diff_len = sh.delta_frame_id_length; 73 | for i in 0..NUM_REF_FRAMES { 74 | if fh.current_frame_id > (1 << diff_len) { 75 | if self.ref_frame_id[i] > fh.current_frame_id 76 | || self.ref_frame_id[i] < fh.current_frame_id - (1 << diff_len) 77 | { 78 | self.ref_valid[i] = false; 79 | } 80 | } else { 81 | if self.ref_frame_id[i] > fh.current_frame_id 82 | && self.ref_frame_id[i] 83 | < ((1 << id_len) + fh.current_frame_id - (1 << diff_len)) 84 | { 85 | self.ref_valid[i] = false; 86 | } 87 | } 88 | } 89 | } 90 | 91 | /// Output process 92 | pub fn output_process(&mut self, _: &obu::FrameHeader) { 93 | self.present_order += 1; 94 | } 95 | 96 | /// Reference frame update process 97 | pub fn update_process(&mut self, fh: &obu::FrameHeader) { 98 | for i in 0..NUM_REF_FRAMES { 99 | if (fh.refresh_frame_flags >> i) & 1 == 1 { 100 | self.ref_valid[i] = true; 101 | self.ref_frame_id[i] = fh.current_frame_id; 102 | self.ref_frame_type[i] = fh.frame_type; 103 | self.ref_order_hint[i] = fh.order_hint; 104 | for ref_ in LAST_FRAME..=ALTREF_FRAME { 105 | for j in 0..=5 { 106 | self.saved_gm_params[i][ref_][j] = 107 | fh.global_motion_params.gm_params[ref_][j]; 108 | } 109 | } 110 | // user data 111 | self.frame_buf[i] = self.decode_order; 112 | } 113 | } 114 | self.decode_order += 1; 115 | } 116 | } 117 | 118 | /// Get relative distance function 119 | pub fn get_relative_dist(a: i32, b: i32, sh: &obu::SequenceHeader) -> i32 { 120 | if !sh.enable_order_hint { 121 | return 0; 122 | } 123 | let mut diff = a - b; 124 | let m = 1 << (sh.order_hint_bits - 1); 125 | diff = (diff & (m - 1)) - (diff & m); 126 | return diff; 127 | } 128 | 129 | pub mod stringify { 130 | use super::obu; 131 | use std::borrow::Cow; 132 | 133 | pub fn frame_type(v: u8) -> &'static str { 134 | match v { 135 | obu::KEY_FRAME => "KeyFrame", 136 | obu::INTER_FRAME => "InterFrame", 137 | obu::INTRA_ONLY_FRAME => "IntraOnlyFrame", 138 | obu::SWITCH_FRAME => "SwitchFrame", 139 | _ => "(undefined)", 140 | } 141 | } 142 | 143 | pub fn ref_frame(bitmask: u8) -> Cow<'static, str> { 144 | const INTRA_FRAME: u8 = 1 << super::INTRA_FRAME; 145 | const LAST_FRAME: u8 = 1 << super::LAST_FRAME; 146 | const LAST2_FRAME: u8 = 1 << super::LAST2_FRAME; 147 | const LAST3_FRAME: u8 = 1 << super::LAST3_FRAME; 148 | const GOLDEN_FRAME: u8 = 1 << super::GOLDEN_FRAME; 149 | const BWDREF_FRAME: u8 = 1 << super::BWDREF_FRAME; 150 | const ALTREF2_FRAME: u8 = 1 << super::ALTREF2_FRAME; 151 | const ALTREF_FRAME: u8 = 1 << super::ALTREF_FRAME; 152 | match bitmask { 153 | 0 => "none".into(), 154 | 255 => "all".into(), 155 | INTRA_FRAME => "INTRA".into(), 156 | LAST_FRAME => "LAST".into(), 157 | LAST2_FRAME => "LAST2".into(), 158 | LAST3_FRAME => "LAST3".into(), 159 | GOLDEN_FRAME => "GOLDEN".into(), 160 | BWDREF_FRAME => "BWDREF".into(), 161 | ALTREF2_FRAME => "ALTREF".into(), 162 | ALTREF_FRAME => "ALTREF".into(), 163 | _ => format!("0b{:08b}", bitmask).into(), 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/bitio.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | /// numeric cast helper (u32 as T) 4 | pub trait FromU32 { 5 | fn from_u32(v: u32) -> Self; 6 | } 7 | 8 | impl FromU32 for bool { 9 | #[inline] 10 | fn from_u32(v: u32) -> Self { 11 | v != 0 12 | } 13 | } 14 | 15 | macro_rules! impl_from_u32 { 16 | ($($ty:ty)*) => { 17 | $( 18 | impl FromU32 for $ty { 19 | #[inline] 20 | fn from_u32(v: u32) -> $ty { 21 | v as $ty 22 | } 23 | } 24 | )* 25 | } 26 | } 27 | 28 | impl_from_u32!(u8 u16 u32 u64 usize); 29 | 30 | /// 31 | /// Bitwise reader 32 | /// 33 | pub struct BitReader { 34 | inner: R, 35 | bbuf: u8, 36 | bpos: u8, 37 | } 38 | 39 | impl BitReader { 40 | pub fn new(inner: R) -> BitReader { 41 | BitReader { 42 | inner, 43 | bbuf: 0, 44 | bpos: 0, 45 | } 46 | } 47 | 48 | /// read_bit: read 1 bit 49 | pub fn read_bit(&mut self) -> Option { 50 | if self.bpos == 0 { 51 | let mut bbuf = [0; 1]; 52 | match self.inner.read(&mut bbuf) { 53 | Ok(0) | Err(_) => return None, // EOF or IOErr 54 | Ok(n) => assert_eq!(n, 1), 55 | } 56 | self.bbuf = bbuf[0]; 57 | self.bpos = 8; 58 | } 59 | self.bpos -= 1; 60 | Some((self.bbuf >> self.bpos) & 1) 61 | } 62 | 63 | /// f(n): read n-bits 64 | pub fn f(&mut self, nbit: usize) -> Option { 65 | assert!(nbit <= 32); 66 | let mut x: u32 = 0; 67 | for _ in 0..nbit { 68 | x = (x << 1) | self.read_bit()? as u32; 69 | } 70 | Some(FromU32::from_u32(x)) 71 | } 72 | 73 | /// su(n) 74 | pub fn su(&mut self, n: usize) -> Option { 75 | let mut value = self.f::(n)? as i32; 76 | let sign_mask = 1 << (n - 1); 77 | if value & sign_mask != 0 { 78 | value -= 2 * sign_mask 79 | } 80 | Some(value) 81 | } 82 | 83 | /// ns(n) 84 | pub fn ns(&mut self, n: u32) -> Option { 85 | let w = Self::floor_log2(n) + 1; 86 | let m = (1 << w) - n; 87 | let v = self.f::(w as usize - 1)?; // f(w - 1) 88 | if v < m { 89 | return Some(v); 90 | } 91 | let extra_bit = self.f::(1)?; // f(1) 92 | Some((v << 1) - m + extra_bit) 93 | } 94 | 95 | // FloorLog2(x) 96 | fn floor_log2(mut x: u32) -> u32 { 97 | let mut s = 0; 98 | while x != 0 { 99 | x >>= 1; 100 | s += 1; 101 | } 102 | s - 1 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/ivf.rs: -------------------------------------------------------------------------------- 1 | // 2 | // https://wiki.multimedia.cx/index.php/IVF 3 | // 4 | use byteorder::{ByteOrder, LittleEndian}; 5 | use hex; 6 | use std::io::Read; 7 | 8 | pub const IVF_HEADER_SIZE: usize = 32; 9 | pub const IVF_SIGNATURE: [u8; 4] = *b"DKIF"; 10 | pub const IVF_VERSION: u16 = 0; 11 | 12 | /// 13 | /// IVF file header 14 | /// 15 | #[derive(Debug)] 16 | pub struct IvfHeader { 17 | pub codec: [u8; 4], // FourCC 18 | pub width: u16, // [pel] 19 | pub height: u16, // [pel] 20 | pub timescale_num: u32, 21 | pub timescale_den: u32, 22 | pub length: u32, // nframes in libvpx, duration in ffmpeg 23 | } 24 | 25 | /// 26 | /// IVF frame 27 | /// 28 | #[derive(Debug)] 29 | pub struct IvfFrame { 30 | pub size: u32, // [byte] 31 | pub pts: u64, 32 | } 33 | 34 | /// 35 | /// parse IVF file header 36 | /// 37 | pub fn parse_ivf_header(mut ivf: &[u8]) -> Result { 38 | assert_eq!(ivf.len(), IVF_HEADER_SIZE); 39 | // signature (4b) 40 | let mut sig = [0; 4]; 41 | ivf.read_exact(&mut sig).unwrap(); 42 | if sig != IVF_SIGNATURE { 43 | return Err(format!( 44 | "Invalid IVF signature(0x{})", 45 | hex::encode_upper(sig) 46 | )); 47 | } 48 | // version (2b) 49 | let mut ver = [0; 2]; 50 | ivf.read_exact(&mut ver).unwrap(); 51 | let ver = LittleEndian::read_u16(&ver); 52 | if ver != IVF_VERSION { 53 | return Err(format!("Invalid IVF version({})", ver)); 54 | } 55 | // header length (2b) 56 | let mut hdrlen = [0; 2]; 57 | ivf.read_exact(&mut hdrlen).unwrap(); 58 | let hdrlen = LittleEndian::read_u16(&hdrlen); 59 | if hdrlen != IVF_HEADER_SIZE as u16 { 60 | return Err(format!("Invalid IVF header length({})", hdrlen)); 61 | } 62 | // codec (4b) 63 | let mut codec = [0; 4]; 64 | ivf.read_exact(&mut codec).unwrap(); 65 | // width (2b), height (2b) 66 | let mut width = [0; 2]; 67 | let mut height = [0; 2]; 68 | ivf.read_exact(&mut width).unwrap(); 69 | ivf.read_exact(&mut height).unwrap(); 70 | let width = LittleEndian::read_u16(&width); 71 | let height = LittleEndian::read_u16(&height); 72 | // timescale_num (4b), timescale_den (4b) 73 | let mut timescale_num = [0; 4]; 74 | let mut timescale_den = [0; 4]; 75 | ivf.read_exact(&mut timescale_num).unwrap(); 76 | ivf.read_exact(&mut timescale_den).unwrap(); 77 | let timescale_num = LittleEndian::read_u32(×cale_num); 78 | let timescale_den = LittleEndian::read_u32(×cale_den); 79 | // length (4b) 80 | let mut length = [0; 4]; 81 | ivf.read_exact(&mut length).unwrap(); 82 | let length = LittleEndian::read_u32(&length); 83 | 84 | Ok(IvfHeader { 85 | codec, 86 | width, 87 | height, 88 | timescale_num, 89 | timescale_den, 90 | length, 91 | }) 92 | } 93 | 94 | /// 95 | /// parse IVF frame header 96 | /// 97 | pub fn parse_ivf_frame(bs: &mut R) -> Result { 98 | let mut hdr = [0; 4 + 8]; 99 | match bs.read_exact(&mut hdr) { 100 | Ok(_) => (), 101 | Err(_) => return Err("IO error".to_owned()), 102 | }; 103 | 104 | Ok(IvfFrame { 105 | size: LittleEndian::read_u32(&hdr[0..4]), // frame size (4b) 106 | pts: LittleEndian::read_u64(&hdr[4..]), // presentation timestamp (8b) 107 | }) 108 | } 109 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | extern crate hex; 3 | 4 | pub mod av1; 5 | mod bitio; 6 | pub mod ivf; 7 | pub mod mkv; 8 | pub mod mp4; 9 | pub mod obu; 10 | 11 | use std::io; 12 | 13 | pub const FCC_AV01: [u8; 4] = *b"AV01"; // AV1 codec 14 | const WEBM_SIGNATURE: [u8; 4] = [0x1A, 0x45, 0xDF, 0xA3]; // EBML(Matroska/WebM) 15 | 16 | pub enum FileFormat { 17 | IVF, // IVF format 18 | WebM, // Matroska/WebM format 19 | MP4, // ISOBMFF/MP4 format 20 | Bitstream, // Raw bitstream 21 | } 22 | 23 | /// probe file format 24 | pub fn probe_fileformat(reader: &mut R) -> io::Result { 25 | let mut b4 = [0; 4]; 26 | reader.read_exact(&mut b4)?; 27 | let fmt = match b4 { 28 | ivf::IVF_SIGNATURE => FileFormat::IVF, 29 | WEBM_SIGNATURE => FileFormat::WebM, 30 | _ => { 31 | reader.read_exact(&mut b4)?; 32 | match b4 { 33 | mp4::BOX_FILETYPE => FileFormat::MP4, 34 | _ => FileFormat::Bitstream, 35 | } 36 | } 37 | }; 38 | Ok(fmt) 39 | } 40 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate av1parser; 2 | extern crate byteorder; 3 | #[macro_use] 4 | extern crate clap; 5 | extern crate hex; 6 | 7 | use av1parser::*; 8 | use clap::{App, Arg}; 9 | use std::cmp; 10 | use std::fs; 11 | use std::io; 12 | use std::io::{Seek, SeekFrom}; 13 | 14 | mod av1; 15 | mod bitio; 16 | mod ivf; 17 | mod mkv; 18 | mod mp4; 19 | mod obu; 20 | 21 | /// application global config 22 | struct AppConfig { 23 | verbose: u64, 24 | } 25 | 26 | /// 27 | /// process OBU(Open Bitstream Unit) 28 | /// 29 | fn process_obu( 30 | reader: &mut R, 31 | seq: &mut av1::Sequence, 32 | obu: &obu::Obu, 33 | config: &AppConfig, 34 | ) { 35 | let reader = &mut io::Read::take(reader, obu.obu_size as u64); 36 | match obu.obu_type { 37 | obu::OBU_SEQUENCE_HEADER => { 38 | if let Some(sh) = obu::parse_sequence_header(reader) { 39 | if config.verbose > 1 { 40 | println!(" {:?}", sh); 41 | } 42 | seq.sh = Some(sh); 43 | } else { 44 | println!(" invalid SequenceHeader"); 45 | } 46 | } 47 | obu::OBU_FRAME_HEADER | obu::OBU_FRAME => { 48 | if seq.sh.is_none() { 49 | if config.verbose > 1 { 50 | println!(" no sequence header"); 51 | } 52 | return; 53 | } 54 | if let Some(fh) = 55 | obu::parse_frame_header(reader, seq.sh.as_ref().unwrap(), &mut seq.rfman) 56 | { 57 | if !fh.show_existing_frame { 58 | let error_resilient = if fh.error_resilient_mode { "*" } else { "" }; 59 | if fh.show_frame { 60 | println!( 61 | " #{} {}{}, update({}), show@{}", 62 | seq.rfman.decode_order, 63 | av1::stringify::frame_type(fh.frame_type), 64 | error_resilient, 65 | av1::stringify::ref_frame(fh.refresh_frame_flags), 66 | seq.rfman.present_order 67 | ); 68 | } else { 69 | println!( 70 | " #{} {}{}, update({}), {}", 71 | seq.rfman.decode_order, 72 | av1::stringify::frame_type(fh.frame_type), 73 | error_resilient, 74 | av1::stringify::ref_frame(fh.refresh_frame_flags), 75 | if fh.showable_frame { 76 | "showable" 77 | } else { 78 | "(refonly)" 79 | } 80 | ); 81 | } 82 | } else { 83 | let show_idx = fh.frame_to_show_map_idx; 84 | println!( 85 | " #{} ({}) show@{}", 86 | seq.rfman.frame_buf[show_idx as usize], 87 | av1::stringify::ref_frame(1 << show_idx), 88 | seq.rfman.present_order, 89 | ); 90 | } 91 | if config.verbose > 1 { 92 | println!(" {:?}", fh); 93 | } 94 | 95 | // decode_frame_wrapup(): Decode frame wrapup process 96 | if fh.show_frame || fh.show_existing_frame { 97 | seq.rfman.output_process(&fh); 98 | } 99 | if !fh.show_existing_frame { 100 | if config.verbose > 2 { 101 | println!(" {:?}", seq.rfman); 102 | } 103 | seq.rfman.update_process(&fh); 104 | } 105 | } 106 | } 107 | obu::OBU_TILE_LIST => { 108 | if let Some(tl) = obu::parse_tile_list(reader) { 109 | if config.verbose > 2 { 110 | println!(" {:?}", tl); 111 | } 112 | } else { 113 | println!(" invalid TileList") 114 | } 115 | } 116 | obu::OBU_METADATA => { 117 | if let Ok(metadata) = obu::parse_metadata_obu(reader) { 118 | if config.verbose > 1 { 119 | println!(" {:?}", metadata); 120 | } 121 | } else { 122 | println!(" invalid MetadataObu"); 123 | } 124 | } 125 | _ => {} 126 | } 127 | } 128 | 129 | /// parse IVF format 130 | fn parse_ivf_format( 131 | mut reader: R, 132 | fname: &str, 133 | config: &AppConfig, 134 | ) -> io::Result<()> { 135 | // parse IVF header 136 | let mut ivf_header = [0; ivf::IVF_HEADER_SIZE]; 137 | reader.read_exact(&mut ivf_header)?; 138 | match ivf::parse_ivf_header(&ivf_header) { 139 | Ok(hdr) => { 140 | let codec = String::from_utf8(hdr.codec.to_vec()).unwrap(); 141 | println!( 142 | "{}: IVF codec={:?} size={}x{} timescale={}/{} length={}", 143 | fname, 144 | codec, 145 | hdr.width, 146 | hdr.height, 147 | hdr.timescale_num, 148 | hdr.timescale_den, 149 | hdr.length 150 | ); 151 | if hdr.codec != FCC_AV01 { 152 | println!( 153 | "{}: unsupport codec(0x{})", 154 | fname, 155 | hex::encode_upper(hdr.codec) 156 | ); 157 | return Ok(()); 158 | } 159 | } 160 | Err(msg) => { 161 | println!("{}: {}", fname, msg); 162 | return Ok(()); 163 | } 164 | }; 165 | 166 | let mut seq = av1::Sequence::new(); 167 | 168 | // parse IVF frames 169 | while let Ok(frame) = ivf::parse_ivf_frame(&mut reader) { 170 | if config.verbose > 0 { 171 | println!("IVF F#{} size={}", frame.pts, frame.size); 172 | } 173 | let mut sz = frame.size; 174 | let pos = reader.stream_position()?; 175 | // parse OBU(open bitstream unit)s 176 | while sz > 0 { 177 | let obu = obu::parse_obu_header(&mut reader, sz)?; 178 | if config.verbose > 0 { 179 | println!(" {}", obu); 180 | } 181 | sz -= obu.header_len + obu.obu_size; 182 | let pos = reader.stream_position()?; 183 | process_obu(&mut reader, &mut seq, &obu, config); 184 | reader.seek(SeekFrom::Start(pos + obu.obu_size as u64))?; 185 | } 186 | reader.seek(SeekFrom::Start(pos + frame.size as u64))?; 187 | } 188 | Ok(()) 189 | } 190 | 191 | /// parse WebM format 192 | fn parse_webm_format( 193 | mut reader: R, 194 | fname: &str, 195 | config: &AppConfig, 196 | ) -> io::Result<()> { 197 | // open Matroska/WebM file 198 | let mut webm = mkv::open_mkvfile(&mut reader)?; 199 | 200 | let codec_id = mkv::CODEC_V_AV1; 201 | let track_num = match webm.find_track(codec_id) { 202 | Some(num) => num, 203 | _ => { 204 | println!("{}: Matroska/WebM \"{}\" codec not found", fname, codec_id); 205 | return Ok(()); 206 | } 207 | }; 208 | match webm.get_videosetting(track_num) { 209 | Some(video) => println!( 210 | "{}: Matroska/WebM codec=\"{}\" size={}x{}", 211 | fname, codec_id, video.pixel_width, video.pixel_height 212 | ), 213 | None => println!( 214 | "{}: Matroska/WebM codec=\"{}\" size=(unknown)", 215 | fname, codec_id 216 | ), 217 | } 218 | 219 | let mut seq = av1::Sequence::new(); 220 | 221 | // parse WebM block 222 | while let Ok(Some(block)) = webm.next_block(&mut reader) { 223 | if block.track_num != track_num { 224 | // skip non AV1 track data 225 | continue; 226 | } 227 | 228 | if config.verbose > 0 { 229 | println!( 230 | "MKV F#{} flags=0x{:02x} size={}", 231 | block.timecode, block.flags, block.size 232 | ); 233 | } 234 | let mut sz = block.size as u32; 235 | // parse OBU(open bitstream unit)s 236 | while sz > 0 { 237 | let obu = obu::parse_obu_header(&mut reader, sz)?; 238 | if config.verbose > 0 { 239 | println!(" {}", obu); 240 | } 241 | sz -= obu.header_len + obu.obu_size; 242 | let pos = reader.stream_position()?; 243 | process_obu(&mut reader, &mut seq, &obu, config); 244 | reader.seek(SeekFrom::Start(pos + obu.obu_size as u64))?; 245 | } 246 | 247 | reader.seek(SeekFrom::Start(block.offset + block.size))?; 248 | } 249 | Ok(()) 250 | } 251 | 252 | /// parse MP4(ISOBMFF) format 253 | fn parse_mp4_format( 254 | mut reader: R, 255 | fname: &str, 256 | config: &AppConfig, 257 | ) -> io::Result<()> { 258 | // open MP4(ISOBMFF) file 259 | let mp4 = mp4::open_mp4file(&mut reader)?; 260 | if config.verbose > 1 { 261 | println!(" {:?}", mp4.get_filetype()); 262 | } 263 | 264 | let brand_av01 = mp4::FCC::from(mp4::BRAND_AV01); 265 | let brands = &mp4.get_filetype().compatible_brands; 266 | if !brands.iter().any(|b| *b == brand_av01) { 267 | println!("{}: ISOBMFF/MP4 {} brand not found", fname, brand_av01); 268 | return Ok(()); 269 | } 270 | let (av1se, av1cc) = match mp4.get_av1config() { 271 | Some(config) => config, 272 | None => { 273 | println!("{}: ISOBMFF/MP4 {} track not found", fname, brand_av01); 274 | return Ok(()); 275 | } 276 | }; 277 | println!( 278 | "{}: ISOBMFF/MP4 codec={} size={}x{}", 279 | fname, brand_av01, av1se.width, av1se.height 280 | ); 281 | if config.verbose > 1 { 282 | println!(" {:?}", av1se); 283 | println!(" {:?}", av1cc); 284 | } 285 | 286 | let mut seq = av1::Sequence::new(); 287 | 288 | // process AV1CodecConfigurationBox::configOBUs 289 | let mut cur = io::Cursor::new(av1cc.config_obus.clone()); 290 | let mut config_sz = av1cc.config_obus.len() as u32; 291 | while config_sz > 0 { 292 | let obu = obu::parse_obu_header(&mut cur, config_sz)?; 293 | if config.verbose > 0 { 294 | println!(" {}", obu); 295 | } 296 | config_sz -= obu.header_len + obu.obu_size; 297 | process_obu(&mut cur, &mut seq, &obu, config); 298 | } 299 | 300 | // parse AV1 Samples 301 | for sample in mp4.get_samples() { 302 | reader.seek(SeekFrom::Start(sample.pos))?; 303 | let mut sz = sample.size; 304 | // parse OBU(open bitstream unit)s 305 | while sz > 0 { 306 | let obu_size = cmp::min(sz, u32::MAX as u64) as u32; 307 | let obu = obu::parse_obu_header(&mut reader, obu_size)?; 308 | if config.verbose > 0 { 309 | println!(" {}", obu); 310 | } 311 | sz -= (obu.header_len + obu.obu_size) as u64; 312 | let pos = reader.stream_position()?; 313 | process_obu(&mut reader, &mut seq, &obu, config); 314 | reader.seek(SeekFrom::Start(pos + obu.obu_size as u64))?; 315 | } 316 | } 317 | Ok(()) 318 | } 319 | 320 | /// parse low overhead bitstream format 321 | fn parse_obu_bitstream( 322 | mut reader: R, 323 | fname: &str, 324 | config: &AppConfig, 325 | ) -> io::Result<()> { 326 | println!("{}: Raw stream", fname); 327 | 328 | let mut seq = av1::Sequence::new(); 329 | let sz = u32::MAX; 330 | let mut fnum = 0; 331 | 332 | // parse OBU(open bitstream unit)s sequence 333 | while let Ok(obu) = obu::parse_obu_header(&mut reader, sz) { 334 | if config.verbose > 0 { 335 | if obu.obu_type == obu::OBU_TEMPORAL_DELIMITER { 336 | println!("Raw F#{}", fnum); 337 | fnum += 1; 338 | } 339 | println!(" {}", obu); 340 | } 341 | let pos = reader.stream_position()?; 342 | process_obu(&mut reader, &mut seq, &obu, config); 343 | reader.seek(SeekFrom::Start(pos + obu.obu_size as u64))?; 344 | } 345 | Ok(()) 346 | } 347 | 348 | /// process input file 349 | fn process_file(fname: &str, config: &AppConfig) -> io::Result<()> { 350 | // open input file as read-only mode 351 | let f = fs::OpenOptions::new().read(true).open(fname)?; 352 | let mut reader = io::BufReader::new(f); 353 | 354 | // probe media container format 355 | let fmt = probe_fileformat(&mut reader)?; 356 | reader.seek(SeekFrom::Start(0))?; 357 | 358 | match fmt { 359 | FileFormat::IVF => parse_ivf_format(reader, fname, config)?, 360 | FileFormat::WebM => parse_webm_format(reader, fname, config)?, 361 | FileFormat::MP4 => parse_mp4_format(reader, fname, config)?, 362 | FileFormat::Bitstream => parse_obu_bitstream(reader, fname, config)?, 363 | }; 364 | Ok(()) 365 | } 366 | 367 | /// application entry point 368 | fn main() -> std::io::Result<()> { 369 | let app = App::new(crate_name!()) 370 | .version(crate_version!()) 371 | .about(crate_description!()) 372 | .arg(Arg::from_usage("... 'Input AV1 bitstream files'").index(1)) 373 | .arg(Arg::from_usage("[v]... -v --verbose 'Show verbose log'")); 374 | 375 | // get commandline flags 376 | let matches = app.get_matches(); 377 | let config = AppConfig { 378 | verbose: matches.occurrences_of("v"), 379 | }; 380 | 381 | for fname in matches.values_of("INPUT").unwrap() { 382 | process_file(fname, &config)?; 383 | } 384 | Ok(()) 385 | } 386 | -------------------------------------------------------------------------------- /src/mkv.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | /// 3 | /// https://matroska.org/technical/specs/index.html 4 | /// 5 | use byteorder::{BigEndian, ByteOrder}; 6 | use std::io; 7 | use std::io::{Read, SeekFrom}; 8 | 9 | // Element ID 10 | const ELEMENT_EBML: u32 = 0x1A45DFA3; // EBML header 11 | const ELEMENT_SEGMENT: u32 = 0x18538067; // Segment 12 | const ELEMENT_SEEKHEAD: u32 = 0x114D9B74; // Meta Seek Information 13 | const ELEMENT_INFO: u32 = 0x1549A966; // Segment Information 14 | const ELEMENT_CLUSTER: u32 = 0x1F43B675; // Cluster 15 | const ELEMENT_TIMECODE: u32 = 0xE7; // Cluster/Timecode 16 | const ELEMENT_SIMPLEBLOCK: u32 = 0xA3; // Cluster/SimpleBlock 17 | const ELEMENT_BLOCKGROUP: u32 = 0xA0; // Cluster/BlockGroup 18 | const ELEMENT_TRACKS: u32 = 0x1654AE6B; // Track 19 | const ELEMENT_TRACKENTRY: u32 = 0xAE; // Tracks/TrackEntry 20 | const ELEMENT_TRACKNUMBER: u32 = 0xD7; // Tracks/TrackEntry/TrackNumber 21 | const ELEMENT_TRACKTYPE: u32 = 0x83; // Tracks/TrackEntry/TrackType 22 | const ELEMENT_CODECID: u32 = 0x86; // Tracks/TrackEntry/CodecID 23 | const ELEMENT_VIDEO: u32 = 0xE0; // Tracks/TrackEntry/Video 24 | const ELEMENT_PIXELWIDTH: u32 = 0xB0; // Tracks/TrackEntry/Video/PixelWidth 25 | const ELEMENT_PIXELHEIGHT: u32 = 0xBA; // Tracks/TrackEntry/Video/PixelHeight 26 | const ELEMENT_CUES: u32 = 0x1C53BB6B; // Cueing Data 27 | 28 | // Codec ID 29 | pub const CODEC_V_AV1: &str = "V_AV1"; // video/AV1 30 | 31 | /// Element ID (1-4 bytes) 32 | fn read_elementid(mut reader: R) -> io::Result { 33 | let mut b0 = [0; 1]; 34 | reader.read_exact(&mut b0)?; 35 | let value: u32; 36 | if b0[0] & 0b1000_0000 == 0b1000_0000 { 37 | value = b0[0] as u32; 38 | } else if b0[0] & 0b1100_0000 == 0b0100_0000 { 39 | let mut b1 = [0; 1]; 40 | reader.read_exact(&mut b1)?; 41 | value = (b0[0] as u32) << 8 | b1[0] as u32; 42 | } else if b0[0] & 0b1110_0000 == 0b0010_0000 { 43 | let mut b2 = [0; 2]; 44 | reader.read_exact(&mut b2)?; 45 | value = (b0[0] as u32) << 16 | (b2[0] as u32) << 8 | b2[1] as u32; 46 | } else if b0[0] & 0b1111_0000 == 0b0001_0000 { 47 | let mut b3 = [0; 3]; 48 | reader.read_exact(&mut b3)?; 49 | value = (b0[0] as u32) << 24 | (b3[0] as u32) << 16 | (b3[1] as u32) << 8 | b3[2] as u32; 50 | } else { 51 | return Err(io::Error::new( 52 | io::ErrorKind::InvalidData, 53 | "Invalid ElementID", 54 | )); 55 | } 56 | Ok(value) 57 | } 58 | 59 | /// variable length codeded integer, return (value, length) 60 | fn read_varint(mut reader: R) -> io::Result<(i64, usize)> { 61 | let mut b0 = [0; 1]; 62 | reader.read_exact(&mut b0)?; 63 | let mut value = b0[0] as i64; 64 | let lzcnt = b0[0].leading_zeros() as usize; 65 | if lzcnt > 7 { 66 | return Err(io::Error::new( 67 | io::ErrorKind::InvalidData, 68 | "Invalid leading zero bits", 69 | )); 70 | } 71 | value &= (1 << (7 - lzcnt)) - 1; 72 | if lzcnt > 0 { 73 | let mut buf = [0; 7]; 74 | let rlen = reader.take(lzcnt as u64).read(&mut buf)?; 75 | if rlen < lzcnt { 76 | return Err(io::Error::new( 77 | io::ErrorKind::UnexpectedEof, 78 | "Unexpected EOF at variable length codeded integer", 79 | )); 80 | } 81 | for i in 0..lzcnt { 82 | value = (value << 8) | buf[i] as i64; 83 | } 84 | } 85 | Ok((value, 1 + lzcnt)) 86 | } 87 | 88 | /// Data size (1-8 bytes) 89 | #[inline] 90 | fn read_datasize(reader: R) -> io::Result { 91 | let (value, _) = read_varint(reader)?; 92 | Ok(value) 93 | } 94 | 95 | /// Unsigned integer (1-8 bytes) 96 | fn read_uint(reader: R, len: i64) -> io::Result { 97 | assert!(0 < len && len <= 8); 98 | let mut buf = [0; 8]; 99 | let rlen = reader.take(len as u64).read(&mut buf)?; 100 | if rlen < len as usize { 101 | return Err(io::Error::new( 102 | io::ErrorKind::UnexpectedEof, 103 | "Unexpected EOF at unsigned integer", 104 | )); 105 | } 106 | let mut value = buf[0] as u64; 107 | for i in 1..(len as usize) { 108 | value = value << 8 | buf[i] as u64; 109 | } 110 | Ok(value) 111 | } 112 | 113 | /// String (1-n bytes) 114 | fn read_string(reader: R, len: i64) -> io::Result { 115 | assert!(0 < len); 116 | let mut value = String::new(); 117 | reader.take(len as u64).read_to_string(&mut value)?; 118 | Ok(value) 119 | } 120 | 121 | /// 122 | /// Matorska format 123 | /// 124 | #[derive(Debug)] 125 | pub struct Matroska { 126 | tracks: Vec, 127 | clusters: Vec, 128 | curr_cluster: usize, 129 | curr_offset: u64, 130 | } 131 | 132 | impl Matroska { 133 | fn new() -> Self { 134 | Matroska { 135 | tracks: Vec::new(), 136 | clusters: Vec::new(), 137 | curr_cluster: 0, 138 | curr_offset: 0, 139 | } 140 | } 141 | 142 | /// find track with CodecID 143 | pub fn find_track(&self, codec_id: &str) -> Option { 144 | self.tracks 145 | .iter() 146 | .find(|t| t.codec_id == codec_id) 147 | .map(|t| t.track_num) 148 | } 149 | 150 | /// get Video settings 151 | pub fn get_videosetting(&self, track_num: u64) -> Option<&VideoTrack> { 152 | self.tracks 153 | .iter() 154 | .find(|t| t.track_num == track_num) 155 | .and_then(|t| t.setting.as_ref()) 156 | } 157 | 158 | /// read next block 159 | pub fn next_block( 160 | &mut self, 161 | mut reader: R, 162 | ) -> io::Result> { 163 | if self.curr_offset == 0 { 164 | if self.clusters.len() <= self.curr_cluster { 165 | return Ok(None); // end of clusters 166 | } 167 | self.curr_offset = self.clusters[self.curr_cluster].pos_begin; 168 | } 169 | reader.seek(SeekFrom::Start(self.curr_offset))?; 170 | loop { 171 | // seek to SimpleBlock element 172 | let node = read_elementid(&mut reader)?; 173 | let node_size = read_datasize(&mut reader)?; 174 | if node != ELEMENT_SIMPLEBLOCK { 175 | reader.seek(SeekFrom::Current(node_size))?; 176 | continue; 177 | } 178 | 179 | // read SimpleBlock header (4- bytes) 180 | let (track_num, len) = read_varint(&mut reader)?; 181 | let mut buf = [0; 3]; 182 | reader.read_exact(&mut buf)?; 183 | let tc_offset = BigEndian::read_i16(&buf); 184 | let node_size = (node_size - (len as i64) - 3) as u64; 185 | let flags = buf[2]; 186 | 187 | self.curr_offset = reader.stream_position()? + node_size; 188 | return Ok(Some(Block { 189 | track_num: track_num as u64, 190 | timecode: self.clusters[self.curr_cluster].timecode + (tc_offset as i64), 191 | flags: flags, 192 | offset: self.curr_offset, 193 | size: node_size, 194 | })); 195 | } 196 | } 197 | 198 | // TrackEntry element 199 | fn read_trackentry(mut reader: R) -> io::Result { 200 | let mut entry = TrackEntey::default(); 201 | while let Ok(node) = read_elementid(&mut reader) { 202 | let node_size = read_datasize(&mut reader)?; 203 | match node { 204 | ELEMENT_TRACKNUMBER => entry.track_num = read_uint(&mut reader, node_size)?, 205 | ELEMENT_TRACKTYPE => entry.track_type = read_uint(&mut reader, node_size)?, 206 | ELEMENT_CODECID => entry.codec_id = read_string(&mut reader, node_size)?, 207 | ELEMENT_VIDEO => { 208 | let mut node_body = Vec::with_capacity(node_size as usize); 209 | node_body.resize(node_size as usize, 0); 210 | reader.read_exact(&mut node_body)?; 211 | let node_body = io::Cursor::new(node_body); 212 | let video = Self::read_videoentry(node_body)?; 213 | entry.setting = Some(video); 214 | } 215 | _ => { 216 | reader.seek(SeekFrom::Current(node_size))?; 217 | } 218 | }; 219 | } 220 | Ok(entry) 221 | } 222 | 223 | // Video element 224 | fn read_videoentry(mut reader: R) -> io::Result { 225 | let mut video = VideoTrack::default(); 226 | while let Ok(node) = read_elementid(&mut reader) { 227 | let node_size = read_datasize(&mut reader)?; 228 | match node { 229 | ELEMENT_PIXELWIDTH => video.pixel_width = read_uint(&mut reader, node_size)?, 230 | ELEMENT_PIXELHEIGHT => video.pixel_height = read_uint(&mut reader, node_size)?, 231 | _ => { 232 | reader.seek(SeekFrom::Current(node_size))?; 233 | } 234 | } 235 | } 236 | Ok(video) 237 | } 238 | 239 | // Track element 240 | fn read_track(&mut self, mut reader: R) -> io::Result<()> { 241 | let mut pos = reader.stream_position()?; 242 | // TrackEntry nodes 243 | while let Ok(entry) = read_elementid(&mut reader) { 244 | if entry != ELEMENT_TRACKENTRY { 245 | reader.seek(SeekFrom::Start(pos))?; 246 | break; 247 | } 248 | let entry_size = read_datasize(&mut reader)? as usize; 249 | 250 | // add new track 251 | let mut entry_body = Vec::with_capacity(entry_size); 252 | entry_body.resize(entry_size, 0); 253 | reader.read_exact(&mut entry_body)?; 254 | let entry_body = io::Cursor::new(entry_body); 255 | self.tracks.push(Self::read_trackentry(entry_body)?); 256 | 257 | pos = reader.stream_position()?; 258 | } 259 | Ok(()) 260 | } 261 | 262 | // Cluster element 263 | fn read_cluster( 264 | &mut self, 265 | mut reader: R, 266 | node_size: i64, 267 | ) -> io::Result<()> { 268 | let mut pos = reader.stream_position()?; 269 | let limit_pos = pos + node_size as u64; 270 | 271 | let mut cluster = Cluster { 272 | pos_end: limit_pos, 273 | ..Default::default() 274 | }; 275 | let mut first_block = true; 276 | 277 | // Level2 elements 278 | while let Ok(node) = read_elementid(&mut reader) { 279 | let node_size = read_datasize(&mut reader)?; 280 | match node { 281 | ELEMENT_TIMECODE => cluster.timecode = read_uint(&mut reader, node_size)? as i64, 282 | ELEMENT_SIMPLEBLOCK => { 283 | if first_block { 284 | // store offset of first Block 285 | cluster.pos_begin = pos; 286 | first_block = false; 287 | } 288 | reader.seek(SeekFrom::Current(node_size))?; 289 | } 290 | ELEMENT_BLOCKGROUP => unimplemented!("BlockGroup"), 291 | _ => { 292 | reader.seek(SeekFrom::Current(node_size))?; 293 | } 294 | } 295 | 296 | pos = reader.stream_position()?; 297 | if limit_pos <= pos { 298 | break; 299 | } 300 | } 301 | self.clusters.push(cluster); 302 | Ok(()) 303 | } 304 | } 305 | 306 | /// 307 | /// Matroska/TrackEntry 308 | /// 309 | #[derive(Debug, Default)] 310 | struct TrackEntey { 311 | track_num: u64, 312 | track_type: u64, 313 | codec_id: String, 314 | setting: Option, 315 | } 316 | 317 | /// 318 | /// Matroska/TrackEntry/Video settings 319 | /// 320 | #[derive(Debug, Default)] 321 | pub struct VideoTrack { 322 | pub pixel_width: u64, // PixelWidth 323 | pub pixel_height: u64, // PixelHeight 324 | } 325 | 326 | /// 327 | /// Matroska/Cluster 328 | /// 329 | #[derive(Debug, Default)] 330 | struct Cluster { 331 | timecode: i64, 332 | pos_begin: u64, 333 | pos_end: u64, 334 | } 335 | 336 | /// 337 | /// Matroska/(Simple)Block 338 | /// 339 | #[derive(Debug)] 340 | pub struct Block { 341 | pub track_num: u64, 342 | pub timecode: i64, 343 | pub flags: u8, 344 | pub offset: u64, 345 | pub size: u64, 346 | } 347 | 348 | /// 349 | /// open Matroska/WebM file 350 | /// 351 | pub fn open_mkvfile(mut reader: R) -> io::Result { 352 | // EBML header 353 | let ebml_tag = read_elementid(&mut reader)?; 354 | if ebml_tag != ELEMENT_EBML { 355 | return Err(io::Error::new( 356 | io::ErrorKind::InvalidData, 357 | "Invalid EBML header", 358 | )); 359 | } 360 | let ebml_size = read_datasize(&mut reader)?; 361 | reader.seek(SeekFrom::Current(ebml_size))?; 362 | 363 | // Segment 364 | let segment_tag = read_elementid(&mut reader)?; 365 | if segment_tag != ELEMENT_SEGMENT { 366 | return Err(io::Error::new( 367 | io::ErrorKind::InvalidData, 368 | "Invalid Segment element", 369 | )); 370 | } 371 | let _segment_size = read_datasize(&mut reader)?; 372 | 373 | // Level1 elements 374 | let mut mkv = Matroska::new(); 375 | while let Ok(node) = read_elementid(&mut reader) { 376 | let node_size = read_datasize(&mut reader)?; 377 | match node { 378 | ELEMENT_TRACKS => mkv.read_track(&mut reader)?, 379 | ELEMENT_CLUSTER => mkv.read_cluster(&mut reader, node_size)?, 380 | _ => { 381 | reader.seek(SeekFrom::Current(node_size))?; 382 | } 383 | }; 384 | } 385 | 386 | Ok(mkv) 387 | } 388 | -------------------------------------------------------------------------------- /src/mp4.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | /// 3 | /// https://aomediacodec.github.io/av1-isobmff/ 4 | /// 5 | use byteorder::{BigEndian, ByteOrder}; 6 | use std::cmp; 7 | use std::convert; 8 | use std::fmt; 9 | use std::io; 10 | use std::io::{Read, SeekFrom}; 11 | 12 | pub const BOX_FILETYPE: [u8; 4] = *b"ftyp"; // FileType Box 13 | const BOX_MEDIADATA: [u8; 4] = *b"mdat"; // Media Data Box 14 | const BOX_MOVIE: [u8; 4] = *b"moov"; // Movie Box 15 | const BOX_MOVIEHEADER: [u8; 4] = *b"mvhd"; // Movie Header Box 16 | const BOX_TRACK: [u8; 4] = *b"trak"; // Track Box 17 | const BOX_TRACKHEADER: [u8; 4] = *b"tkhd"; // Track Header Box 18 | const BOX_MEDIA: [u8; 4] = *b"mdia"; // Media Box 19 | const BOX_MEDIAINFORMATION: [u8; 4] = *b"minf"; // Media Information Box 20 | const BOX_SAMPLETABLE: [u8; 4] = *b"stbl"; // Sample Table Box 21 | const BOX_SAMPLEDESCRIPTION: [u8; 4] = *b"stsd"; // Sample Description Box 22 | const BOX_SAMPLETOCHUNK: [u8; 4] = *b"stsc"; // Sample To Chunk Box 23 | const BOX_SAMPLESIZE: [u8; 4] = *b"stsz"; // Sample Size Box 24 | const BOX_CHUNKOFFSET: [u8; 4] = *b"stco"; // Chunk Offset Box/32bit 25 | const BOX_CHUNKOFFSET64: [u8; 4] = *b"co64"; // Chunk Offset Box/64bit 26 | const BOX_AV1SAMPLEENTRY: [u8; 4] = *b"av01"; // AV1 Sample Entry 27 | const BOX_AV1CODECCONFIG: [u8; 4] = *b"av1C"; // AV1 Codec Configuration Box 28 | 29 | pub const BRAND_AV01: [u8; 4] = *b"av01"; 30 | 31 | /// 32 | /// Four charactors code (u32) 33 | /// 34 | #[derive(PartialEq)] 35 | pub struct FCC { 36 | fcc: [u8; 4], 37 | } 38 | 39 | impl convert::From<[u8; 4]> for FCC { 40 | fn from(fcc: [u8; 4]) -> Self { 41 | Self { fcc } 42 | } 43 | } 44 | 45 | impl cmp::PartialEq<[u8; 4]> for FCC { 46 | #[must_use] 47 | fn eq(&self, other: &[u8; 4]) -> bool { 48 | self.fcc == *other 49 | } 50 | } 51 | 52 | impl fmt::Display for FCC { 53 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 54 | f.write_fmt(format_args!( 55 | "{}{}{}{}", 56 | self.fcc[0] as char, self.fcc[1] as char, self.fcc[2] as char, self.fcc[3] as char 57 | )) 58 | } 59 | } 60 | 61 | impl fmt::Debug for FCC { 62 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 63 | // same as fmt::Display 64 | f.write_fmt(format_args!("{}", self)) 65 | } 66 | } 67 | 68 | fn read_fcc(mut reader: R) -> io::Result { 69 | let mut fcc = [0; 4]; 70 | reader.read_exact(&mut fcc)?; 71 | Ok(FCC { fcc }) 72 | } 73 | 74 | fn read_u16(mut reader: R) -> io::Result { 75 | let mut value = [0; 2]; 76 | reader.read_exact(&mut value)?; 77 | Ok(BigEndian::read_u16(&value)) 78 | } 79 | 80 | fn read_u32(mut reader: R) -> io::Result { 81 | let mut value = [0; 4]; 82 | reader.read_exact(&mut value)?; 83 | Ok(BigEndian::read_u32(&value)) 84 | } 85 | 86 | fn read_u64(mut reader: R) -> io::Result { 87 | let mut value = [0; 8]; 88 | reader.read_exact(&mut value)?; 89 | Ok(BigEndian::read_u64(&value)) 90 | } 91 | 92 | /// read Box header, return (boxtype, payload_size) 93 | fn read_box(mut reader: R) -> io::Result<(FCC, u64)> { 94 | let size = read_u32(&mut reader)? as u64; 95 | let boxtype = read_fcc(&mut reader)?; 96 | let payload_size = if size == 1 { 97 | let largesize = read_u64(&mut reader)?; 98 | if largesize < 16 { 99 | return Err(io::Error::new( 100 | io::ErrorKind::InvalidData, 101 | format!("Too small Box(largesize={})", largesize), 102 | )); 103 | } 104 | largesize - 16 105 | } else if size == 0 { 106 | unimplemented!("box extends to end of file") 107 | } else { 108 | if size < 8 { 109 | return Err(io::Error::new( 110 | io::ErrorKind::InvalidData, 111 | format!("Too small Box(size={})", size), 112 | )); 113 | } 114 | size as u64 - 8 115 | }; 116 | Ok((boxtype, payload_size)) 117 | } 118 | 119 | /// 120 | /// FileTypeBox 121 | /// 122 | #[derive(Debug)] 123 | pub struct FileTypeBox { 124 | pub major_brand: FCC, 125 | pub minor_version: u32, 126 | pub compatible_brands: Vec, 127 | } 128 | 129 | /// read FileTypeBox 130 | fn read_ftypbox(mut reader: R) -> io::Result { 131 | let (boxtype, mut payload_size) = read_box(&mut reader)?; 132 | if boxtype != BOX_FILETYPE { 133 | return Err(io::Error::new( 134 | io::ErrorKind::InvalidData, 135 | format!("Invalid FileTypeBox boxtype={}", boxtype), 136 | )); 137 | } 138 | let major_brand = read_fcc(&mut reader)?; 139 | let minor_version = read_u32(&mut reader)?; 140 | payload_size -= 8; 141 | let mut compatible_brands = Vec::new(); 142 | while 4 <= payload_size { 143 | compatible_brands.push(read_fcc(&mut reader)?); 144 | payload_size -= 4; 145 | } 146 | 147 | Ok(FileTypeBox { 148 | major_brand, 149 | minor_version, 150 | compatible_brands, 151 | }) 152 | } 153 | 154 | /// 155 | /// AV1SampleEntry(VisualSampleEntry) 156 | /// 157 | #[derive(Debug, Default)] 158 | pub struct AV1SampleEntry { 159 | data_reference_index: u16, // ui(16) 160 | pub width: u16, // ui(16) 161 | pub height: u16, // ui(16) 162 | horizresolution: u32, // ui(32) 163 | vertresolution: u32, // ui(32) 164 | frame_count: u16, // ui(16) 165 | compressorname: [u8; 32], // string[32] 166 | depth: u16, // ui(16) 167 | } 168 | 169 | fn read_av1sampleentry(mut reader: R) -> io::Result { 170 | let mut av1se = AV1SampleEntry::default(); 171 | 172 | // SampleEntry 173 | let mut _reserved0 = [0; 6]; 174 | reader.read_exact(&mut _reserved0)?; 175 | av1se.data_reference_index = read_u16(&mut reader)?; 176 | // VisualSampleEntry 177 | let mut _reserved1 = [0; 16]; 178 | reader.read_exact(&mut _reserved1)?; 179 | av1se.width = read_u16(&mut reader)?; 180 | av1se.height = read_u16(&mut reader)?; 181 | av1se.horizresolution = read_u32(&mut reader)?; 182 | av1se.vertresolution = read_u32(&mut reader)?; 183 | let _reserved2 = read_u32(&mut reader)?; 184 | av1se.frame_count = read_u16(&mut reader)?; 185 | reader.read_exact(&mut av1se.compressorname)?; 186 | av1se.depth = read_u16(&mut reader)?; 187 | let _pre_defined = read_u16(&mut reader)?; 188 | 189 | Ok(av1se) 190 | } 191 | 192 | /// 193 | /// AV1CodecConfigurationBox 194 | /// 195 | #[derive(Debug, Default)] 196 | pub struct AV1CodecConfigurationBox { 197 | pub seq_profile: u8, // ui(3) 198 | pub seq_level_idx_0: u8, // ui(5) 199 | pub seq_tier_0: u8, // ui(1) 200 | pub high_bitdepth: u8, // ui(1) 201 | pub twelve_bit: u8, // ui(1) 202 | pub monochrome: u8, // ui(1) 203 | pub chroma_subsampling_x: u8, // ui(1) 204 | pub chroma_subsampling_y: u8, // ui(1) 205 | pub chroma_sample_position: u8, // ui(2) 206 | pub initial_presentation_delay_present: bool, // ui(1) 207 | pub initial_presentation_delay_minus_one: u8, // ui(4) 208 | pub config_obus: Vec, // ui(8)[] 209 | } 210 | 211 | fn read_av1codecconfig( 212 | mut reader: R, 213 | payload_size: u64, 214 | ) -> io::Result { 215 | let mut av1cc = AV1CodecConfigurationBox::default(); 216 | 217 | let mut bb = [0; 4]; 218 | reader.read_exact(&mut bb)?; 219 | let (marker, version) = (bb[0] >> 7, bb[0] & 0x7f); 220 | if marker != 1 || version != 1 { 221 | return Err(io::Error::new( 222 | io::ErrorKind::InvalidData, 223 | format!( 224 | "Invalid AV1CodecConfigurationBox(marker={}, version={})", 225 | marker, version 226 | ), 227 | )); 228 | } 229 | av1cc.seq_profile = bb[1] >> 5; // ui(3) 230 | av1cc.seq_level_idx_0 = bb[1] & 0x1f; // ui(5) 231 | av1cc.seq_tier_0 = bb[2] >> 7; // ui(1) 232 | av1cc.high_bitdepth = (bb[2] >> 6) & 1; // ui(1) 233 | av1cc.twelve_bit = (bb[2] >> 5) & 1; // ui(1) 234 | av1cc.monochrome = (bb[2] >> 4) & 1; // ui(1) 235 | av1cc.chroma_subsampling_x = (bb[2] >> 3) & 1; // ui(1) 236 | av1cc.chroma_subsampling_y = (bb[2] >> 2) & 1; // ui(1) 237 | av1cc.chroma_sample_position = bb[2] & 3; // ui(2) 238 | let _reserved = bb[3] >> 5; // ui(3) 239 | av1cc.initial_presentation_delay_present = ((bb[3] >> 4) & 1) != 0; // ui(1) 240 | av1cc.initial_presentation_delay_minus_one = bb[3] & 0xf; // ui(4) 241 | if 4 < payload_size { 242 | reader 243 | .take(payload_size - 4) 244 | .read_to_end(&mut av1cc.config_obus)?; 245 | } 246 | Ok(av1cc) 247 | } 248 | 249 | /// parse SampleDescriptionBox payload 250 | fn parse_sampledescription( 251 | mut reader: R, 252 | ) -> io::Result> { 253 | let mut payload = None; 254 | let _version_flag = read_u32(&mut reader)?; 255 | let entry_count = read_u32(&mut reader)?; 256 | for _ in 0..entry_count { 257 | let (boxtype, size) = read_box(&mut reader)?; 258 | if boxtype == BOX_AV1SAMPLEENTRY { 259 | // read AV1SampleEntry 260 | let av1se = read_av1sampleentry(&mut reader)?; 261 | // read AV1CodecConfigurationBox 262 | let (boxtype, size) = read_box(&mut reader)?; 263 | if boxtype != BOX_AV1CODECCONFIG { 264 | return Err(io::Error::new( 265 | io::ErrorKind::InvalidData, 266 | format!( 267 | "Invalid AV1CodecConfigurationBox(boxtype={}, size={})", 268 | boxtype, size 269 | ), 270 | )); 271 | } 272 | let av1cc = read_av1codecconfig(&mut reader, size)?; 273 | payload = Some((av1se, av1cc)); 274 | } else { 275 | // ignore unknown SampleEntry 276 | reader.seek(SeekFrom::Current(size as i64))?; 277 | } 278 | } 279 | Ok(payload) 280 | } 281 | 282 | /// parse SampleToChunkBox payload 283 | fn parse_sampletochunk(mut reader: R) -> io::Result> { 284 | let _version_flag = read_u32(&mut reader)?; 285 | let entry_count = read_u32(&mut reader)?; 286 | let mut stcs = Vec::with_capacity(entry_count as usize); 287 | for _ in 1..=entry_count { 288 | let first_chunk = read_u32(&mut reader)?; 289 | let samples_per_chunk = read_u32(&mut reader)?; 290 | let _sample_description_index = read_u32(&mut reader)?; 291 | stcs.push((first_chunk, samples_per_chunk)); 292 | } 293 | Ok(stcs) 294 | } 295 | 296 | /// parse SampleSizeBox payload 297 | fn parse_samplesize(mut reader: R) -> io::Result> { 298 | let _version_flag = read_u32(&mut reader)?; 299 | let sample_size = read_u32(&mut reader)?; 300 | let sample_count = read_u32(&mut reader)?; 301 | let mut sizes = Vec::with_capacity(sample_count as usize); 302 | if sample_size == 0 { 303 | for _ in 1..=sample_count { 304 | let entry_size = read_u32(&mut reader)?; 305 | sizes.push(entry_size); 306 | } 307 | } else { 308 | for _ in 1..=sample_count { 309 | sizes.push(sample_size); 310 | } 311 | } 312 | Ok(sizes) 313 | } 314 | 315 | /// parse ChunkOffsetBox/ChunkLargeOffsetBox payload 316 | fn parse_chunkoffset(mut reader: R, boxtype: FCC) -> io::Result> { 317 | assert!(boxtype == BOX_CHUNKOFFSET || boxtype == BOX_CHUNKOFFSET64); 318 | let _version_flag = read_u32(&mut reader)?; 319 | let entry_count = read_u32(&mut reader)?; 320 | let mut offsets = Vec::with_capacity(entry_count as usize); 321 | for _ in 0..entry_count { 322 | let chunk_offset = if boxtype == BOX_CHUNKOFFSET { 323 | read_u32(&mut reader)? as u64 324 | } else { 325 | read_u64(&mut reader)? 326 | }; 327 | offsets.push(chunk_offset); 328 | } 329 | Ok(offsets) 330 | } 331 | 332 | /// parse TrackBox payload 333 | fn parse_track( 334 | mut reader: R, 335 | size: u64, 336 | mp4: &mut IsoBmff, 337 | ) -> io::Result { 338 | let limit = reader.stream_position()? + size; 339 | let mut av1config = None; 340 | let (mut stsc, mut stsz, mut stco) = (Vec::new(), Vec::new(), Vec::new()); 341 | loop { 342 | // read next Box 343 | let (boxtype, size) = match read_box(&mut reader) { 344 | Ok(result) => result, 345 | Err(err) => { 346 | if err.kind() == io::ErrorKind::UnexpectedEof { 347 | break; 348 | } else { 349 | return Err(err); 350 | } 351 | } 352 | }; 353 | if boxtype == BOX_MEDIA || boxtype == BOX_MEDIAINFORMATION || boxtype == BOX_SAMPLETABLE { 354 | // parse nested Boxes 355 | } else if boxtype == BOX_SAMPLEDESCRIPTION { 356 | // parse SampleDescriptionBox 357 | av1config = parse_sampledescription(&mut reader)?; 358 | } else if boxtype == BOX_SAMPLETOCHUNK { 359 | // parse SampleToChunkBox 360 | stsc = parse_sampletochunk(&mut reader)?; 361 | } else if boxtype == BOX_SAMPLESIZE { 362 | // parse SampleSizeBox 363 | stsz = parse_samplesize(&mut reader)?; 364 | } else if boxtype == BOX_CHUNKOFFSET || boxtype == BOX_CHUNKOFFSET64 { 365 | // parse ChunkOffsetBox/ChunkLargeOffsetBox 366 | stco = parse_chunkoffset(&mut reader, boxtype)?; 367 | } else { 368 | reader.seek(SeekFrom::Current(size as i64))?; 369 | } 370 | if limit <= reader.stream_position()? { 371 | break; 372 | } 373 | } 374 | if av1config.is_none() { 375 | // This track is not 'av01' video 376 | return Ok(false); 377 | } 378 | mp4.av1config = av1config; 379 | 380 | // calculate Sample{pos,size} from stsc/stsz/stco 381 | let nsample = stsz.len(); 382 | let mut samples = Vec::with_capacity(nsample); 383 | let (mut stsc_idx, mut stsz_idx, mut stco_idx) = (0, 0, 0); 384 | stsc.push((nsample as u32, 0)); // add sentinel 385 | while stsz_idx < nsample { 386 | let mut pos = stco[stco_idx]; 387 | for _ in 0..(stsc[stsc_idx].1) { 388 | let size = stsz[stsz_idx] as u64; 389 | samples.push(Sample { pos, size }); 390 | pos += size; 391 | stsz_idx += 1; 392 | } 393 | stco_idx += 1; 394 | if stsz_idx + 1 >= stsc[stsc_idx + 1].0 as usize { 395 | stsc_idx += 1; 396 | } 397 | } 398 | mp4.samples = samples; 399 | 400 | Ok(true) 401 | } 402 | 403 | /// 404 | /// Sample 405 | /// 406 | #[derive(Debug)] 407 | pub struct Sample { 408 | pub pos: u64, 409 | pub size: u64, 410 | } 411 | 412 | /// 413 | /// ISOBMFF/MP4 format 414 | /// 415 | #[derive(Debug)] 416 | pub struct IsoBmff { 417 | filetype: FileTypeBox, 418 | av1config: Option<(AV1SampleEntry, AV1CodecConfigurationBox)>, 419 | samples: Vec, 420 | } 421 | 422 | impl IsoBmff { 423 | fn new(filetype: FileTypeBox) -> Self { 424 | IsoBmff { 425 | filetype, 426 | av1config: None, 427 | samples: Vec::new(), 428 | } 429 | } 430 | 431 | // get FileTypeBox 432 | pub fn get_filetype(&self) -> &FileTypeBox { 433 | &self.filetype 434 | } 435 | 436 | /// get (AV1SampleEntry, AV1CodecConfigurationBox) 437 | pub fn get_av1config(&self) -> Option<&(AV1SampleEntry, AV1CodecConfigurationBox)> { 438 | self.av1config.as_ref() 439 | } 440 | 441 | /// get 'av01' Samples 442 | pub fn get_samples(&self) -> &Vec { 443 | &self.samples 444 | } 445 | } 446 | 447 | /// 448 | /// open ISOBMFF/MP4 file 449 | /// 450 | pub fn open_mp4file(mut reader: R) -> io::Result { 451 | // read FileTypeBox 452 | let ftyp_box = read_ftypbox(&mut reader)?; 453 | let mut mp4 = IsoBmff::new(ftyp_box); 454 | loop { 455 | // read next Box 456 | let (boxtype, size) = match read_box(&mut reader) { 457 | Ok(result) => result, 458 | Err(err) => { 459 | if err.kind() == io::ErrorKind::UnexpectedEof { 460 | break; 461 | } else { 462 | return Err(err); 463 | } 464 | } 465 | }; 466 | if boxtype == BOX_MOVIE { 467 | // parse nested Boxes 468 | } else if boxtype == BOX_TRACK { 469 | // parse TrackBox 470 | parse_track(&mut reader, size, &mut mp4)?; 471 | } else { 472 | reader.seek(SeekFrom::Current(size as i64))?; 473 | } 474 | } 475 | Ok(mp4) 476 | } 477 | -------------------------------------------------------------------------------- /src/obu.rs: -------------------------------------------------------------------------------- 1 | // 2 | // https://aomedia.org/av1-bitstream-and-decoding-process-specification/ 3 | // 4 | use crate::av1; 5 | use crate::bitio::BitReader; 6 | use std::cmp; 7 | use std::fmt; 8 | use std::io; 9 | 10 | pub const OBU_SEQUENCE_HEADER: u8 = 1; 11 | pub const OBU_TEMPORAL_DELIMITER: u8 = 2; 12 | pub const OBU_FRAME_HEADER: u8 = 3; 13 | pub const OBU_TILE_GROUP: u8 = 4; 14 | pub const OBU_METADATA: u8 = 5; 15 | pub const OBU_FRAME: u8 = 6; 16 | pub const OBU_REDUNDANT_FRAME_HEADER: u8 = 7; 17 | pub const OBU_TILE_LIST: u8 = 8; 18 | pub const OBU_PADDING: u8 = 15; 19 | 20 | use crate::av1::{ 21 | ALTREF2_FRAME, ALTREF_FRAME, BWDREF_FRAME, GOLDEN_FRAME, INTRA_FRAME, LAST2_FRAME, LAST3_FRAME, 22 | LAST_FRAME, 23 | }; 24 | 25 | const REFS_PER_FRAME: usize = 7; // Number of reference frames that can be used for inter prediction 26 | const TOTAL_REFS_PER_FRAME: usize = 8; // Number of reference frame types (including intra type) 27 | const MAX_TILE_WIDTH: u32 = 4096; // Maximum width of a tile in units of luma samples 28 | const MAX_TILE_AREA: u32 = 4096 * 2304; // Maximum area of a tile in units of luma samples 29 | const MAX_TILE_ROWS: u32 = 64; // Maximum number of tile rows 30 | const MAX_TILE_COLS: u32 = 64; // Maximum number of tile columns 31 | pub const NUM_REF_FRAMES: usize = 8; // Number of frames that can be stored for future reference 32 | const MAX_SEGMENTS: usize = 8; // Number of segments allowed in segmentation map 33 | const SEG_LVL_MAX: usize = 8; // Number of segment features 34 | const SELECT_SCREEN_CONTENT_TOOLS: u8 = 2; // Value that indicates the allow_screen_content_tools syntax element is coded 35 | const SELECT_INTEGER_MV: u8 = 2; // Value that indicates the force_integer_mv syntax element is coded 36 | const RESTORATION_TILESIZE_MAX: usize = 256; // Maximum size of a loop restoration tile 37 | const PRIMARY_REF_NONE: u8 = 7; // Value of primary_ref_frame indicating that there is no primary reference frame 38 | const SUPERRES_NUM: usize = 8; // Numerator for upscaling ratio 39 | const SUPERRES_DENOM_MIN: usize = 9; // Smallest denominator for upscaling ratio 40 | const SUPERRS_DENOM_BITS: usize = 3; // Number of bits sent to specify denominator of upscaling ratio 41 | const MAX_LOOP_FILTER: i32 = 63; // Maximum value used for loop filtering 42 | const WARPEDMODEL_PREC_BITS: usize = 16; // Internal precision of warped motion models 43 | const GM_ABS_TRANS_BITS: usize = 12; // Number of bits encoded for translational components of global motion models, if part of a ROTZOOM or AFFINE model 44 | const GM_ABS_TRANS_ONLY_BITS: usize = 9; // Number of bits encoded for translational components of global motion models, if part of a TRANSLATION model 45 | const GM_ABS_ALPHA_BITS: usize = 12; // Number of bits encoded for non-translational components of global motion models 46 | const GM_ALPHA_PREC_BITS: usize = 15; // Number of fractional bits for sending non-translational warp model coefacients 47 | const GM_TRANS_PREC_BITS: usize = 6; // Number of fractional bits for sending translational warp model coefacients 48 | const GM_TRANS_ONLY_PREC_BITS: usize = 3; // Number of fractional bits used for pure translational warps 49 | 50 | // Color primaries 51 | const CP_BT_709: u8 = 1; // BT.709 52 | const CP_UNSPECIFIED: u8 = 2; // Unspecified 53 | 54 | // Transfer characteristics 55 | const TC_UNSPECIFIED: u8 = 2; // Unspecified 56 | const TC_SRGB: u8 = 13; // sRGB or sYCC 57 | 58 | // Matrix coefacients 59 | const MC_IDENTITY: u8 = 0; // Identity matrix 60 | const MC_UNSPECIFIED: u8 = 2; // Unspecified 61 | 62 | // Chroma sample position 63 | const CSP_UNKNOWN: u8 = 0; // Unknown (in this case the source video transfer function must be signaled outside the AV1 bitstream) 64 | 65 | // Frame type 66 | pub const KEY_FRAME: u8 = 0; 67 | pub const INTER_FRAME: u8 = 1; 68 | pub const INTRA_ONLY_FRAME: u8 = 2; 69 | pub const SWITCH_FRAME: u8 = 3; 70 | 71 | // interpolation_filter 72 | const SWITCHABLE: u8 = 4; 73 | 74 | // Loop restoration type (FrameRestorationType, not lr_type) 75 | const RESTORE_NONE: u8 = 0; 76 | const RESTORE_SWITCHABLE: u8 = 3; 77 | const RESTORE_WIENER: u8 = 1; 78 | const RESTORE_SGRPROJ: u8 = 2; 79 | 80 | // TxMode 81 | const ONLY_4X4: u8 = 0; 82 | const TX_MODE_LARGEST: u8 = 1; 83 | const TX_MODE_SELECT: u8 = 2; 84 | 85 | const IDENTITY: u8 = 0; // Warp model is just an identity transform 86 | const TRANSLATION: u8 = 1; // Warp model is a pure translation 87 | const ROTZOOM: u8 = 2; // Warp model is a rotation + symmetric zoom + translation 88 | const AFFINE: u8 = 3; // Warp model is a general afane transform 89 | 90 | // OBU Metadata Type 91 | const METADATA_TYPE_HDR_CLL: u32 = 1; 92 | const METADATA_TYPE_HDR_MDCV: u32 = 2; 93 | const METADATA_TYPE_SCALABILITY: u32 = 3; 94 | const METADATA_TYPE_ITUT_T35: u32 = 4; 95 | const METADATA_TYPE_TIMECODE: u32 = 5; 96 | 97 | // scalability_mode_idc 98 | const SCALABILITY_SS: u8 = 14; 99 | 100 | /// 101 | /// OBU(Open Bitstream Unit) 102 | /// 103 | #[derive(Debug)] 104 | pub struct Obu { 105 | // obu_header() 106 | pub obu_type: u8, // f(4) 107 | pub obu_extension_flag: bool, // f(1) 108 | pub obu_has_size_field: bool, // f(1) 109 | // obu_extension_header() 110 | pub temporal_id: u8, // f(3) 111 | pub spatial_id: u8, // f(2) 112 | // open_bitstream_unit() 113 | pub obu_size: u32, // leb128() 114 | pub header_len: u32, 115 | } 116 | 117 | impl fmt::Display for Obu { 118 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 119 | let obu_type = match self.obu_type { 120 | OBU_SEQUENCE_HEADER => "SEQUENCE_HEADER".to_owned(), 121 | OBU_TEMPORAL_DELIMITER => "TEMPORAL_DELIMITER".to_owned(), 122 | OBU_FRAME_HEADER => "FRAME_HEADER".to_owned(), 123 | OBU_TILE_GROUP => "TILE_GROUP".to_owned(), 124 | OBU_FRAME => "FRAME".to_owned(), 125 | OBU_METADATA => "METADATA".to_owned(), 126 | OBU_REDUNDANT_FRAME_HEADER => "REDUNDANT_FRAME_HEADER".to_owned(), 127 | OBU_TILE_LIST => "TILE_LIST".to_owned(), 128 | OBU_PADDING => "PADDING".to_owned(), 129 | _ => format!("Reserved({})", self.obu_type), // Reserved 130 | }; 131 | if self.obu_extension_flag { 132 | write!( 133 | f, 134 | "{} T{}S{} size={}+{}", 135 | obu_type, self.temporal_id, self.spatial_id, self.header_len, self.obu_size 136 | ) 137 | } else { 138 | // Base layer (temporal_id == 0 && spatial_id == 0) 139 | write!(f, "{} size={}+{}", obu_type, self.header_len, self.obu_size) 140 | } 141 | } 142 | } 143 | 144 | // Color config 145 | #[derive(Clone, Copy, Debug, Default)] 146 | pub struct ColorConfig { 147 | pub bit_depth: u8, // BitDepth 148 | pub num_planes: u8, // NumPlanes 149 | // color_config() 150 | pub mono_chrome: bool, // f(1) 151 | pub color_primaries: u8, // f(8) 152 | pub transfer_characteristics: u8, // f(8) 153 | pub matrix_coefficients: u8, // f(8) 154 | pub color_range: bool, // f(1) 155 | pub subsampling_x: u8, // f(1) 156 | pub subsampling_y: u8, // f(1) 157 | pub chroma_sample_position: u8, // f(2) 158 | pub separate_uv_delta_q: bool, // f(1) 159 | } 160 | 161 | /// Timing info 162 | #[derive(Clone, Copy, Debug, Default)] 163 | pub struct TimingInfo { 164 | // timing_info() 165 | pub num_units_in_display_tick: u32, // f(32) 166 | pub time_scale: u32, // f(32) 167 | pub equal_picture_interval: bool, // f(1) 168 | pub num_ticks_per_picture: u32, // uvlc() 169 | } 170 | 171 | /// 172 | /// operating point in Sequence Header OBU 173 | /// 174 | #[derive(Clone, Copy, Debug, Default)] 175 | pub struct OperatingPoint { 176 | pub operating_point_idc: u16, // f(12) 177 | pub seq_level_idx: u8, // f(5) 178 | pub seq_tier: u8, // f(1) 179 | } 180 | 181 | /// 182 | /// Sequence header OBU 183 | /// 184 | #[derive(Clone, Copy, Debug, Default)] 185 | pub struct SequenceHeader { 186 | pub seq_profile: u8, // f(3) 187 | pub still_picture: bool, // f(1) 188 | pub reduced_still_picture_header: bool, // f(1) 189 | pub timing_info_present_flag: bool, // f(1) 190 | pub timing_info: TimingInfo, // timing_info() 191 | pub decoder_model_info_present_flag: bool, // f(1) 192 | pub initial_display_delay_present_flag: bool, // f(1) 193 | pub operating_points_cnt: u8, // f(5) 194 | pub op: [OperatingPoint; 1], // OperatingPoint 195 | pub frame_width_bits: u8, // f(4) 196 | pub frame_height_bits: u8, // f(4) 197 | pub max_frame_width: u32, // f(n) 198 | pub max_frame_height: u32, // f(n) 199 | pub frame_id_numbers_present_flag: bool, // f(1) 200 | pub delta_frame_id_length: u8, // f(4) 201 | pub additional_frame_id_length: u8, // f(3) 202 | pub use_128x128_superblock: bool, // f(1) 203 | pub enable_filter_intra: bool, // f(1) 204 | pub enable_intra_edge_filter: bool, // f(1) 205 | pub enable_interintra_compound: bool, // f(1) 206 | pub enable_masked_compound: bool, // f(1) 207 | pub enable_warped_motion: bool, // f(1) 208 | pub enable_dual_filter: bool, // f(1) 209 | pub enable_order_hint: bool, // f(1) 210 | pub enable_jnt_comp: bool, // f(1) 211 | pub enable_ref_frame_mvs: bool, // f(1) 212 | pub seq_force_screen_content_tools: u8, // f(1) 213 | pub seq_force_integer_mv: u8, // f(1) 214 | pub order_hint_bits: u8, // f(3) 215 | pub enable_superres: bool, // f(1) 216 | pub enable_cdef: bool, // f(1) 217 | pub enable_restoration: bool, // f(1) 218 | pub color_config: ColorConfig, // color_config() 219 | pub film_grain_params_present: bool, // f(1) 220 | } 221 | 222 | /// Frame size 223 | #[derive(Debug, Default)] 224 | pub struct FrameSize { 225 | // frame_size() 226 | pub frame_width: u32, // FrameWidth 227 | pub frame_height: u32, // FrameHeight 228 | // superres_params() 229 | pub use_superres: bool, // f(1) 230 | pub upscaled_width: u32, // UpscaledWidth 231 | } 232 | 233 | /// Render size 234 | #[derive(Debug, Default)] 235 | pub struct RenderSize { 236 | // render_size() 237 | pub render_width: u32, // RenderWidth 238 | pub render_height: u32, // RenderHeight 239 | } 240 | 241 | /// Loop filter params 242 | #[derive(Debug, Default)] 243 | pub struct LoopFilterParams { 244 | // loop_filter_params() 245 | pub loop_filter_level: [u8; 4], // f(6) 246 | pub loop_filter_sharpness: u8, // f(3) 247 | pub loop_filter_delta_enabled: bool, // f(1) 248 | pub loop_filter_ref_deltas: [i32; TOTAL_REFS_PER_FRAME], // su(1+6) 249 | pub loop_filter_mode_deltas: [i32; 2], // su(1+6) 250 | } 251 | 252 | /// Tile info 253 | #[derive(Debug, Default, Clone, Copy)] 254 | pub struct TileInfo { 255 | pub tile_cols: u16, // TileCols 256 | pub tile_rows: u16, // TileRows 257 | // tile_info() 258 | pub context_update_tile_id: u32, // f(TileRowsLog2+TileColsLog2) 259 | pub tile_size_bytes: usize, // TileSizeBytes 260 | } 261 | 262 | /// Quantization params 263 | #[derive(Debug, Default)] 264 | pub struct QuantizationParams { 265 | pub deltaq_y_dc: i32, // DeltaQYDc 266 | pub deltaq_u_dc: i32, // DeltaQUDc 267 | pub deltaq_u_ac: i32, // DeltaQUAc 268 | pub deltaq_v_dc: i32, // DeltaQVDc 269 | pub deltaq_v_ac: i32, // DeltaQVAc 270 | // quantization_params() 271 | pub base_q_idx: u8, // f(8) 272 | pub using_qmatrix: bool, // f(1) 273 | pub qm_y: u8, // f(4) 274 | pub qm_u: u8, // f(4) 275 | pub qm_v: u8, // f(4) 276 | } 277 | 278 | /// Segmentation params 279 | #[derive(Debug, Default)] 280 | pub struct SegmentationParams { 281 | // segmentation_params() 282 | pub segmentation_enabled: bool, // f(1) 283 | pub segmentation_update_map: bool, // f(1) 284 | pub segmentation_temporal_update: bool, // f(1) 285 | pub segmentation_update_data: bool, // f(1) 286 | } 287 | 288 | /// Quantizer index delta parameters 289 | #[derive(Debug, Default)] 290 | pub struct DeltaQParams { 291 | // delta_q_params() 292 | pub delta_q_present: bool, // f(1) 293 | pub delta_q_res: u8, // f(2) 294 | } 295 | 296 | /// Loop filter delta parameters 297 | #[derive(Debug, Default)] 298 | pub struct DeltaLfParams { 299 | // delta_lf_params() 300 | pub delta_lf_present: bool, // f(1) 301 | pub delta_lf_res: u8, // f(2) 302 | pub delta_lf_multi: bool, // f(1) 303 | } 304 | 305 | /// CDEF params 306 | #[derive(Debug, Default)] 307 | pub struct CdefParams { 308 | // cdef_params() 309 | pub cdef_damping: u8, // f(2) 310 | pub cdef_bits: u8, // f(2) 311 | pub cdef_y_pri_strength: [u8; 8], // f(4) 312 | pub cdef_y_sec_strength: [u8; 8], // f(2) 313 | pub cdef_uv_pri_strength: [u8; 8], // f(4) 314 | pub cdef_uv_sec_strength: [u8; 8], // f(2) 315 | } 316 | 317 | /// Loop restoration params 318 | #[derive(Debug, Default)] 319 | pub struct LrParams { 320 | pub uses_lr: bool, // UsesLr 321 | pub frame_restoration_type: [u8; 3], // FrameRestorationType[] 322 | pub loop_restoration_size: [u8; 3], // LoopRestorationSize[] 323 | } 324 | 325 | /// Skip mode params 326 | #[derive(Debug, Default)] 327 | pub struct SkipModeParams { 328 | pub skip_mode_frame: [u8; 2], // SkipModeFrame[] 329 | // skip_mode_params() 330 | pub skip_mode_present: bool, // f(1) 331 | } 332 | 333 | /// Global motion params 334 | #[derive(Debug, Default)] 335 | pub struct GlobalMotionParams { 336 | pub gm_type: [u8; NUM_REF_FRAMES], // GmType[] 337 | pub gm_params: [[i32; 6]; NUM_REF_FRAMES], // gm_params[] 338 | pub prev_gm_params: [[i32; 6]; NUM_REF_FRAMES], // PrevGmParams[][] 339 | } 340 | 341 | /// 342 | /// Frame header OBU 343 | /// 344 | #[derive(Debug, Default)] 345 | pub struct FrameHeader { 346 | // uncompressed_header() 347 | pub show_existing_frame: bool, // f(1) 348 | pub frame_to_show_map_idx: u8, // f(3) 349 | pub display_frame_id: u16, // f(idLen) 350 | pub frame_type: u8, // f(2) 351 | pub frame_is_intra: bool, // FrameIsIntra 352 | pub show_frame: bool, // f(1) 353 | pub showable_frame: bool, // f(1) 354 | pub error_resilient_mode: bool, // f(1) 355 | pub disable_cdf_update: bool, // f(1) 356 | pub allow_screen_content_tools: bool, // f(1) 357 | pub force_integer_mv: bool, // f(1) 358 | pub current_frame_id: u16, // f(idLen) 359 | pub frame_size_override_flag: bool, // f(1) 360 | pub order_hint: u8, // f(OrderHintBits) 361 | pub primary_ref_frame: u8, // f(3) 362 | pub refresh_frame_flags: u8, // f(8) 363 | pub ref_order_hint: [u8; NUM_REF_FRAMES], // f(OrderHintBits) 364 | pub frame_size: FrameSize, // frame_size() 365 | pub render_size: RenderSize, // render_size() 366 | pub allow_intrabc: bool, // f(1) 367 | pub last_frame_idx: u8, // f(3) 368 | pub gold_frame_idx: u8, // f(3) 369 | pub ref_frame_idx: [u8; NUM_REF_FRAMES], // f(3) 370 | pub allow_high_precision_mv: bool, // f(1) 371 | pub interpolation_filter: u8, // f(2) 372 | pub is_motion_mode_switchable: bool, // f(1) 373 | pub use_ref_frame_mvs: bool, // f(1) 374 | pub disable_frame_end_update_cdf: bool, // f(1) 375 | pub order_hints: [u8; NUM_REF_FRAMES], // OrderHints 376 | pub tile_info: TileInfo, // tile_info() 377 | pub quantization_params: QuantizationParams, // quantization_params() 378 | pub segmentation_params: SegmentationParams, // segmentation_params() 379 | pub delta_q_params: DeltaQParams, // delta_q_params() 380 | pub delta_lf_params: DeltaLfParams, // delta_lf_params() 381 | pub coded_lossless: bool, // CodedLossless 382 | pub all_lossless: bool, // AllLossless 383 | pub loop_filter_params: LoopFilterParams, // loop_filter_params() 384 | pub cdef_params: CdefParams, // cdef_params() 385 | pub lr_params: LrParams, // lr_params() 386 | pub tx_mode: u8, // TxMode 387 | pub skip_mode_params: SkipModeParams, // skip_mode_params() 388 | pub global_motion_params: GlobalMotionParams, // global_motion_params() 389 | pub film_grain_params: FilmGrainParams, // film_grain_params() 390 | pub reference_select: bool, // f(1) 391 | pub allow_warped_motion: bool, // f(1) 392 | pub reduced_tx_set: bool, // f(1) 393 | } 394 | 395 | /// 396 | /// Tile list OBU 397 | /// 398 | #[derive(Debug, Default)] 399 | pub struct TileList { 400 | pub output_frame_width_in_tiles_minus_1: u8, // f(8) 401 | pub output_frame_height_in_tiles_minus_1: u8, // f(8) 402 | pub tile_count_minus_1: u16, // f(16) 403 | pub tile_list_entries: Vec, // tile_list_entry() 404 | } 405 | 406 | /// Tile list entry parameters 407 | #[derive(Debug, Default)] 408 | pub struct TileListEntry { 409 | pub anchor_frame_idx: u8, // f(8) 410 | pub anchor_tile_row: u8, // f(8) 411 | pub anchor_tile_col: u8, // f(8) 412 | pub tile_data_size_minus_1: u16, // f(16) 413 | } 414 | 415 | /// Film grain synthesis parameters 416 | #[derive(Debug, Default)] 417 | pub struct FilmGrainParams { 418 | pub apply_grain: bool, // f(1) 419 | pub grain_seed: u16, // f(16) 420 | pub update_grain: bool, // f(1) 421 | pub film_grain_params_ref_idx: u8, // f(3) 422 | pub num_y_points: u8, // f(4) 423 | pub point_y_value: Vec, // f(8) 424 | pub point_y_scaling: Vec, // f(8) 425 | pub chroma_scaling_from_luma: bool, // f(1) 426 | pub num_cb_points: u8, // f(4) 427 | pub point_cb_value: Vec, // f(8) 428 | pub point_cb_scaling: Vec, // f(8) 429 | pub num_cr_points: u8, // f(4) 430 | pub point_cr_value: Vec, // f(8) 431 | pub point_cr_scaling: Vec, // f(8) 432 | pub grain_scaling_minus_8: u8, // f(2) 433 | pub ar_coeff_lag: u8, // f(2) 434 | pub ar_coeffs_y_plus_128: Vec, // f(8) 435 | pub ar_coeffs_cb_plus_128: Vec, // f(8) 436 | pub ar_coeffs_cr_plus_128: Vec, // f(8) 437 | pub ar_coeff_shift_minus_6: u8, // f(2) 438 | pub grain_scale_shift: u8, // f(2) 439 | pub cb_mult: u8, // f(8) 440 | pub cb_luma_mult: u8, // f(8) 441 | pub cb_offset: u16, // f(9) 442 | pub cr_mult: u8, // f(8) 443 | pub cr_luma_mult: u8, // f(8) 444 | pub cr_offset: u16, // f(9) 445 | pub overlap_flag: bool, // f(1) 446 | pub clip_to_restricted_range: bool, // f(1) 447 | } 448 | 449 | #[derive(Debug, Default)] 450 | pub struct ScalabilityStructure { 451 | pub spatial_layers_cnt_minus_1: u8, // f(2) 452 | pub spatial_layer_dimensions_present_flag: bool, // f(1) 453 | pub spatial_layer_description_present_flag: bool, // f(1) 454 | pub temporal_group_description_present_flag: bool, // f(1) 455 | pub scalability_structure_reserved_3bits: u8, // f(3) 456 | pub spatial_layer_max_width: Vec, // f(16) 457 | pub spatial_layer_max_height: Vec, // f(16) 458 | pub spatial_layer_ref_id: Vec, // f(8) 459 | pub temporal_group_size: u8, // f(8) 460 | pub temporal_group_temporal_id: Vec, // f(3) 461 | pub temporal_group_temporal_switching_up_point_flag: Vec, // f(1) 462 | pub temporal_group_spatial_switching_up_point_flag: Vec, // f(1) 463 | pub temporal_group_ref_cnt: Vec, // f(3) 464 | pub temporal_group_ref_pic_diff: Vec>, // f(8) 465 | } 466 | 467 | // Metadata OBU structs 468 | #[derive(Debug)] 469 | pub enum MetadataObu { 470 | HdrCll(HdrCllMetadata), 471 | HdrMdcv(HdrMdcvMetadata), 472 | Scalability(ScalabilityMetadata), 473 | ItutT35(ItutT35Metadata), 474 | Timecode(TimecodeMetadata), 475 | } 476 | 477 | #[derive(Debug, Default)] 478 | pub struct HdrCllMetadata { 479 | pub max_cll: u16, // f(16) 480 | pub max_fall: u16, // f(16) 481 | } 482 | 483 | #[derive(Debug, Default)] 484 | pub struct HdrMdcvMetadata { 485 | pub primary_chromaticity_x: [u16; 3], 486 | pub primary_chromaticity_y: [u16; 3], 487 | pub white_point_chromaticity_x: u16, // f(16) 488 | pub white_point_chromaticity_y: u16, // f(16) 489 | pub luminance_max: u32, // f(32) 490 | pub luminance_min: u32, // f(32) 491 | } 492 | 493 | #[derive(Debug, Default)] 494 | pub struct ScalabilityMetadata { 495 | pub scalability_mode_idc: u8, // f(8) 496 | pub scalability_structure: Option, // scalability_structure() 497 | } 498 | 499 | #[derive(Debug, Default)] 500 | pub struct ItutT35Metadata { 501 | pub itu_t_t35_country_code: u8, // f(8) 502 | pub itu_t_t35_country_code_extension_byte: Option, // f(8) 503 | pub itu_t_t35_payload_bytes: Vec, 504 | } 505 | 506 | #[derive(Debug, Default)] 507 | pub struct TimecodeMetadata { 508 | pub counting_type: u8, // f(5) 509 | pub full_timestamp_flag: bool, // f(1) 510 | pub discontinuity_flag: bool, // f(1) 511 | pub cnt_dropped_flag: bool, // f(1) 512 | pub n_frames: u16, // f(9) 513 | pub seconds_value: u8, // f(6) 514 | pub minutes_value: u8, // f(6) 515 | pub hours_value: u8, // f(5) 516 | pub seconds_flag: bool, // f(1) 517 | pub minutes_flag: bool, // f(1) 518 | pub hours_flag: bool, // f(1) 519 | pub time_offset_length: u8, // f(5) 520 | pub time_offset_value: u32, // f(time_offset_length), 5 bits <= 31 521 | } 522 | 523 | /// return (MiCols, MiRows) 524 | fn compute_image_size(fs: &FrameSize) -> (u32, u32) { 525 | ( 526 | 2 * ((fs.frame_width + 7) >> 3), // MiCol 527 | 2 * ((fs.frame_height + 7) >> 3), // MiRows 528 | ) 529 | } 530 | 531 | /// return (Leb128Bytes, leb128()) 532 | fn leb128(bs: &mut R) -> io::Result<(u32, u32)> { 533 | let mut value: u64 = 0; 534 | let mut leb128bytes = 0; 535 | for i in 0..8 { 536 | let mut leb128_byte = [0; 1]; 537 | bs.read_exact(&mut leb128_byte)?; // f(8) 538 | let leb128_byte = leb128_byte[0]; 539 | value |= ((leb128_byte & 0x7f) as u64) << (i * 7); 540 | leb128bytes += 1; 541 | if (leb128_byte & 0x80) != 0x80 { 542 | break; 543 | } 544 | } 545 | assert!(value < (1u64 << 32)); 546 | Ok((leb128bytes, value as u32)) 547 | } 548 | 549 | /// 550 | /// parse trailing_bits() 551 | /// 552 | fn trailing_bits(br: &mut BitReader) -> Option<()> { 553 | let trailing_one_bit = br.f::(1)?; 554 | if trailing_one_bit != 1 { 555 | return None; 556 | } 557 | while let Some(trailing_zero_bit) = br.f::(1) { 558 | if trailing_zero_bit != 0 { 559 | return None; 560 | } 561 | } 562 | Some(()) 563 | } 564 | 565 | /// 566 | /// parse color_config() 567 | /// 568 | fn parse_color_config( 569 | br: &mut BitReader, 570 | sh: &SequenceHeader, 571 | ) -> Option { 572 | let mut cc = ColorConfig::default(); 573 | 574 | let high_bitdepth = br.f::(1)?; // f(1) 575 | if sh.seq_profile == 2 && high_bitdepth { 576 | let twelve_bit = br.f::(1)?; // f(1) 577 | cc.bit_depth = if twelve_bit { 12 } else { 10 } 578 | } else if sh.seq_profile <= 2 { 579 | cc.bit_depth = if high_bitdepth { 10 } else { 8 } 580 | } 581 | if sh.seq_profile == 1 { 582 | cc.mono_chrome = false; 583 | } else { 584 | cc.mono_chrome = br.f::(1)?; // f(1) 585 | } 586 | cc.num_planes = if cc.mono_chrome { 1 } else { 3 }; 587 | let color_description_present_flag = br.f::(1)?; // f(1) 588 | if color_description_present_flag { 589 | cc.color_primaries = br.f::(8)?; // f(8) 590 | cc.transfer_characteristics = br.f::(8)?; // f(8) 591 | cc.matrix_coefficients = br.f::(8)?; // f(8) 592 | } else { 593 | cc.color_primaries = CP_UNSPECIFIED; 594 | cc.transfer_characteristics = TC_UNSPECIFIED; 595 | cc.matrix_coefficients = MC_UNSPECIFIED; 596 | } 597 | if cc.mono_chrome { 598 | cc.color_range = br.f::(1)?; // f(1) 599 | cc.subsampling_x = 1; 600 | cc.subsampling_y = 1; 601 | cc.chroma_sample_position = CSP_UNKNOWN; 602 | cc.separate_uv_delta_q = false; 603 | return Some(cc); 604 | } else if cc.color_primaries == CP_BT_709 605 | && cc.transfer_characteristics == TC_SRGB 606 | && cc.matrix_coefficients == MC_IDENTITY 607 | { 608 | cc.color_range = true; 609 | cc.subsampling_x = 0; 610 | cc.subsampling_y = 0; 611 | return Some(cc); 612 | } else { 613 | cc.color_range = br.f::(1)?; // f(1) 614 | if sh.seq_profile == 0 { 615 | cc.subsampling_x = 1; 616 | cc.subsampling_y = 1; 617 | } else if sh.seq_profile == 1 { 618 | cc.subsampling_x = 0; 619 | cc.subsampling_y = 0; 620 | } else { 621 | if cc.bit_depth == 12 { 622 | cc.subsampling_x = br.f::(1)?; // f(1) 623 | if cc.subsampling_x != 0 { 624 | cc.subsampling_y = br.f::(1)?; // f(1) 625 | } else { 626 | cc.subsampling_y = 0; 627 | } 628 | } else { 629 | cc.subsampling_x = 1; 630 | cc.subsampling_y = 0; 631 | } 632 | } 633 | if cc.subsampling_x != 0 && cc.subsampling_y != 0 { 634 | cc.chroma_sample_position = br.f::(2)?; // f(2) 635 | } 636 | } 637 | cc.separate_uv_delta_q = br.f::(1)?; // f(1) 638 | 639 | Some(cc) 640 | } 641 | 642 | /// 643 | /// parse timing_info() 644 | /// 645 | fn parse_timing_info(br: &mut BitReader) -> Option { 646 | let mut ti = TimingInfo::default(); 647 | 648 | ti.num_units_in_display_tick = br.f::(32)?; // f(32) 649 | ti.time_scale = br.f::(32)?; // f(32) 650 | ti.equal_picture_interval = br.f::(1)?; // f(1) 651 | if ti.equal_picture_interval { 652 | ti.num_ticks_per_picture = 0 + 1; // uvlc() 653 | unimplemented!("uvlc() for num_ticks_per_picture_minus_1"); 654 | } 655 | 656 | Some(ti) 657 | } 658 | 659 | /// 660 | /// parse frame_size() (include superres_params()) 661 | /// 662 | fn parse_frame_size( 663 | br: &mut BitReader, 664 | sh: &SequenceHeader, 665 | fh: &FrameHeader, 666 | ) -> Option { 667 | let mut fs = FrameSize::default(); 668 | 669 | // frame_size() 670 | if fh.frame_size_override_flag { 671 | fs.frame_width = br.f::(sh.frame_width_bits as usize)? + 1; // f(n) 672 | fs.frame_height = br.f::(sh.frame_height_bits as usize)? + 1; // f(n) 673 | } else { 674 | fs.frame_width = sh.max_frame_width; 675 | fs.frame_height = sh.max_frame_height; 676 | } 677 | // superres_params() 678 | if sh.enable_superres { 679 | fs.use_superres = br.f::(1)?; // f(1) 680 | } else { 681 | fs.use_superres = false; 682 | } 683 | let supreres_denom; 684 | if fs.use_superres { 685 | let coded_denom = br.f::(SUPERRS_DENOM_BITS)?; // f(SUPERRES_DENOM_BITS) 686 | supreres_denom = coded_denom + SUPERRES_DENOM_MIN; 687 | } else { 688 | supreres_denom = SUPERRES_NUM; 689 | } 690 | fs.upscaled_width = fs.frame_width; 691 | fs.frame_width = ((fs.upscaled_width as usize * SUPERRES_NUM + (supreres_denom / 2)) 692 | / supreres_denom) as u32; 693 | // compute_image_size() 694 | 695 | Some(fs) 696 | } 697 | 698 | /// 699 | /// parse render_size() 700 | /// 701 | fn parse_render_size(br: &mut BitReader, fs: &FrameSize) -> Option { 702 | let mut rs = RenderSize::default(); 703 | 704 | let render_and_frame_size_different = br.f::(1)?; // f(1) 705 | if render_and_frame_size_different { 706 | rs.render_width = br.f::(16)? + 1; // f(16) 707 | rs.render_height = br.f::(16)? + 1; // f(16) 708 | } else { 709 | rs.render_width = fs.upscaled_width; 710 | rs.render_height = fs.frame_height; 711 | } 712 | 713 | Some(rs) 714 | } 715 | 716 | /// read_interpolation_filter() 717 | fn read_interpolation_filter(br: &mut BitReader) -> Option { 718 | let is_filter_switchable = br.f::(1)?; // f(1) 719 | let interpolation_filter; 720 | if is_filter_switchable { 721 | interpolation_filter = SWITCHABLE; 722 | } else { 723 | interpolation_filter = br.f::(2)?; // f(2) 724 | } 725 | 726 | Some(interpolation_filter) 727 | } 728 | 729 | /// 730 | /// parse loop_filter_params() 731 | /// 732 | fn parse_loop_filter_params( 733 | br: &mut BitReader, 734 | cc: &ColorConfig, 735 | fh: &FrameHeader, 736 | ) -> Option { 737 | let mut lfp = LoopFilterParams::default(); 738 | 739 | if fh.coded_lossless || fh.allow_intrabc { 740 | lfp.loop_filter_level[0] = 0; 741 | lfp.loop_filter_level[1] = 0; 742 | lfp.loop_filter_ref_deltas[INTRA_FRAME] = 1; 743 | lfp.loop_filter_ref_deltas[LAST_FRAME] = 0; 744 | lfp.loop_filter_ref_deltas[LAST2_FRAME] = 0; 745 | lfp.loop_filter_ref_deltas[LAST3_FRAME] = 0; 746 | lfp.loop_filter_ref_deltas[BWDREF_FRAME] = 0; 747 | lfp.loop_filter_ref_deltas[GOLDEN_FRAME] = -1; 748 | lfp.loop_filter_ref_deltas[ALTREF_FRAME] = -1; 749 | lfp.loop_filter_ref_deltas[ALTREF2_FRAME] = -1; 750 | for i in 0..2 { 751 | lfp.loop_filter_mode_deltas[i] = 0; 752 | } 753 | return Some(lfp); 754 | } 755 | lfp.loop_filter_level[0] = br.f::(6)?; // f(6) 756 | lfp.loop_filter_level[1] = br.f::(6)?; // f(6) 757 | if cc.num_planes > 1 { 758 | if lfp.loop_filter_level[0] != 0 || lfp.loop_filter_level[1] != 0 { 759 | lfp.loop_filter_level[2] = br.f::(6)?; // f(6) 760 | lfp.loop_filter_level[3] = br.f::(6)?; // f(6) 761 | } 762 | } 763 | lfp.loop_filter_sharpness = br.f::(3)?; // f(3) 764 | lfp.loop_filter_delta_enabled = br.f::(1)?; // f(1) 765 | if lfp.loop_filter_delta_enabled { 766 | let loop_filter_delta_update = br.f::(1)?; // f(1) 767 | if loop_filter_delta_update { 768 | for i in 0..TOTAL_REFS_PER_FRAME { 769 | let update_ref_delta = br.f::(1)?; // f(1) 770 | if update_ref_delta { 771 | lfp.loop_filter_ref_deltas[i] = br.su(1 + 6)?; // su(1+6) 772 | } 773 | } 774 | for i in 0..2 { 775 | let update_mode_delta = br.f::(1)?; // f(1) 776 | if update_mode_delta { 777 | lfp.loop_filter_mode_deltas[i] = br.su(1 + 6)?; // su(1+6) 778 | } 779 | } 780 | } 781 | } 782 | 783 | Some(lfp) 784 | } 785 | 786 | /// 787 | /// parse tile_info() 788 | /// 789 | fn parse_tile_info( 790 | br: &mut BitReader, 791 | sh: &SequenceHeader, 792 | fs: &FrameSize, 793 | ) -> Option { 794 | let mut ti = TileInfo::default(); 795 | 796 | // tile_log2: Tile size calculation function 797 | let tile_log2 = |blk_size, target| { 798 | let mut k = 0; 799 | while (blk_size << k) < target { 800 | k += 1; 801 | } 802 | k 803 | }; 804 | 805 | let (mi_cols, mi_rows) = compute_image_size(fs); 806 | let sb_cols = if sh.use_128x128_superblock { 807 | (mi_cols + 31) >> 5 808 | } else { 809 | (mi_cols + 15) >> 4 810 | }; 811 | let sb_rows = if sh.use_128x128_superblock { 812 | (mi_rows + 31) >> 5 813 | } else { 814 | (mi_rows + 15) >> 4 815 | }; 816 | let sb_shift = if sh.use_128x128_superblock { 5 } else { 4 }; 817 | let sb_size = sb_shift + 2; 818 | let max_tile_width_sb = MAX_TILE_WIDTH >> sb_size; 819 | let max_tile_area_sb = MAX_TILE_AREA >> (2 * sb_size); 820 | let min_log2_tile_cols = tile_log2(max_tile_width_sb, sb_cols); 821 | let max_log2_tile_cols = tile_log2(1, cmp::min(sb_cols, MAX_TILE_COLS)); 822 | let max_log2_tile_rows = tile_log2(1, cmp::min(sb_rows, MAX_TILE_ROWS)); 823 | let min_log2_tiles = cmp::max( 824 | min_log2_tile_cols, 825 | tile_log2(max_tile_area_sb, sb_rows * sb_cols), 826 | ); 827 | 828 | let uniform_tile_spacing_flag = br.f::(1)?; // f(1) 829 | let (mut tile_cols_log2, mut tile_rows_log2): (usize, usize); 830 | if uniform_tile_spacing_flag { 831 | tile_cols_log2 = min_log2_tile_cols; 832 | while tile_cols_log2 < max_log2_tile_cols { 833 | let increment_tile_cols_log2 = br.f::(1)?; // f(1) 834 | if increment_tile_cols_log2 { 835 | tile_cols_log2 += 1; 836 | } else { 837 | break; 838 | } 839 | } 840 | let tile_width_sb = (sb_cols + (1 << tile_cols_log2) - 1) >> tile_cols_log2; 841 | let (mut i, mut start_sb) = (0, 0); 842 | while start_sb < sb_cols { 843 | // MiColStarts[i] = startSb << sbShift 844 | i += 1; 845 | start_sb += tile_width_sb; 846 | } 847 | // MiColStarts[i] = MiCols 848 | ti.tile_cols = i; 849 | 850 | let min_log2_tile_rows = 851 | cmp::max(min_log2_tiles as isize - tile_cols_log2 as isize, 0) as usize; 852 | tile_rows_log2 = min_log2_tile_rows; 853 | while tile_rows_log2 < max_log2_tile_rows { 854 | let increment_tile_rows_log2 = br.f::(1)?; // f(1) 855 | if increment_tile_rows_log2 { 856 | tile_rows_log2 += 1; 857 | } else { 858 | break; 859 | } 860 | } 861 | let tile_height_sb = (sb_rows + (1 << tile_rows_log2) - 1) >> tile_rows_log2; 862 | let (mut i, mut start_sb) = (0, 0); 863 | while start_sb < sb_rows { 864 | // MiRowStarts[i] = startSb << sbShift 865 | i += 1; 866 | start_sb += tile_height_sb; 867 | } 868 | // MiRowStarts[i] = MiRows 869 | ti.tile_rows = i; 870 | } else { 871 | let mut widest_tile_sb = 0; 872 | let (mut i, mut start_sb) = (0, 0); 873 | while start_sb < sb_cols { 874 | // MiColStarts[i] = startSb << sbShift 875 | let max_width = cmp::min(sb_cols - start_sb, max_tile_width_sb); 876 | let width_in_sbs = br.ns(max_width)? + 1; // ns(maxWidth) 877 | let size_sb = width_in_sbs; 878 | widest_tile_sb = cmp::max(size_sb, widest_tile_sb); 879 | start_sb += size_sb; 880 | i += 1; 881 | } 882 | // MiColStarts[i] = MiCols 883 | ti.tile_cols = i; 884 | tile_cols_log2 = tile_log2(1, ti.tile_cols as u32); 885 | 886 | let max_tile_area_sb = if min_log2_tiles > 0 { 887 | (sb_rows * sb_cols) >> (min_log2_tiles + 1) 888 | } else { 889 | sb_rows * sb_cols 890 | }; 891 | let max_tile_height_sb = cmp::max(max_tile_area_sb / widest_tile_sb, 1); 892 | let (mut start_sb, mut i) = (0, 0); 893 | while start_sb < sb_rows { 894 | // MiRowStarts[i] = startSb << sbShift 895 | let max_height = cmp::min(sb_rows - start_sb, max_tile_height_sb); 896 | let height_in_sbs = br.ns(max_height)? + 1; // ns(maxHeight) 897 | let size_sb = height_in_sbs; 898 | start_sb += size_sb; 899 | i += 1; 900 | } 901 | // MiRowStarts[i] = MiRows 902 | ti.tile_rows = i; 903 | tile_rows_log2 = tile_log2(1, ti.tile_rows as u32); 904 | } 905 | if tile_cols_log2 > 0 || tile_rows_log2 > 0 { 906 | ti.context_update_tile_id = br.f::(tile_cols_log2 + tile_rows_log2)?; // f(TileRowsLog2+TileColsLog2) 907 | ti.tile_size_bytes = br.f::(2)? + 1; // f(2) 908 | } else { 909 | ti.context_update_tile_id = 0; 910 | } 911 | 912 | Some(ti) 913 | } 914 | 915 | /// 916 | /// parse quantization_params() 917 | /// 918 | fn parse_quantization_params( 919 | br: &mut BitReader, 920 | cc: &ColorConfig, 921 | ) -> Option { 922 | let mut qp = QuantizationParams::default(); 923 | 924 | qp.base_q_idx = br.f::(8)?; // f(8) 925 | qp.deltaq_y_dc = read_delta_q(br)?; // read_delta_q() 926 | if cc.num_planes > 1 { 927 | let diff_uv_delta; 928 | if cc.separate_uv_delta_q { 929 | diff_uv_delta = br.f::(1)?; // f(1) 930 | } else { 931 | diff_uv_delta = false; 932 | } 933 | qp.deltaq_u_dc = read_delta_q(br)?; // read_delta_q() 934 | qp.deltaq_u_ac = read_delta_q(br)?; // read_delta_q() 935 | if diff_uv_delta { 936 | qp.deltaq_v_dc = read_delta_q(br)?; // read_delta_q() 937 | qp.deltaq_v_ac = read_delta_q(br)?; // read_delta_q() 938 | } else { 939 | qp.deltaq_v_dc = qp.deltaq_u_dc; 940 | qp.deltaq_v_ac = qp.deltaq_u_ac; 941 | } 942 | } else { 943 | qp.deltaq_u_dc = 0; 944 | qp.deltaq_u_ac = 0; 945 | qp.deltaq_v_dc = 0; 946 | qp.deltaq_v_ac = 0; 947 | } 948 | qp.using_qmatrix = br.f::(1)?; // f(1) 949 | if qp.using_qmatrix { 950 | qp.qm_y = br.f::(4)?; // f(4) 951 | qp.qm_u = br.f::(4)?; // f(4) 952 | if !cc.separate_uv_delta_q { 953 | qp.qm_v = qp.qm_u; 954 | } else { 955 | qp.qm_v = br.f::(4)?; // f(4) 956 | } 957 | } 958 | 959 | Some(qp) 960 | } 961 | 962 | /// Delta quantizer 963 | fn read_delta_q(br: &mut BitReader) -> Option { 964 | let delta_coded = br.f::(1)?; // f(1) 965 | let delta_q; 966 | if delta_coded { 967 | delta_q = br.su(1 + 6)?; // su(1+6) 968 | } else { 969 | delta_q = 0; 970 | } 971 | 972 | Some(delta_q as i32) 973 | } 974 | 975 | /// 976 | /// parse segmentation_params() 977 | /// 978 | fn parse_segmentation_params( 979 | br: &mut BitReader, 980 | fh: &FrameHeader, 981 | ) -> Option { 982 | let mut sp = SegmentationParams::default(); 983 | 984 | #[allow(non_upper_case_globals)] 985 | const Segmentation_Feature_Bits: [usize; SEG_LVL_MAX] = [8, 6, 6, 6, 6, 3, 0, 0]; 986 | #[allow(non_upper_case_globals)] 987 | const Segmentation_Feature_Signed: [usize; SEG_LVL_MAX] = [1, 1, 1, 1, 1, 0, 0, 0]; 988 | #[allow(non_upper_case_globals)] 989 | const Segmentation_Feature_Max: [i32; SEG_LVL_MAX] = [ 990 | 255, 991 | MAX_LOOP_FILTER, 992 | MAX_LOOP_FILTER, 993 | MAX_LOOP_FILTER, 994 | MAX_LOOP_FILTER, 995 | 7, 996 | 0, 997 | 0, 998 | ]; 999 | 1000 | sp.segmentation_enabled = br.f::(1)?; // f(1) 1001 | if sp.segmentation_enabled { 1002 | if fh.primary_ref_frame == PRIMARY_REF_NONE { 1003 | sp.segmentation_update_map = true; 1004 | sp.segmentation_temporal_update = false; 1005 | sp.segmentation_update_data = true; 1006 | } else { 1007 | sp.segmentation_update_map = br.f::(1)?; // f(1) 1008 | if sp.segmentation_update_map { 1009 | sp.segmentation_temporal_update = br.f::(1)?; // f(1) 1010 | } 1011 | sp.segmentation_update_data = br.f::(1)?; // f(1) 1012 | } 1013 | if sp.segmentation_update_data { 1014 | for _ in 0..MAX_SEGMENTS { 1015 | for j in 0..SEG_LVL_MAX { 1016 | let feature_value; 1017 | let feature_enabled = br.f::(1)?; // f(1) 1018 | 1019 | // FeatureEnabled[i][j] = feature_enabled 1020 | let mut clipped_value = 0; 1021 | if feature_enabled { 1022 | let bits_to_read = Segmentation_Feature_Bits[j]; 1023 | let limit = Segmentation_Feature_Max[j]; 1024 | if Segmentation_Feature_Signed[j] == 1 { 1025 | feature_value = br.su(1 + bits_to_read)?; // su(1+bitsToRead) 1026 | clipped_value = cmp::max(-limit, cmp::min(limit, feature_value)); 1027 | } else { 1028 | feature_value = br.f::(bits_to_read)? as i32; // f(bitsToRead) 1029 | clipped_value = cmp::max(0, cmp::min(limit, feature_value)); 1030 | } 1031 | } 1032 | let _ = clipped_value; // FeatureData[i][j] = clippedValue 1033 | } 1034 | } 1035 | } 1036 | } else { 1037 | // FeatureEnabled[i][j] = 0 1038 | // FeatureData[i][j] = 0 1039 | } 1040 | // SegIdPreSkip 1041 | // LastActiveSegId 1042 | 1043 | Some(sp) 1044 | } 1045 | 1046 | /// 1047 | /// parse delta_q_params() 1048 | /// 1049 | fn parse_delta_q_params( 1050 | br: &mut BitReader, 1051 | qp: &QuantizationParams, 1052 | ) -> Option { 1053 | let mut dqp = DeltaQParams::default(); 1054 | 1055 | dqp.delta_q_res = 0; 1056 | dqp.delta_q_present = false; 1057 | if qp.base_q_idx > 0 { 1058 | dqp.delta_q_present = br.f::(1)?; // f(1) 1059 | } 1060 | if dqp.delta_q_present { 1061 | dqp.delta_q_res = br.f::(2)?; // f(2) 1062 | } 1063 | 1064 | Some(dqp) 1065 | } 1066 | 1067 | /// 1068 | /// parse delta_lf_params() 1069 | /// 1070 | fn parse_delta_lf_params( 1071 | br: &mut BitReader, 1072 | fh: &FrameHeader, 1073 | ) -> Option { 1074 | let mut dlfp = DeltaLfParams::default(); 1075 | 1076 | dlfp.delta_lf_present = false; 1077 | dlfp.delta_lf_res = 0; 1078 | dlfp.delta_lf_multi = false; 1079 | if fh.delta_q_params.delta_q_present { 1080 | if !fh.allow_intrabc { 1081 | dlfp.delta_lf_present = br.f::(1)?; // f(1) 1082 | } 1083 | if dlfp.delta_lf_present { 1084 | dlfp.delta_lf_res = br.f::(2)?; // f(2) 1085 | dlfp.delta_lf_multi = br.f::(1)?; // f(1) 1086 | } 1087 | } 1088 | 1089 | Some(dlfp) 1090 | } 1091 | 1092 | /// 1093 | /// parse cdef_params() 1094 | /// 1095 | fn parse_cdef_params( 1096 | br: &mut BitReader, 1097 | sh: &SequenceHeader, 1098 | fh: &FrameHeader, 1099 | ) -> Option { 1100 | let mut cdefp = CdefParams::default(); 1101 | 1102 | if fh.coded_lossless || fh.allow_intrabc || !sh.enable_cdef { 1103 | cdefp.cdef_bits = 0; 1104 | cdefp.cdef_y_pri_strength[0] = 0; 1105 | cdefp.cdef_y_sec_strength[0] = 0; 1106 | cdefp.cdef_uv_pri_strength[0] = 0; 1107 | cdefp.cdef_uv_sec_strength[0] = 0; 1108 | cdefp.cdef_damping = 3; 1109 | return Some(cdefp); 1110 | } 1111 | cdefp.cdef_damping = br.f::(2)? + 3; // f(2) 1112 | cdefp.cdef_bits = br.f::(2)?; // f(2) 1113 | for i in 0..(1 << cdefp.cdef_bits) { 1114 | cdefp.cdef_y_pri_strength[i] = br.f::(4)?; // f(4) 1115 | cdefp.cdef_y_sec_strength[i] = br.f::(2)?; // f(2) 1116 | if cdefp.cdef_y_sec_strength[i] == 3 { 1117 | cdefp.cdef_y_sec_strength[i] += 1; 1118 | } 1119 | if sh.color_config.num_planes > 1 { 1120 | cdefp.cdef_uv_pri_strength[i] = br.f::(4)?; // f(4) 1121 | cdefp.cdef_uv_sec_strength[i] = br.f::(2)?; // f(2) 1122 | if cdefp.cdef_uv_sec_strength[i] == 3 { 1123 | cdefp.cdef_uv_sec_strength[i] += 1; 1124 | } 1125 | } 1126 | } 1127 | 1128 | Some(cdefp) 1129 | } 1130 | 1131 | /// 1132 | /// parse lr_params() 1133 | /// 1134 | fn parse_lr_params( 1135 | br: &mut BitReader, 1136 | sh: &SequenceHeader, 1137 | fh: &FrameHeader, 1138 | ) -> Option { 1139 | let mut lrp = LrParams::default(); 1140 | 1141 | #[allow(non_upper_case_globals)] 1142 | const Remap_Lr_Type: [u8; 4] = [ 1143 | RESTORE_NONE, 1144 | RESTORE_SWITCHABLE, 1145 | RESTORE_WIENER, 1146 | RESTORE_SGRPROJ, 1147 | ]; 1148 | 1149 | if fh.all_lossless || fh.allow_intrabc || !sh.enable_restoration { 1150 | lrp.frame_restoration_type[0] = RESTORE_NONE; 1151 | lrp.frame_restoration_type[1] = RESTORE_NONE; 1152 | lrp.frame_restoration_type[2] = RESTORE_NONE; 1153 | lrp.uses_lr = false; 1154 | return Some(lrp); 1155 | } 1156 | lrp.uses_lr = false; 1157 | let mut use_chroma_lr = false; 1158 | for i in 0..sh.color_config.num_planes as usize { 1159 | let lr_type = br.f::(2)?; // f(2) 1160 | lrp.frame_restoration_type[i] = Remap_Lr_Type[lr_type]; 1161 | if lrp.frame_restoration_type[i] != RESTORE_NONE { 1162 | lrp.uses_lr = true; 1163 | if i > 0 { 1164 | use_chroma_lr = true; 1165 | } 1166 | } 1167 | } 1168 | if lrp.uses_lr { 1169 | let mut lr_unit_shift; 1170 | if sh.use_128x128_superblock { 1171 | lr_unit_shift = br.f::(1)?; // f(1) 1172 | lr_unit_shift += 1; 1173 | } else { 1174 | lr_unit_shift = br.f::(1)?; // f(1) 1175 | if lr_unit_shift != 0 { 1176 | let lr_unit_extra_shift = br.f::(1)?; // f(1) 1177 | lr_unit_shift += lr_unit_extra_shift; 1178 | } 1179 | } 1180 | lrp.loop_restoration_size[0] = (RESTORATION_TILESIZE_MAX >> (2 - lr_unit_shift)) as u8; 1181 | let lr_uv_shift; 1182 | if sh.color_config.subsampling_x != 0 && sh.color_config.subsampling_y != 0 && use_chroma_lr 1183 | { 1184 | lr_uv_shift = br.f::(1)?; // f(1) 1185 | } else { 1186 | lr_uv_shift = 0; 1187 | } 1188 | lrp.loop_restoration_size[1] = lrp.loop_restoration_size[0] >> lr_uv_shift; 1189 | lrp.loop_restoration_size[2] = lrp.loop_restoration_size[0] >> lr_uv_shift; 1190 | } 1191 | 1192 | Some(lrp) 1193 | } 1194 | 1195 | /// read_tx_mode() 1196 | fn read_tx_mode(br: &mut BitReader, fh: &FrameHeader) -> Option { 1197 | let tx_mode: u8; 1198 | if fh.coded_lossless { 1199 | tx_mode = ONLY_4X4; 1200 | } else { 1201 | let tx_mode_select = br.f::(1)?; // f(1) 1202 | if tx_mode_select { 1203 | tx_mode = TX_MODE_SELECT; 1204 | } else { 1205 | tx_mode = TX_MODE_LARGEST; 1206 | } 1207 | } 1208 | 1209 | Some(tx_mode) 1210 | } 1211 | 1212 | /// 1213 | /// parse skip_mode_params() 1214 | /// 1215 | fn parse_skip_mode_params( 1216 | br: &mut BitReader, 1217 | sh: &SequenceHeader, 1218 | fh: &FrameHeader, 1219 | rfman: &av1::RefFrameManager, 1220 | ) -> Option { 1221 | let mut smp = SkipModeParams::default(); 1222 | 1223 | let skip_mode_allowed; 1224 | if fh.frame_is_intra || !fh.reference_select || !sh.enable_order_hint { 1225 | skip_mode_allowed = false; 1226 | } else { 1227 | let mut forward_idx = -1; 1228 | let mut backward_idx = -1; 1229 | let (mut forward_hint, mut backward_hint) = (0, 0); 1230 | for i in 0..REFS_PER_FRAME { 1231 | let ref_hint = rfman.ref_order_hint[fh.ref_frame_idx[i] as usize] as i32; 1232 | if av1::get_relative_dist(ref_hint, fh.order_hint as i32, sh) < 0 { 1233 | if forward_idx < 0 || av1::get_relative_dist(ref_hint, forward_hint, sh) > 0 { 1234 | forward_idx = i as i32; 1235 | forward_hint = ref_hint; 1236 | } 1237 | } else if av1::get_relative_dist(ref_hint, fh.order_hint as i32, sh) > 0 { 1238 | if backward_idx < 0 || av1::get_relative_dist(ref_hint, backward_hint, sh) < 0 { 1239 | backward_idx = i as i32; 1240 | backward_hint = ref_hint; 1241 | } 1242 | } 1243 | } 1244 | if forward_idx < 0 { 1245 | skip_mode_allowed = false; 1246 | } else if backward_idx >= 0 { 1247 | skip_mode_allowed = true; 1248 | smp.skip_mode_frame[0] = 1249 | (LAST_FRAME as i32 + cmp::min(forward_idx, backward_idx)) as u8; 1250 | smp.skip_mode_frame[1] = 1251 | (LAST_FRAME as i32 + cmp::max(forward_idx, backward_idx)) as u8; 1252 | } else { 1253 | let mut second_forward_id = -1; 1254 | let mut second_forward_hint = 0; 1255 | for i in 0..REFS_PER_FRAME { 1256 | let ref_hint = rfman.ref_order_hint[fh.ref_frame_idx[i] as usize] as i32; 1257 | if av1::get_relative_dist(ref_hint, forward_hint, sh) < 0 { 1258 | if second_forward_id < 0 1259 | || av1::get_relative_dist(ref_hint, second_forward_hint, sh) > 0 1260 | { 1261 | second_forward_id = i as i32; 1262 | second_forward_hint = ref_hint; 1263 | } 1264 | } 1265 | } 1266 | if second_forward_id < 0 { 1267 | skip_mode_allowed = false; 1268 | } else { 1269 | skip_mode_allowed = true; 1270 | smp.skip_mode_frame[0] = 1271 | (LAST_FRAME as i32 + cmp::min(forward_idx, second_forward_id)) as u8; 1272 | smp.skip_mode_frame[1] = 1273 | (LAST_FRAME as i32 + cmp::max(forward_idx, second_forward_id)) as u8; 1274 | } 1275 | } 1276 | } 1277 | if skip_mode_allowed { 1278 | smp.skip_mode_present = br.f::(1)?; // f(1) 1279 | } else { 1280 | smp.skip_mode_present = false; 1281 | } 1282 | 1283 | Some(smp) 1284 | } 1285 | 1286 | /// 1287 | /// parse global_motion_params() 1288 | /// 1289 | fn parse_global_motion_params( 1290 | br: &mut BitReader, 1291 | fh: &FrameHeader, 1292 | ) -> Option { 1293 | let mut gmp = GlobalMotionParams::default(); 1294 | 1295 | for ref_ in LAST_FRAME..=ALTREF_FRAME { 1296 | gmp.gm_type[ref_] = IDENTITY; 1297 | for i in 0..6 { 1298 | gmp.gm_params[ref_][i] = if i % 3 == 2 { 1299 | 1 << WARPEDMODEL_PREC_BITS 1300 | } else { 1301 | 0 1302 | }; 1303 | } 1304 | } 1305 | if fh.frame_is_intra { 1306 | return Some(gmp); 1307 | } 1308 | for ref_ in LAST_FRAME..=ALTREF_FRAME { 1309 | let is_global = br.f::(1)?; // f(1) 1310 | let type_; 1311 | if is_global { 1312 | let is_rot_zoom = br.f::(1)?; // f(1) 1313 | if is_rot_zoom { 1314 | type_ = ROTZOOM; 1315 | } else { 1316 | let is_translation = br.f::(1)?; // f(1) 1317 | type_ = if is_translation { TRANSLATION } else { AFFINE }; 1318 | } 1319 | } else { 1320 | type_ = IDENTITY; 1321 | } 1322 | gmp.gm_type[ref_] = type_; 1323 | 1324 | if type_ >= ROTZOOM { 1325 | gmp.gm_params[ref_][2] = read_global_param(br, type_, ref_, 2, fh)?; 1326 | gmp.gm_params[ref_][3] = read_global_param(br, type_, ref_, 3, fh)?; 1327 | if type_ == AFFINE { 1328 | gmp.gm_params[ref_][4] = read_global_param(br, type_, ref_, 4, fh)?; 1329 | gmp.gm_params[ref_][5] = read_global_param(br, type_, ref_, 5, fh)?; 1330 | } else { 1331 | gmp.gm_params[ref_][4] = -gmp.gm_params[ref_][3]; 1332 | gmp.gm_params[ref_][5] = gmp.gm_params[ref_][2]; 1333 | } 1334 | } 1335 | if type_ > TRANSLATION { 1336 | gmp.gm_params[ref_][0] = read_global_param(br, type_, ref_, 1, fh)?; 1337 | gmp.gm_params[ref_][1] = read_global_param(br, type_, ref_, 0, fh)?; 1338 | } 1339 | } 1340 | 1341 | Some(gmp) 1342 | } 1343 | 1344 | /// read_global_param() return gm_params[ref][idx] 1345 | fn read_global_param( 1346 | br: &mut BitReader, 1347 | type_: u8, 1348 | ref_: usize, 1349 | idx: usize, 1350 | fh: &FrameHeader, 1351 | ) -> Option { 1352 | let mut abs_bits = GM_ABS_ALPHA_BITS; 1353 | let mut prec_bits = GM_ALPHA_PREC_BITS; 1354 | if idx < 2 { 1355 | if type_ == TRANSLATION { 1356 | abs_bits = GM_ABS_TRANS_ONLY_BITS - if fh.allow_high_precision_mv { 0 } else { 1 }; 1357 | prec_bits = GM_TRANS_ONLY_PREC_BITS - if fh.allow_high_precision_mv { 0 } else { 1 }; 1358 | } else { 1359 | abs_bits = GM_ABS_TRANS_BITS; 1360 | prec_bits = GM_TRANS_PREC_BITS; 1361 | } 1362 | } 1363 | let prec_diff = WARPEDMODEL_PREC_BITS - prec_bits; 1364 | let round = if (idx % 3) == 2 { 1365 | 1 << WARPEDMODEL_PREC_BITS 1366 | } else { 1367 | 0 1368 | }; 1369 | let sub = if (idx % 3) == 2 { 1 << prec_bits } else { 0 }; 1370 | let mx = 1 << abs_bits; 1371 | let r = (fh.global_motion_params.prev_gm_params[ref_][idx] >> prec_diff) - sub; 1372 | let gm_params = (decode_signed_subexp_with_ref(br, -mx, mx + 1, r)? << prec_diff) + round; 1373 | 1374 | Some(gm_params) 1375 | } 1376 | 1377 | /// decode_signed_subexp_with_ref() 1378 | fn decode_signed_subexp_with_ref( 1379 | br: &mut BitReader, 1380 | low: i32, 1381 | high: i32, 1382 | r: i32, 1383 | ) -> Option { 1384 | let x = decode_unsigned_subexp_with_ref(br, high - low, r - low)?; 1385 | Some(x + low) 1386 | } 1387 | 1388 | /// decode_unsigned_subexp_with_ref() 1389 | fn decode_unsigned_subexp_with_ref( 1390 | br: &mut BitReader, 1391 | mx: i32, 1392 | r: i32, 1393 | ) -> Option { 1394 | let v = decode_subexp(br, mx)?; 1395 | if (r << 1) <= mx { 1396 | Some(inverse_recenter(r, v)) 1397 | } else { 1398 | Some(mx - 1 - inverse_recenter(mx - 1 - r, v)) 1399 | } 1400 | } 1401 | 1402 | /// decode_subexp() 1403 | fn decode_subexp(br: &mut BitReader, num_syms: i32) -> Option { 1404 | let mut i = 0; 1405 | let mut mk = 0; 1406 | let k = 3; 1407 | loop { 1408 | let b2 = if i != 0 { k + i - 1 } else { k }; 1409 | let a = 1 << b2; 1410 | if num_syms <= mk + 3 * a { 1411 | let subexp_final_bits = br.ns((num_syms - mk) as u32)? as i32; // ns(numSyms-mk) 1412 | return Some(subexp_final_bits + mk); 1413 | } else { 1414 | let subexp_more_bits = br.f::(1)?; // f(1) 1415 | if subexp_more_bits { 1416 | i += 1; 1417 | mk += a; 1418 | } else { 1419 | let subexp_bits = br.ns(b2)? as i32; // ns(b2) 1420 | return Some(subexp_bits + mk); 1421 | } 1422 | } 1423 | } 1424 | } 1425 | 1426 | /// inverse_recenter() 1427 | #[inline] 1428 | fn inverse_recenter(r: i32, v: i32) -> i32 { 1429 | if v > 2 * r { 1430 | v 1431 | } else if (v & 1) != 0 { 1432 | r - ((v + 1) >> 1) 1433 | } else { 1434 | r + (v >> 1) 1435 | } 1436 | } 1437 | 1438 | /// 1439 | /// parse film_grain_params() 1440 | /// 1441 | fn parse_film_grain_params( 1442 | br: &mut BitReader, 1443 | sh: &SequenceHeader, 1444 | fh: &FrameHeader, 1445 | ) -> Option { 1446 | let mut fgp = FilmGrainParams::default(); 1447 | 1448 | if !sh.film_grain_params_present || (!fh.show_frame && fh.showable_frame) { 1449 | // reset_grain_params() 1450 | return Some(fgp); 1451 | } 1452 | 1453 | fgp.apply_grain = br.f::(1)?; // f(1) 1454 | if !fgp.apply_grain { 1455 | // reset_grain_params() 1456 | return Some(fgp); 1457 | } 1458 | 1459 | fgp.grain_seed = br.f::(16)?; // f(16) 1460 | 1461 | fgp.update_grain = if fh.frame_type == INTER_FRAME { 1462 | br.f::(1)? // f(1) 1463 | } else { 1464 | true // 1 1465 | }; 1466 | 1467 | if !fgp.update_grain { 1468 | fgp.film_grain_params_ref_idx = br.f::(3)?; 1469 | 1470 | assert!(fgp.film_grain_params_ref_idx <= (REFS_PER_FRAME - 1) as u8); 1471 | } 1472 | 1473 | fgp.num_y_points = br.f::(4)?; 1474 | 1475 | assert!(fgp.num_y_points <= 14); 1476 | 1477 | for _ in 0..fgp.num_y_points { 1478 | fgp.point_y_value.push(br.f::(8)?); // f(8) 1479 | fgp.point_y_scaling.push(br.f::(8)?); // f(8) 1480 | } 1481 | 1482 | let cc = sh.color_config; 1483 | fgp.chroma_scaling_from_luma = if cc.mono_chrome { 1484 | false // 0 1485 | } else { 1486 | br.f::(1)? // f(1) 1487 | }; 1488 | 1489 | if sh.color_config.mono_chrome 1490 | || fgp.chroma_scaling_from_luma 1491 | || (cc.subsampling_x == 1 && cc.subsampling_y == 1 && fgp.num_y_points == 0) 1492 | { 1493 | fgp.num_cb_points = 0; 1494 | fgp.num_cr_points = 0; 1495 | } else { 1496 | fgp.num_cb_points = br.f::(4)?; // f(4) 1497 | 1498 | for _ in 0..fgp.num_cb_points { 1499 | fgp.point_cb_value.push(br.f::(8)?); // f(8) 1500 | fgp.point_cb_scaling.push(br.f::(8)?); // f(8) 1501 | } 1502 | 1503 | fgp.num_cr_points = br.f::(4)?; // f(4) 1504 | 1505 | for _ in 0..fgp.num_cr_points { 1506 | fgp.point_cr_value.push(br.f::(8)?); // f(8) 1507 | fgp.point_cr_scaling.push(br.f::(8)?); // f(8) 1508 | } 1509 | } 1510 | 1511 | assert!(fgp.num_cb_points <= 10); 1512 | assert!(fgp.num_cr_points <= 10); 1513 | 1514 | fgp.grain_scaling_minus_8 = br.f::(2)?; // f(2) 1515 | fgp.ar_coeff_lag = br.f::(2)?; // f(2) 1516 | let num_pos_luma = 2 * fgp.ar_coeff_lag * (fgp.ar_coeff_lag + 1); 1517 | let num_pos_chroma; 1518 | 1519 | if fgp.num_y_points != 0 { 1520 | num_pos_chroma = num_pos_luma + 1; 1521 | 1522 | for _ in 0..num_pos_luma { 1523 | fgp.ar_coeffs_y_plus_128.push(br.f::(8)?); // f(8) 1524 | } 1525 | } else { 1526 | num_pos_chroma = num_pos_luma; 1527 | } 1528 | 1529 | if fgp.chroma_scaling_from_luma || fgp.num_cb_points != 0 { 1530 | for _ in 0..num_pos_chroma { 1531 | fgp.ar_coeffs_cb_plus_128.push(br.f::(8)?); // f(8) 1532 | } 1533 | } 1534 | 1535 | if fgp.chroma_scaling_from_luma || fgp.num_cr_points != 0 { 1536 | for _ in 0..num_pos_chroma { 1537 | fgp.ar_coeffs_cr_plus_128.push(br.f::(8)?); // f(8) 1538 | } 1539 | } 1540 | 1541 | fgp.ar_coeff_shift_minus_6 = br.f::(2)?; // f(2) 1542 | fgp.grain_scale_shift = br.f::(2)?; // f(2) 1543 | 1544 | if fgp.num_cb_points != 0 { 1545 | fgp.cb_mult = br.f::(8)?; // f(8) 1546 | fgp.cb_luma_mult = br.f::(8)?; // f(8) 1547 | fgp.cb_offset = br.f::(9)?; // f(9) 1548 | } 1549 | 1550 | if fgp.num_cr_points != 0 { 1551 | fgp.cr_mult = br.f::(8)?; // f(8) 1552 | fgp.cr_luma_mult = br.f::(8)?; // f(8) 1553 | fgp.cr_offset = br.f::(9)?; // f(9) 1554 | } 1555 | 1556 | fgp.overlap_flag = br.f::(1)?; // f(1) 1557 | fgp.clip_to_restricted_range = br.f::(1)?; // f(1) 1558 | 1559 | Some(fgp) 1560 | } 1561 | 1562 | /// setup_past_independence() 1563 | fn setup_past_independence(fh: &mut FrameHeader) { 1564 | // FeatureData[i][j] 1565 | // PrevSegmentIds[row][col] 1566 | for ref_ in LAST_FRAME..=ALTREF_FRAME { 1567 | fh.global_motion_params.gm_type[ref_] = IDENTITY; 1568 | for i in 0..=5 { 1569 | fh.global_motion_params.prev_gm_params[ref_][i] = if i % 3 == 2 { 1570 | 1 << WARPEDMODEL_PREC_BITS 1571 | } else { 1572 | 0 1573 | }; 1574 | } 1575 | } 1576 | fh.loop_filter_params.loop_filter_delta_enabled = true; 1577 | fh.loop_filter_params.loop_filter_ref_deltas[INTRA_FRAME] = 1; 1578 | fh.loop_filter_params.loop_filter_ref_deltas[LAST_FRAME] = 0; 1579 | fh.loop_filter_params.loop_filter_ref_deltas[LAST2_FRAME] = 0; 1580 | fh.loop_filter_params.loop_filter_ref_deltas[LAST3_FRAME] = 0; 1581 | fh.loop_filter_params.loop_filter_ref_deltas[BWDREF_FRAME] = 0; 1582 | fh.loop_filter_params.loop_filter_ref_deltas[GOLDEN_FRAME] = -1; 1583 | fh.loop_filter_params.loop_filter_ref_deltas[ALTREF_FRAME] = -1; 1584 | fh.loop_filter_params.loop_filter_ref_deltas[ALTREF2_FRAME] = -1; 1585 | fh.loop_filter_params.loop_filter_mode_deltas[0] = 0; 1586 | fh.loop_filter_params.loop_filter_mode_deltas[1] = 0; 1587 | } 1588 | 1589 | /// load_previous() 1590 | fn load_previous(fh: &mut FrameHeader, rfman: &av1::RefFrameManager) { 1591 | let prev_frame = fh.ref_frame_idx[fh.primary_ref_frame as usize] as usize; 1592 | fh.global_motion_params.prev_gm_params = rfman.saved_gm_params[prev_frame]; 1593 | } 1594 | 1595 | /// 1596 | /// parse AV1 OBU header 1597 | /// 1598 | pub fn parse_obu_header(bs: &mut R, sz: u32) -> io::Result { 1599 | // parse obu_header() 1600 | let mut b1 = [0; 1]; 1601 | bs.read_exact(&mut b1)?; 1602 | let obu_forbidden_bit = (b1[0] >> 7) & 1; // f(1) 1603 | if obu_forbidden_bit != 0 { 1604 | return Err(io::Error::new( 1605 | io::ErrorKind::InvalidData, 1606 | "obu_forbidden_bit!=0", 1607 | )); 1608 | } 1609 | let obu_type = (b1[0] >> 3) & 0b1111; // f(4) 1610 | let obu_extension_flag = (b1[0] >> 2) & 1; // f(1) 1611 | let obu_has_size_field = (b1[0] >> 1) & 1; // f(1) 1612 | let (temporal_id, spatial_id) = if obu_extension_flag == 1 { 1613 | // parse obu_extension_header() 1614 | let mut b2 = [0; 1]; 1615 | bs.read_exact(&mut b2)?; 1616 | ((b2[0] >> 5) & 0b111, (b2[0] >> 3) & 0b11) // f(3),f(2) 1617 | } else { 1618 | (0, 0) 1619 | }; 1620 | // parse 'obu_size' in open_bitstream_unit() 1621 | let obu_header_len = 1 + (obu_extension_flag as u32); 1622 | let (obu_size_len, obu_size) = if obu_has_size_field == 1 { 1623 | leb128(bs)? 1624 | } else { 1625 | if sz < obu_header_len { 1626 | return Err(io::Error::new( 1627 | io::ErrorKind::InvalidData, 1628 | "invalid sz in open_bitstream_unit()", 1629 | )); 1630 | } 1631 | (0, sz - obu_header_len) 1632 | }; 1633 | 1634 | if sz < obu_header_len + obu_size_len + obu_size { 1635 | return Err(io::Error::new( 1636 | io::ErrorKind::InvalidData, 1637 | "invalid OBU size", 1638 | )); 1639 | } 1640 | 1641 | Ok(Obu { 1642 | obu_type, 1643 | obu_extension_flag: obu_extension_flag == 1, 1644 | obu_has_size_field: obu_has_size_field == 1, 1645 | temporal_id, 1646 | spatial_id, 1647 | obu_size, 1648 | header_len: obu_header_len + obu_size_len, 1649 | }) 1650 | } 1651 | 1652 | /// 1653 | /// parse sequence_header_obu() 1654 | /// 1655 | pub fn parse_sequence_header(bs: &mut R) -> Option { 1656 | let mut br = BitReader::new(bs); 1657 | let mut sh = SequenceHeader::default(); 1658 | 1659 | sh.seq_profile = br.f::(3)?; // f(3) 1660 | sh.still_picture = br.f::(1)?; // f(1) 1661 | sh.reduced_still_picture_header = br.f::(1)?; // f(1) 1662 | if sh.reduced_still_picture_header { 1663 | sh.timing_info_present_flag = false; 1664 | sh.decoder_model_info_present_flag = false; 1665 | sh.initial_display_delay_present_flag = false; 1666 | sh.operating_points_cnt = 1; 1667 | sh.op[0].operating_point_idc = 0; 1668 | sh.op[0].seq_level_idx = br.f::(5)?; // f(5) 1669 | sh.op[0].seq_tier = 0; 1670 | // decoder_model_present_for_this_op[0] = 0 1671 | // initial_display_delay_present_for_this_op[0] = 0 1672 | assert!(true); 1673 | } else { 1674 | sh.timing_info_present_flag = br.f::(1)?; // f(1) 1675 | if sh.timing_info_present_flag { 1676 | sh.timing_info = parse_timing_info(&mut br)?; // timing_info() 1677 | sh.decoder_model_info_present_flag = br.f::(1)?; // f(1) 1678 | if sh.decoder_model_info_present_flag { 1679 | unimplemented!("decoder_model_info()"); 1680 | } 1681 | } else { 1682 | sh.decoder_model_info_present_flag = false; 1683 | } 1684 | sh.initial_display_delay_present_flag = br.f::(1)?; // f(1) 1685 | sh.operating_points_cnt = br.f::(5)? + 1; // f(5) 1686 | assert_eq!(sh.operating_points_cnt, 1); // FIXME: support single operating point 1687 | for i in 0..(sh.operating_points_cnt) as usize { 1688 | sh.op[i].operating_point_idc = br.f::(12)?; // f(12) 1689 | sh.op[i].seq_level_idx = br.f::(5)?; // f(5) 1690 | if sh.op[i].seq_level_idx > 7 { 1691 | sh.op[i].seq_tier = br.f::(1)?; // f(1) 1692 | } else { 1693 | sh.op[i].seq_tier = 0; 1694 | } 1695 | if sh.decoder_model_info_present_flag { 1696 | unimplemented!("decoder_model_info_present_flag==1"); 1697 | } 1698 | if sh.initial_display_delay_present_flag { 1699 | unimplemented!("initial_display_delay_present_flag==1"); 1700 | } 1701 | } 1702 | } 1703 | // operatingPoint = choose_operating_point() 1704 | // OperatingPointIdc = operating_point_idc[operatingPoint] 1705 | sh.frame_width_bits = br.f::(4)? + 1; // f(4) 1706 | sh.frame_height_bits = br.f::(4)? + 1; // f(4) 1707 | sh.max_frame_width = br.f::(sh.frame_width_bits as usize)? + 1; // f(n) 1708 | sh.max_frame_height = br.f::(sh.frame_height_bits as usize)? + 1; // f(n) 1709 | if sh.reduced_still_picture_header { 1710 | sh.frame_id_numbers_present_flag = false; 1711 | } else { 1712 | sh.frame_id_numbers_present_flag = br.f::(1)?; // f(1) 1713 | } 1714 | if sh.frame_id_numbers_present_flag { 1715 | sh.delta_frame_id_length = br.f::(4)? + 2; // f(4) 1716 | sh.additional_frame_id_length = br.f::(3)? + 1; // f(3) 1717 | } 1718 | sh.use_128x128_superblock = br.f::(1)?; // f(1) 1719 | sh.enable_filter_intra = br.f::(1)?; // f(1) 1720 | sh.enable_intra_edge_filter = br.f::(1)?; // f(1) 1721 | if sh.reduced_still_picture_header { 1722 | sh.enable_interintra_compound = false; 1723 | sh.enable_masked_compound = false; 1724 | sh.enable_warped_motion = false; 1725 | sh.enable_dual_filter = false; 1726 | sh.enable_order_hint = false; 1727 | sh.enable_jnt_comp = false; 1728 | sh.enable_ref_frame_mvs = false; 1729 | sh.seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS; 1730 | sh.seq_force_integer_mv = SELECT_INTEGER_MV; 1731 | sh.order_hint_bits = 0; 1732 | } else { 1733 | sh.enable_interintra_compound = br.f::(1)?; // f(1) 1734 | sh.enable_masked_compound = br.f::(1)?; // f(1) 1735 | sh.enable_warped_motion = br.f::(1)?; // f(1) 1736 | sh.enable_dual_filter = br.f::(1)?; // f(1) 1737 | sh.enable_order_hint = br.f::(1)?; // f(1) 1738 | if sh.enable_order_hint { 1739 | sh.enable_jnt_comp = br.f::(1)?; // f(1) 1740 | sh.enable_ref_frame_mvs = br.f::(1)?; // f(1) 1741 | } else { 1742 | sh.enable_jnt_comp = false; 1743 | sh.enable_ref_frame_mvs = false; 1744 | } 1745 | let seq_choose_screen_content_tools = br.f::(1)?; // f(1) 1746 | if seq_choose_screen_content_tools { 1747 | sh.seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS; 1748 | } else { 1749 | sh.seq_force_screen_content_tools = br.f::(1)?; // f(1) 1750 | } 1751 | if sh.seq_force_screen_content_tools > 0 { 1752 | let seq_choose_integer_mv = br.f::(1)?; // f(1) 1753 | if seq_choose_integer_mv > 0 { 1754 | sh.seq_force_integer_mv = SELECT_INTEGER_MV; 1755 | } else { 1756 | sh.seq_force_integer_mv = br.f::(1)?; // f(1) 1757 | } 1758 | } else { 1759 | sh.seq_force_integer_mv = SELECT_INTEGER_MV; 1760 | } 1761 | if sh.enable_order_hint { 1762 | sh.order_hint_bits = br.f::(3)? + 1; // f(3) 1763 | } else { 1764 | sh.order_hint_bits = 0; 1765 | } 1766 | } 1767 | sh.enable_superres = br.f::(1)?; // f(1) 1768 | sh.enable_cdef = br.f::(1)?; // f(1) 1769 | sh.enable_restoration = br.f::(1)?; // f(1) 1770 | sh.color_config = parse_color_config(&mut br, &sh)?; // color_config() 1771 | sh.film_grain_params_present = br.f::(1)?; // f(1) 1772 | trailing_bits(&mut br)?; 1773 | 1774 | Some(sh) 1775 | } 1776 | 1777 | /// 1778 | /// parse frame_header 1779 | /// 1780 | pub fn parse_frame_header( 1781 | bs: &mut R, 1782 | sh: &SequenceHeader, 1783 | rfman: &mut av1::RefFrameManager, 1784 | ) -> Option { 1785 | let mut br = BitReader::new(bs); 1786 | let mut fh = FrameHeader::default(); 1787 | 1788 | // uncompressed_header() 1789 | let id_len = if sh.frame_id_numbers_present_flag { 1790 | sh.additional_frame_id_length + sh.delta_frame_id_length 1791 | } else { 1792 | 0 1793 | } as usize; 1794 | assert!(id_len <= 16); 1795 | assert!(NUM_REF_FRAMES <= 8); 1796 | let all_frames = ((1usize << NUM_REF_FRAMES) - 1) as u8; // 0xff 1797 | if sh.reduced_still_picture_header { 1798 | fh.show_existing_frame = false; 1799 | fh.frame_type = KEY_FRAME; 1800 | fh.frame_is_intra = true; 1801 | fh.show_frame = true; 1802 | fh.showable_frame = false; 1803 | } else { 1804 | fh.show_existing_frame = br.f::(1)?; // f(1) 1805 | if fh.show_existing_frame { 1806 | fh.frame_to_show_map_idx = br.f::(3)?; // f(3) 1807 | if sh.decoder_model_info_present_flag && !sh.timing_info.equal_picture_interval { 1808 | unimplemented!("temporal_point_info()"); 1809 | } 1810 | fh.refresh_frame_flags = 0; 1811 | if sh.frame_id_numbers_present_flag { 1812 | fh.display_frame_id = br.f::(id_len)?; // f(idLen) 1813 | } 1814 | fh.frame_type = rfman.ref_frame_type[fh.frame_to_show_map_idx as usize]; 1815 | if fh.frame_type == KEY_FRAME { 1816 | fh.refresh_frame_flags = all_frames; 1817 | } 1818 | if sh.film_grain_params_present { 1819 | unimplemented!("load_grain_params()"); 1820 | } 1821 | return Some(fh); 1822 | } 1823 | fh.frame_type = br.f::(2)?; // f(2) 1824 | fh.frame_is_intra = fh.frame_type == INTRA_ONLY_FRAME || fh.frame_type == KEY_FRAME; 1825 | fh.show_frame = br.f::(1)?; // f(1) 1826 | if fh.show_frame 1827 | && sh.decoder_model_info_present_flag 1828 | && !sh.timing_info.equal_picture_interval 1829 | { 1830 | unimplemented!("temporal_point_info()"); 1831 | } 1832 | if fh.show_frame { 1833 | fh.showable_frame = fh.frame_type != KEY_FRAME; 1834 | } else { 1835 | fh.showable_frame = br.f::(1)?; // f(1) 1836 | } 1837 | if fh.frame_type == SWITCH_FRAME || (fh.frame_type == KEY_FRAME && fh.show_frame) { 1838 | fh.error_resilient_mode = true; 1839 | } else { 1840 | fh.error_resilient_mode = br.f::(1)?; // f(1) 1841 | } 1842 | } 1843 | if fh.frame_type == KEY_FRAME && fh.show_frame { 1844 | for i in 0..NUM_REF_FRAMES { 1845 | rfman.ref_valid[i] = false; 1846 | rfman.ref_order_hint[i] = 0; 1847 | } 1848 | for i in 0..REFS_PER_FRAME { 1849 | fh.order_hints[LAST_FRAME + i] = 0; 1850 | } 1851 | } 1852 | fh.disable_cdf_update = br.f::(1)?; // f(1) 1853 | if sh.seq_force_screen_content_tools == SELECT_SCREEN_CONTENT_TOOLS { 1854 | fh.allow_screen_content_tools = br.f::(1)?; // f(1) 1855 | } else { 1856 | fh.allow_screen_content_tools = sh.seq_force_screen_content_tools != 0; 1857 | } 1858 | if fh.allow_screen_content_tools { 1859 | if sh.seq_force_integer_mv == SELECT_INTEGER_MV { 1860 | fh.force_integer_mv = br.f::(1)?; // f(1) 1861 | } else { 1862 | fh.force_integer_mv = sh.seq_force_integer_mv != 0; 1863 | } 1864 | } else { 1865 | fh.force_integer_mv = false; 1866 | } 1867 | if fh.frame_is_intra { 1868 | fh.force_integer_mv = true; 1869 | } 1870 | if sh.frame_id_numbers_present_flag { 1871 | let _prev_frame_id = fh.current_frame_id; 1872 | fh.current_frame_id = br.f::(id_len)?; // f(idLen) 1873 | rfman.mark_ref_frames(id_len, sh, &fh); 1874 | } else { 1875 | fh.current_frame_id = 0; 1876 | } 1877 | if fh.frame_type == SWITCH_FRAME { 1878 | fh.frame_size_override_flag = true; 1879 | } else if sh.reduced_still_picture_header { 1880 | fh.frame_size_override_flag = false; 1881 | } else { 1882 | fh.frame_size_override_flag = br.f::(1)?; // f(1) 1883 | } 1884 | fh.order_hint = br.f::(sh.order_hint_bits as usize)?; // f(OrderHintBits) 1885 | if fh.frame_is_intra || fh.error_resilient_mode { 1886 | fh.primary_ref_frame = PRIMARY_REF_NONE; 1887 | } else { 1888 | fh.primary_ref_frame = br.f::(3)?; // f(3) 1889 | } 1890 | if sh.decoder_model_info_present_flag { 1891 | unimplemented!("decoder_model_info_present_flag==1"); 1892 | } 1893 | fh.allow_high_precision_mv = false; 1894 | fh.use_ref_frame_mvs = false; 1895 | fh.allow_intrabc = false; 1896 | if fh.frame_type == SWITCH_FRAME || (fh.frame_type == KEY_FRAME && fh.show_frame) { 1897 | fh.refresh_frame_flags = all_frames; 1898 | } else { 1899 | fh.refresh_frame_flags = br.f::(8)?; // f(8) 1900 | } 1901 | if !fh.frame_is_intra || fh.refresh_frame_flags != all_frames { 1902 | if fh.error_resilient_mode && sh.enable_order_hint { 1903 | for i in 0..NUM_REF_FRAMES { 1904 | fh.ref_order_hint[i] = br.f::(sh.order_hint_bits as usize)?; // f(OrderHintBits) 1905 | if fh.ref_order_hint[i] != rfman.ref_order_hint[i] { 1906 | rfman.ref_valid[i] = false; 1907 | } 1908 | } 1909 | } 1910 | } 1911 | if fh.frame_type == KEY_FRAME { 1912 | fh.frame_size = parse_frame_size(&mut br, sh, &fh)?; // frame_size() 1913 | fh.render_size = parse_render_size(&mut br, &fh.frame_size)?; // render_size() 1914 | if fh.allow_screen_content_tools 1915 | && fh.frame_size.upscaled_width == fh.frame_size.frame_width 1916 | { 1917 | fh.allow_intrabc = br.f::(1)?; // f(1) 1918 | } 1919 | } else { 1920 | if fh.frame_type == INTRA_ONLY_FRAME { 1921 | fh.frame_size = parse_frame_size(&mut br, sh, &fh)?; // frame_size() 1922 | fh.render_size = parse_render_size(&mut br, &fh.frame_size)?; // render_size() 1923 | if fh.allow_screen_content_tools 1924 | && fh.frame_size.upscaled_width == fh.frame_size.frame_width 1925 | { 1926 | fh.allow_intrabc = br.f::(1)?; // f(1) 1927 | } 1928 | } else { 1929 | let frame_refs_short_signaling; 1930 | if !sh.enable_order_hint { 1931 | frame_refs_short_signaling = false; 1932 | } else { 1933 | frame_refs_short_signaling = br.f::(1)?; // f(1) 1934 | if frame_refs_short_signaling { 1935 | fh.last_frame_idx = br.f::(3)?; // f(3) 1936 | fh.gold_frame_idx = br.f::(3)?; // f(3) 1937 | unimplemented!("set_frame_refs()"); 1938 | } 1939 | } 1940 | for i in 0..REFS_PER_FRAME { 1941 | if !frame_refs_short_signaling { 1942 | fh.ref_frame_idx[i] = br.f::(3)?; // f(3) 1943 | 1944 | // ref_frame_idx[i] specifies which reference frames are used by inter frames. 1945 | // It is a requirement of bitstream conformance that RefValid[ref_frame_idx[i]] is equal to 1, 1946 | // and that the selected reference frames match the current frame in bit depth, profile, 1947 | // chroma subsampling, and color space. 1948 | assert!(rfman.ref_valid[fh.ref_frame_idx[i] as usize]); 1949 | } 1950 | if sh.frame_id_numbers_present_flag { 1951 | let delta_frame_id = br.f::(sh.delta_frame_id_length as usize)? + 1; // f(n) 1952 | let expected_frame_id = 1953 | (fh.current_frame_id + (1 << id_len) - delta_frame_id) % (1 << id_len); 1954 | 1955 | // expectedFrameId[i] specifies the frame id for each frame used for reference. 1956 | // It is a requirement of bitstream conformance that whenever expectedFrameId[i] is calculated, 1957 | // the value matches RefFrameId[ref_frame_idx[i]] (this contains the value of current_frame_id 1958 | // at the time that the frame indexed by ref_frame_idx was stored). 1959 | assert_eq!( 1960 | expected_frame_id, 1961 | rfman.ref_frame_id[fh.ref_frame_idx[i] as usize] 1962 | ); 1963 | } 1964 | } 1965 | if fh.frame_size_override_flag && !fh.error_resilient_mode { 1966 | unimplemented!("frame_size_with_refs()"); 1967 | } else { 1968 | fh.frame_size = parse_frame_size(&mut br, sh, &fh)?; // frame_size() 1969 | fh.render_size = parse_render_size(&mut br, &fh.frame_size)?; // render_size() 1970 | } 1971 | if fh.force_integer_mv { 1972 | fh.allow_high_precision_mv = false; 1973 | } else { 1974 | fh.allow_high_precision_mv = br.f::(1)?; // f(1) 1975 | } 1976 | fh.interpolation_filter = read_interpolation_filter(&mut br)?; // read_interpolation_filter() 1977 | fh.is_motion_mode_switchable = br.f::(1)?; // f(1) 1978 | if fh.error_resilient_mode || !sh.enable_ref_frame_mvs { 1979 | fh.use_ref_frame_mvs = false; 1980 | } else { 1981 | fh.use_ref_frame_mvs = br.f::(1)?; // f(1) 1982 | } 1983 | } 1984 | } 1985 | if !fh.frame_is_intra { 1986 | for i in 0..REFS_PER_FRAME { 1987 | let ref_frame = LAST_FRAME + i; 1988 | let hint = rfman.ref_order_hint[fh.ref_frame_idx[i] as usize]; 1989 | fh.order_hints[ref_frame] = hint; 1990 | if sh.enable_order_hint { 1991 | // RefFrameSignBias[refFrame] = 0 1992 | } else { 1993 | // RefFrameSignBias[refFrame] = get_relative_dist(hint, OrderHint) > 0 1994 | } 1995 | } 1996 | } 1997 | if sh.reduced_still_picture_header || fh.disable_cdf_update { 1998 | fh.disable_frame_end_update_cdf = true; 1999 | } else { 2000 | fh.disable_frame_end_update_cdf = br.f::(1)?; // f(1) 2001 | } 2002 | if fh.primary_ref_frame == PRIMARY_REF_NONE { 2003 | // init_non_coeff_cdfs() 2004 | setup_past_independence(&mut fh); 2005 | } else { 2006 | // load_cdfs(ref_frame_idx[primary_ref_frame]) 2007 | load_previous(&mut fh, rfman); 2008 | } 2009 | if fh.use_ref_frame_mvs { 2010 | // motion_field_estimation() 2011 | } 2012 | fh.tile_info = parse_tile_info(&mut br, sh, &fh.frame_size)?; // tile_info() 2013 | fh.quantization_params = parse_quantization_params(&mut br, &sh.color_config)?; // quantization_params() 2014 | fh.segmentation_params = parse_segmentation_params(&mut br, &fh)?; // segmentation_params() 2015 | fh.delta_q_params = parse_delta_q_params(&mut br, &fh.quantization_params)?; // delta_q_params() 2016 | fh.delta_lf_params = parse_delta_lf_params(&mut br, &fh)?; // delta_lf_params() 2017 | if fh.primary_ref_frame == PRIMARY_REF_NONE { 2018 | // init_coeff_cdfs() 2019 | } else { 2020 | // load_previous_segment_ids() 2021 | } 2022 | fh.coded_lossless = false; // FIXME: assume lossy coding 2023 | for _segment_id in 0..MAX_SEGMENTS { 2024 | // CodedLossless 2025 | // SegQMLevel[][segmentId] 2026 | } 2027 | fh.all_lossless = 2028 | fh.coded_lossless && (fh.frame_size.frame_width == fh.frame_size.upscaled_width); 2029 | fh.loop_filter_params = parse_loop_filter_params(&mut br, &sh.color_config, &fh)?; // loop_filter_params() 2030 | fh.cdef_params = parse_cdef_params(&mut br, sh, &fh)?; // cdef_params() 2031 | fh.lr_params = parse_lr_params(&mut br, sh, &fh)?; // lr_params() 2032 | fh.tx_mode = read_tx_mode(&mut br, &fh)?; // read_tx_mode() 2033 | { 2034 | // frame_reference_mode() 2035 | if fh.frame_is_intra { 2036 | fh.reference_select = false; 2037 | } else { 2038 | fh.reference_select = br.f::(1)?; // f(1) 2039 | } 2040 | } 2041 | fh.skip_mode_params = parse_skip_mode_params(&mut br, sh, &fh, rfman)?; // skip_mode_params() 2042 | if fh.frame_is_intra || fh.error_resilient_mode || !sh.enable_warped_motion { 2043 | fh.allow_warped_motion = false; 2044 | } else { 2045 | fh.allow_warped_motion = br.f::(1)?; // f(1) 2046 | } 2047 | fh.reduced_tx_set = br.f::(1)?; // f(1) 2048 | fh.global_motion_params = parse_global_motion_params(&mut br, &fh)?; // global_motion_params() 2049 | fh.film_grain_params = parse_film_grain_params(&mut br, sh, &fh)?; // film_grain_params() 2050 | 2051 | Some(fh) 2052 | } 2053 | 2054 | /// 2055 | /// parse tile_list_obu() 2056 | /// 2057 | pub fn parse_tile_list(bs: &mut R) -> Option { 2058 | let mut br = BitReader::new(bs); 2059 | let mut tl = TileList::default(); 2060 | 2061 | tl.output_frame_width_in_tiles_minus_1 = br.f::(8)?; 2062 | tl.output_frame_height_in_tiles_minus_1 = br.f::(8)?; 2063 | tl.tile_count_minus_1 = br.f::(16)?; 2064 | 2065 | for _ in 0..=tl.tile_count_minus_1 { 2066 | tl.tile_list_entries.push(parse_tile_list_entry(&mut br)?); 2067 | } 2068 | 2069 | Some(tl) 2070 | } 2071 | 2072 | /// 2073 | /// parse tile_list_entry() 2074 | /// 2075 | fn parse_tile_list_entry(br: &mut BitReader) -> Option { 2076 | let mut tle = TileListEntry::default(); 2077 | 2078 | tle.anchor_frame_idx = br.f::(8)?; 2079 | tle.anchor_tile_row = br.f::(8)?; 2080 | tle.anchor_tile_col = br.f::(8)?; 2081 | tle.tile_data_size_minus_1 = br.f::(16)?; 2082 | 2083 | Some(tle) 2084 | } 2085 | 2086 | /// 2087 | /// parse metadata_obu() 2088 | /// 2089 | pub fn parse_metadata_obu(bs: &mut R) -> io::Result { 2090 | let (_metadata_type_len, metadata_type) = leb128(bs)?; 2091 | let mut br = BitReader::new(bs); 2092 | 2093 | let metadata = match metadata_type { 2094 | METADATA_TYPE_HDR_CLL => parse_hdr_cll_metadata(&mut br), 2095 | METADATA_TYPE_HDR_MDCV => parse_hdr_mdcv_metadata(&mut br), 2096 | METADATA_TYPE_SCALABILITY => parse_scalability_metadata(&mut br), 2097 | METADATA_TYPE_ITUT_T35 => parse_itu_t_t35_metadata(&mut br), 2098 | METADATA_TYPE_TIMECODE => parse_timecode_metadata(&mut br), 2099 | _ => None, 2100 | }; 2101 | 2102 | if let Some(metadata_obu) = metadata { 2103 | Ok(metadata_obu) 2104 | } else { 2105 | Err(io::Error::new( 2106 | io::ErrorKind::InvalidData, 2107 | "Failed parsing metadata OBU or invalid metadata_type", 2108 | )) 2109 | } 2110 | } 2111 | 2112 | /// 2113 | /// parse metadata_hdr_cll() 2114 | /// 2115 | fn parse_hdr_cll_metadata(br: &mut BitReader) -> Option { 2116 | let mut meta = HdrCllMetadata::default(); 2117 | 2118 | meta.max_cll = br.f::(16)?; // f(16) 2119 | meta.max_fall = br.f::(16)?; // f(16) 2120 | 2121 | Some(MetadataObu::HdrCll(meta)) 2122 | } 2123 | 2124 | /// 2125 | /// parse metadata_hdr_mdcv() 2126 | /// 2127 | fn parse_hdr_mdcv_metadata(br: &mut BitReader) -> Option { 2128 | let mut meta = HdrMdcvMetadata::default(); 2129 | 2130 | for i in 0..3 { 2131 | meta.primary_chromaticity_x[i] = br.f::(16)?; // f(16) 2132 | meta.primary_chromaticity_y[i] = br.f::(16)?; // f(16) 2133 | } 2134 | 2135 | meta.white_point_chromaticity_x = br.f::(16)?; // f(16) 2136 | meta.white_point_chromaticity_y = br.f::(16)?; // f(16) 2137 | meta.luminance_max = br.f::(32)?; // f(32) 2138 | meta.luminance_min = br.f::(32)?; // f(32) 2139 | 2140 | Some(MetadataObu::HdrMdcv(meta)) 2141 | } 2142 | 2143 | /// 2144 | /// parse metadata_scalability() 2145 | /// 2146 | fn parse_scalability_metadata(br: &mut BitReader) -> Option { 2147 | let mut meta = ScalabilityMetadata::default(); 2148 | 2149 | meta.scalability_mode_idc = br.f::(8)?; // f(8) 2150 | if meta.scalability_mode_idc == SCALABILITY_SS { 2151 | meta.scalability_structure = parse_scalability_structure(br); 2152 | } 2153 | 2154 | Some(MetadataObu::Scalability(meta)) 2155 | } 2156 | 2157 | /// 2158 | /// parse scalability_structure() 2159 | /// 2160 | fn parse_scalability_structure(br: &mut BitReader) -> Option { 2161 | let mut ss = ScalabilityStructure::default(); 2162 | 2163 | ss.spatial_layers_cnt_minus_1 = br.f::(2)?; // f(2) 2164 | ss.spatial_layer_dimensions_present_flag = br.f::(1)?; // f(1) 2165 | ss.spatial_layer_description_present_flag = br.f::(1)?; // f(1) 2166 | ss.temporal_group_description_present_flag = br.f::(1)?; // f(1) 2167 | ss.scalability_structure_reserved_3bits = br.f::(3)?; // f(3) 2168 | 2169 | if ss.spatial_layer_dimensions_present_flag { 2170 | for _ in 0..=ss.spatial_layers_cnt_minus_1 { 2171 | ss.spatial_layer_max_width.push(br.f::(16)?); // f(16) 2172 | ss.spatial_layer_max_height.push(br.f::(16)?); // f(16) 2173 | } 2174 | } 2175 | 2176 | if ss.spatial_layer_description_present_flag { 2177 | for _ in 0..=ss.spatial_layers_cnt_minus_1 { 2178 | ss.spatial_layer_ref_id.push(br.f::(8)?); // f(8) 2179 | } 2180 | } 2181 | 2182 | if ss.temporal_group_description_present_flag { 2183 | ss.temporal_group_size = br.f::(8)?; // f(8) 2184 | 2185 | for i in 0..ss.temporal_group_size as usize { 2186 | ss.temporal_group_temporal_id.push(br.f::(3)?); // f(3) 2187 | ss.temporal_group_temporal_switching_up_point_flag 2188 | .push(br.f::(1)?); // f(1) 2189 | ss.temporal_group_spatial_switching_up_point_flag 2190 | .push(br.f::(1)?); // f(1) 2191 | ss.temporal_group_ref_cnt.push(br.f::(3)?); // f(3) 2192 | 2193 | for _ in 0..ss.temporal_group_ref_cnt[i] { 2194 | ss.temporal_group_ref_pic_diff[i].push(br.f::(8)?); // f(8) 2195 | } 2196 | } 2197 | } 2198 | 2199 | Some(ss) 2200 | } 2201 | 2202 | /// 2203 | /// parse metadata_itut_t35() 2204 | /// 2205 | fn parse_itu_t_t35_metadata(br: &mut BitReader) -> Option { 2206 | let mut meta = ItutT35Metadata::default(); 2207 | 2208 | meta.itu_t_t35_country_code = br.f::(8)?; // f(8) 2209 | 2210 | meta.itu_t_t35_country_code_extension_byte = if meta.itu_t_t35_country_code == 0xFF { 2211 | br.f::(8) // f(8) 2212 | } else { 2213 | None 2214 | }; 2215 | 2216 | while let Some(byte) = br.f::(8) { 2217 | meta.itu_t_t35_payload_bytes.push(byte); 2218 | } 2219 | 2220 | Some(MetadataObu::ItutT35(meta)) 2221 | } 2222 | 2223 | /// 2224 | /// parse metadata_timecode() 2225 | /// 2226 | fn parse_timecode_metadata(br: &mut BitReader) -> Option { 2227 | let mut meta = TimecodeMetadata::default(); 2228 | 2229 | meta.counting_type = br.f::(5)?; // f(5) 2230 | meta.full_timestamp_flag = br.f::(1)?; // f(1) 2231 | meta.discontinuity_flag = br.f::(1)?; // f(1) 2232 | meta.cnt_dropped_flag = br.f::(1)?; // f(1) 2233 | meta.n_frames = br.f::(9)?; // f(9) 2234 | 2235 | if meta.full_timestamp_flag { 2236 | meta.seconds_value = br.f::(6)?; // f(6) 2237 | meta.minutes_value = br.f::(6)?; // f(6) 2238 | meta.hours_value = br.f::(5)?; // f(5) 2239 | } else { 2240 | meta.seconds_flag = br.f::(1)?; // f(1) 2241 | 2242 | if meta.seconds_flag { 2243 | meta.seconds_value = br.f::(6)?; // f(6) 2244 | meta.minutes_flag = br.f::(1)?; // f(1) 2245 | 2246 | if meta.minutes_flag { 2247 | meta.minutes_value = br.f::(6)?; // f(6) 2248 | meta.hours_flag = br.f::(1)?; // f(1) 2249 | 2250 | if meta.hours_flag { 2251 | meta.hours_value = br.f::(5)?; // f(5) 2252 | } 2253 | } 2254 | } 2255 | } 2256 | 2257 | meta.time_offset_length = br.f::(5)?; // f(5) 2258 | 2259 | if meta.time_offset_length > 0 { 2260 | meta.time_offset_value = br.f::(meta.time_offset_length as usize)?; 2261 | // f(time_offset_length) 2262 | } 2263 | 2264 | Some(MetadataObu::Timecode(meta)) 2265 | } 2266 | -------------------------------------------------------------------------------- /streams/aom_cx_set_ref_av1.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/aom_cx_set_ref_av1.ivf -------------------------------------------------------------------------------- /streams/av1.annexb.obu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/av1.annexb.obu -------------------------------------------------------------------------------- /streams/av1.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/av1.ivf -------------------------------------------------------------------------------- /streams/av1.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/av1.webm -------------------------------------------------------------------------------- /streams/av1_lag5_frames10.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/av1_lag5_frames10.webm -------------------------------------------------------------------------------- /streams/av1_obu_test.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/av1_obu_test.ivf -------------------------------------------------------------------------------- /streams/av1_test.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/av1_test.webm -------------------------------------------------------------------------------- /streams/cdf_mode_0.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/cdf_mode_0.webm -------------------------------------------------------------------------------- /streams/cdf_mode_1.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/cdf_mode_1.webm -------------------------------------------------------------------------------- /streams/cdf_mode_2.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/cdf_mode_2.webm -------------------------------------------------------------------------------- /streams/download.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Download ivf files (aom test vectors) 4 | 5 | https://aomedia.googlesource.com/aom/ 6 | """ 7 | import os.path 8 | from lxml import etree 9 | import requests 10 | 11 | URL = 'http://storage.googleapis.com/aom-test-data/' 12 | XMLNS = 'http://doc.s3.amazonaws.com/2006-03-01' 13 | 14 | 15 | def download_file(fname): 16 | res = requests.get(URL + fname, stream=True) 17 | if not res.status_code == 200: 18 | print(f'{fname} {res.status_code}') 19 | return 20 | with open(fname, 'wb') as f: 21 | for chunk in res.iter_content(): 22 | f.write(chunk) 23 | length = res.headers['Content-length'] 24 | print(f'{fname} done({length})') 25 | 26 | 27 | def download_ivfs(): 28 | xml = etree.fromstring(requests.get(URL).content) 29 | ivf_list = xml.xpath('//s3:Key/text()', namespaces={'s3': XMLNS}) 30 | for fname in ivf_list: 31 | if not fname.endswith('.ivf'): 32 | continue 33 | if os.path.exists(fname): 34 | print(f'{fname} skipped') 35 | continue 36 | download_file(fname) 37 | 38 | 39 | if __name__ == '__main__': 40 | download_ivfs() 41 | -------------------------------------------------------------------------------- /streams/fetchmpd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Download MPEG-DASH contents 4 | """ 5 | import math 6 | import urllib.parse 7 | import re 8 | from lxml import etree 9 | import requests 10 | 11 | XMLNS = {'ns': 'urn:mpeg:dash:schema:mpd:2011'} 12 | 13 | 14 | def parse_mpd(url): 15 | """parse MPD meta""" 16 | mpd = etree.fromstring(requests.get(url).content) 17 | duration = mpd.xpath( 18 | '/ns:MPD/@mediaPresentationDuration', namespaces=XMLNS)[0] 19 | video_set = mpd.xpath( 20 | '//ns:AdaptationSet[@mimeType="video/webm"]/ns:Representation', namespaces=XMLNS) 21 | videos = [] 22 | for node in video_set: 23 | rep = {} 24 | for attr in ['bandwidth', 'width', 'height', 'frameRate', 'codecs']: 25 | rep[attr] = node.xpath(f'@{attr}')[0] 26 | for attr in ['media', 'initialization', 'duration', 'startNumber', 'timescale']: 27 | rep[attr] = node.xpath( 28 | f'ns:SegmentTemplate/@{attr}', namespaces=XMLNS)[0] 29 | rep['media'] = urllib.parse.urljoin(url, rep['media']) 30 | rep['initialization'] = urllib.parse.urljoin( 31 | url, rep['initialization']) 32 | videos.append(rep) 33 | return {'duration': duration, 'media': videos} 34 | 35 | 36 | def download_media(track, chunks, fname): 37 | """download media chunks to local file""" 38 | with open(fname, 'wb') as file: 39 | print(f'{track["initialization"]}') 40 | init_seg = requests.get(track['initialization']) 41 | fsize = file.write(init_seg.content) 42 | seg = int(track['startNumber']) 43 | while chunks > 0: 44 | media_url = track["media"].replace('$Number$', str(seg)) 45 | print(f'{media_url}', end='\r') 46 | media_seg = requests.get(media_url) 47 | fsize += file.write(media_seg.content) 48 | seg += 1 49 | chunks -= 1 50 | print(f'{media_url}') 51 | print(f'write {fsize} bytes') 52 | 53 | 54 | def parse_duration(duration): 55 | """parse ISO 8601 duration('PnYnMnDTnHnMnS')""" 56 | match = re.match(r'P\d+Y\d+M\d+DT(\d+)H(\d+)M(\d+.?\d*)S', duration) 57 | hms = match.groups() 58 | return int(hms[0]) * 3600 + int(hms[1]) * 60 + float(hms[2]) 59 | 60 | 61 | def download_mpd(mpdurl, rep_idx, fname): 62 | """download MPEG-DASH contents""" 63 | mpd = parse_mpd(mpdurl) 64 | duration = parse_duration(mpd['duration']) 65 | print(f'URL: {mpdurl}') 66 | print(f'MPD duration={duration}') 67 | for i, rep in enumerate(mpd['media']): 68 | mark = '*' if i == rep_idx else ' ' 69 | print('{}{}: res={width}x{height} fps={frameRate} codec="{codecs}" br={bandwidth}' 70 | .format(mark, i, **rep)) 71 | track = mpd['media'][rep_idx] 72 | chunks = math.ceil( 73 | duration / (float(track['duration']) / float(track['timescale']))) 74 | print(f'download #{rep_idx} ({chunks} chunks) to "{fname}"') 75 | download_media(mpd['media'][rep_idx], chunks, fname) 76 | 77 | 78 | MPD_URL = 'https://bitmovin-a.akamaihd.net/webpages/demos/content/av1/chrome/stream.mpd' 79 | REP_IDX = 0 80 | download_mpd(MPD_URL, REP_IDX, 'fetchmpd.webm') 81 | -------------------------------------------------------------------------------- /streams/metadata_hdr_cll_mdcv.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/metadata_hdr_cll_mdcv.ivf -------------------------------------------------------------------------------- /streams/note.txt: -------------------------------------------------------------------------------- 1 | ./aomenc --cpu-used=2 --obu park_joy_90p_8_420.y4m -o parkjoy.obu 2 | ./aomenc --cpu-used=2 --ivf park_joy_90p_8_420.y4m -o parkjoy.ivf 3 | ./aomenc --cpu-used=2 --webm park_joy_90p_8_420.y4m -o parkjoy.webm 4 | 5 | ./aomenc --cpu-used=2 --error-resilient=1 park_joy_90p_8_420.y4m -o parkjoy_error-resilient.ivf 6 | 7 | AOM_TEST_PRESERVE_OUTPUT=yes aom/test/examples.sh --bin-path examples 8 | 9 | ffmpeg -i parkjoy.webm -vcodec copy parkjoy.mp4 10 | ffmpeg -i parkjoy.mp4 -f lavfi -i anullsrc -vcodec copy -shortest parkjoy-audio.mp4 11 | -------------------------------------------------------------------------------- /streams/parkjoy-audio.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/parkjoy-audio.mp4 -------------------------------------------------------------------------------- /streams/parkjoy.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/parkjoy.ivf -------------------------------------------------------------------------------- /streams/parkjoy.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/parkjoy.mp4 -------------------------------------------------------------------------------- /streams/parkjoy.obu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/parkjoy.obu -------------------------------------------------------------------------------- /streams/parkjoy.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/parkjoy.webm -------------------------------------------------------------------------------- /streams/parkjoy_error-resilient.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/parkjoy_error-resilient.ivf -------------------------------------------------------------------------------- /streams/requirements.txt: -------------------------------------------------------------------------------- 1 | lxml 2 | requests 3 | -------------------------------------------------------------------------------- /streams/set_maps_av1.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/set_maps_av1.ivf -------------------------------------------------------------------------------- /streams/simple_encoder_av1.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/simple_encoder_av1.ivf -------------------------------------------------------------------------------- /streams/test_encode.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/test_encode.ivf -------------------------------------------------------------------------------- /streams/twopass_encoder_av1.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/twopass_encoder_av1.ivf -------------------------------------------------------------------------------- /streams/vase_tile_list.ivf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yohhoy/av1parser/bb6d3ff8e9415957a423d796969cb821272a0e27/streams/vase_tile_list.ivf --------------------------------------------------------------------------------