Skip to content

Commit

Permalink
initial refactor of the flv crate
Browse files Browse the repository at this point in the history
  • Loading branch information
TroyKomodo committed Jan 13, 2025
1 parent 4459e5e commit 82115f9
Show file tree
Hide file tree
Showing 36 changed files with 1,898 additions and 1,581 deletions.
37 changes: 19 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ scuffle-bytes-util = { path = "crates/bytes-util", version = "0.0.1" }
scuffle-expgolomb = { path = "crates/expgolomb", version = "0.0.1" }
scuffle-amf0 = { path = "crates/amf0", version = "0.0.1" }
scuffle-av1 = { path = "crates/av1", version = "0.0.1" }
scuffle-flv = { path = "crates/flv", version = "0.0.1" }

[profile.release-debug]
inherits = "release"
Expand Down
44 changes: 43 additions & 1 deletion crates/av1/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
use std::io;

use byteorder::ReadBytesExt;
use bytes::Bytes;
use scuffle_bytes_util::{BitReader, BitWriter, BytesCursorExt};

/// AV1 Video Descriptor
/// https://aomediacodec.github.io/av1-mpeg2-ts/#av1-video-descriptor
#[derive(Debug, Clone, PartialEq)]
pub struct AV1VideoDescriptor {
pub codec_configuration_record: AV1CodecConfigurationRecord,
}

impl AV1VideoDescriptor {
pub fn demux(reader: &mut io::Cursor<Bytes>) -> io::Result<Self> {
let tag = reader.read_u8()?;
let length = reader.read_u8()?;

if tag != 0x80 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid AV1 video descriptor tag"));
}

if length != 4 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid AV1 video descriptor length",
));
}

Ok(AV1VideoDescriptor {
codec_configuration_record: AV1CodecConfigurationRecord::demux(reader)?,
})
}
}

#[derive(Debug, Clone, PartialEq)]
/// AV1 Codec Configuration Record
/// https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax
Expand All @@ -16,6 +46,7 @@ pub struct AV1CodecConfigurationRecord {
pub chroma_subsampling_x: bool,
pub chroma_subsampling_y: bool,
pub chroma_sample_position: u8,
pub hdr_wcg_idc: u8,
pub initial_presentation_delay_minus_one: Option<u8>,
pub config_obu: Bytes,
}
Expand Down Expand Up @@ -45,7 +76,13 @@ impl AV1CodecConfigurationRecord {
let chroma_subsampling_y = bit_reader.read_bit()?;
let chroma_sample_position = bit_reader.read_bits(2)? as u8;

bit_reader.seek_bits(3)?; // reserved 3 bits
// This is from the https://aomediacodec.github.io/av1-mpeg2-ts/#av1-video-descriptor spec
// The spec from https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-section is old and contains 3 bits reserved
// The newer spec takes 2 of those reserved bits to represent the HDR WCG IDC
// Leaving 1 bit for future use
let hdr_wcg_idc = bit_reader.read_bits(2)? as u8;

bit_reader.seek_bits(1)?; // reserved 1 bits

let initial_presentation_delay_minus_one = if bit_reader.read_bit()? {
Some(bit_reader.read_bits(4)? as u8)
Expand All @@ -70,6 +107,7 @@ impl AV1CodecConfigurationRecord {
chroma_subsampling_x,
chroma_subsampling_y,
chroma_sample_position,
hdr_wcg_idc,
initial_presentation_delay_minus_one,
config_obu: reader.extract_remaining(),
})
Expand Down Expand Up @@ -139,6 +177,7 @@ mod tests {
chroma_subsampling_x: true,
chroma_subsampling_y: true,
chroma_sample_position: 0,
hdr_wcg_idc: 0,
initial_presentation_delay_minus_one: None,
config_obu: b"\n\x0f\0\0\0j\xef\xbf\xe1\xbc\x02\x19\x90\x10\x10\x10@",
}
Expand Down Expand Up @@ -182,6 +221,7 @@ mod tests {
chroma_subsampling_x: true,
chroma_subsampling_y: true,
chroma_sample_position: 0,
hdr_wcg_idc: 0,
initial_presentation_delay_minus_one: Some(
15,
),
Expand All @@ -202,6 +242,7 @@ mod tests {
chroma_subsampling_x: false,
chroma_subsampling_y: false,
chroma_sample_position: 0,
hdr_wcg_idc: 0,
initial_presentation_delay_minus_one: None,
config_obu: Bytes::from_static(b"HELLO FROM THE OBU"),
};
Expand All @@ -224,6 +265,7 @@ mod tests {
chroma_subsampling_x: false,
chroma_subsampling_y: false,
chroma_sample_position: 0,
hdr_wcg_idc: 0,
initial_presentation_delay_minus_one: Some(0),
config_obu: Bytes::from_static(b"HELLO FROM THE OBU"),
};
Expand Down
2 changes: 1 addition & 1 deletion crates/av1/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
mod config;
mod obu;

pub use config::AV1CodecConfigurationRecord;
pub use config::{AV1CodecConfigurationRecord, AV1VideoDescriptor};
pub use obu::{seq, ObuHeader, ObuType};
14 changes: 12 additions & 2 deletions crates/flv/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
[package]
name = "flv"
name = "scuffle-flv"
version = "0.0.1"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/scufflecloud/scuffle"
authors = ["Scuffle <[email protected]>"]
readme = "README.md"
documentation = "https://docs.rs/scuffle-flv"
description = "A pure Rust FLV demuxer."
keywords = ["flv", "demuxer"]

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] }

[dependencies]
byteorder = "1.5"
bytes = "1.5"
num-traits = "0.2"
num-derive = "0.4"
thiserror = "2.0"

scuffle-av1.workspace = true
h264 = { path = "../h264" }
h265 = { path = "../h265" }
scuffle-aac = { path = "../aac" }
scuffle-bytes-util.workspace = true
scuffle-av1.workspace = true
scuffle-amf0.workspace = true
scuffle-workspace-hack.workspace = true
1 change: 1 addition & 0 deletions crates/flv/LICENSE.Apache-2.0
1 change: 1 addition & 0 deletions crates/flv/LICENSE.MIT
17 changes: 17 additions & 0 deletions crates/flv/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# scuffle-flv

> [!WARNING]
> This crate is under active development and may not be stable.
[![crates.io](https://img.shields.io/crates/v/scuffle-flv.svg)](https://crates.io/crates/scuffle-flv) [![docs.rs](https://img.shields.io/docsrs/scuffle-flv)](https://docs.rs/scuffle-flv)

---

A pure Rust implementation of the FLV format, allowing for demuxing of FLV files or streams.

## License

This project is licensed under the [MIT](./LICENSE.MIT) or [Apache-2.0](./LICENSE.Apache-2.0) license.
You can choose between one of them if you use this work.

`SPDX-License-Identifier: MIT OR Apache-2.0`
44 changes: 44 additions & 0 deletions crates/flv/src/aac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use bytes::Bytes;
use scuffle_bytes_util::BytesCursorExt;

use crate::macros::nutype_enum;

nutype_enum! {
/// FLV AAC Packet Type
///
/// Defined in the FLV specification. Chapter 1 - AACAUDIODATA
///
/// The AACPacketType indicates the type of data in the AACAUDIODATA.
pub enum AacPacketType(u8) {
/// Sequence Header
SequenceHeader = 0x0,
/// Raw
Raw = 0x1,
}
}

/// AAC Packet
/// This is a container for aac data.
/// This enum contains the data for the different types of aac packets.
/// Defined in the FLV specification. Chapter 1 - AACAUDIODATA
#[derive(Debug, Clone, PartialEq)]
pub enum AacPacket {
/// AAC Sequence Header
SequenceHeader(Bytes),
/// AAC Raw
Raw(Bytes),
/// Data we don't know how to parse
Unknown { aac_packet_type: AacPacketType, data: Bytes },
}

impl AacPacket {
pub fn demux(aac_packet_type: AacPacketType, reader: &mut std::io::Cursor<Bytes>) -> std::io::Result<Self> {
let data = reader.extract_remaining();

match aac_packet_type {
AacPacketType::Raw => Ok(AacPacket::Raw(data)),
AacPacketType::SequenceHeader => Ok(AacPacket::SequenceHeader(data)),
_ => Ok(AacPacket::Unknown { aac_packet_type, data }),
}
}
}
Loading

0 comments on commit 82115f9

Please sign in to comment.