Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formatting the catalog as per common catalog format #174

Merged
merged 12 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 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 @@ -8,6 +8,7 @@ members = [
"moq-clock",
"moq-dir",
"moq-native",
"moq-catalog",
]
resolver = "2"

Expand Down
17 changes: 17 additions & 0 deletions moq-catalog/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "moq-catalog"
description = "Media over QUIC"
authors = ["Luke Curley"]
repository = "https://github.com/kixelated/moq-rs"
license = "MIT OR Apache-2.0"

version = "0.1.0"
edition = "2021"

keywords = ["quic", "http3", "webtransport", "media", "live"]
categories = ["multimedia", "network-programming", "web-programming"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1", features = ["derive"] }
190 changes: 190 additions & 0 deletions moq-catalog/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
//! This module contains the structs and functions for the MoQ catalog format
/// The catalog format is a JSON file that describes the tracks available in a broadcast.
///
/// The current version of the catalog format is draft-01.
/// https://www.ietf.org/archive/id/draft-ietf-moq-catalogformat-01.html
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
pub struct Root {
pub version: u16,

#[serde(rename = "streamingFormat")]
pub streaming_format: u16,

#[serde(rename = "streamingFormatVersion")]
pub streaming_format_version: String,

#[serde(rename = "supportsDeltaUpdates")]
pub streaming_delta_updates: bool,

#[serde(rename = "commonTrackFields")]
pub common_track_fields: CommonTrackFields,

pub tracks: Vec<Track>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Track {
#[serde(skip_serializing_if = "Option::is_none")]
pub namespace: Option<String>,

pub name: String,

#[serde(rename = "initTrack")]
pub init_track: Option<String>,

#[serde(rename = "initData")]
pub data_track: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub packaging: Option<TrackPackaging>,

#[serde(rename = "renderGroup", skip_serializing_if = "Option::is_none")]
pub render_group: Option<u16>,

#[serde(rename = "altGroup", skip_serializing_if = "Option::is_none")]
pub alt_group: Option<u16>,

#[serde(rename = "selectionParams")]
pub selection_params: SelectionParam,

#[serde(rename = "temporalId", skip_serializing_if = "Option::is_none")]
pub temporal_id: Option<u32>,

#[serde(rename = "spatialId", skip_serializing_if = "Option::is_none")]
pub spatial_id: Option<u32>,

#[serde(skip_serializing_if = "Option::is_none")]
pub depends: Option<Vec<String>>,
}

impl Track {
#[allow(dead_code)] // TODO use
fn with_common(&mut self, common: &CommonTrackFields) {
if self.namespace.is_none() {
self.namespace.clone_from(&common.namespace);
}
if self.packaging.is_none() {
self.packaging.clone_from(&common.packaging);
}
if self.render_group.is_none() {
self.render_group = common.render_group;
}
if self.alt_group.is_none() {
self.alt_group = common.alt_group;
}
}
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)]
pub enum TrackPackaging {
#[serde(rename = "cmaf")]
#[default]
Cmaf,

#[serde(rename = "loc")]
Loc,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct SelectionParam {
pub codec: Option<String>,

#[serde(rename = "mimeType")]
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub framerate: Option<u64>,

#[serde(skip_serializing_if = "Option::is_none")]
pub bitrate: Option<u32>,

#[serde(skip_serializing_if = "Option::is_none")]
pub width: Option<u32>,

#[serde(skip_serializing_if = "Option::is_none")]
pub height: Option<u32>,

#[serde(skip_serializing_if = "Option::is_none")]
pub samplerate: Option<u32>,

#[serde(rename = "channelConfig", skip_serializing_if = "Option::is_none")]
pub channel_config: Option<String>,

#[serde(rename = "displayWidth", skip_serializing_if = "Option::is_none")]
pub display_width: Option<u16>,

#[serde(rename = "displayHeight", skip_serializing_if = "Option::is_none")]
pub display_height: Option<u16>,

#[serde(rename = "lang", skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct CommonTrackFields {
#[serde(skip_serializing_if = "Option::is_none")]
pub namespace: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub packaging: Option<TrackPackaging>,

#[serde(rename = "renderGroup", skip_serializing_if = "Option::is_none")]
pub render_group: Option<u16>,

#[serde(rename = "altGroup", skip_serializing_if = "Option::is_none")]
pub alt_group: Option<u16>,
}

impl CommonTrackFields {
/// Serialize function to conditionally include fields based on their commonality amoung tracks
pub fn from_tracks(tracks: &mut [Track]) -> Self {
if tracks.is_empty() {
return Default::default();
}

// Use the first track as the basis
let mut common = Self {
namespace: tracks[0].namespace.clone(),
packaging: tracks[0].packaging.clone(),
render_group: tracks[0].render_group,
alt_group: tracks[0].alt_group,
};

// Loop over the other tracks to check if they have the same values
for track in &mut tracks[1..] {
if track.namespace != common.namespace {
common.namespace = None;
}
if track.packaging != common.packaging {
common.packaging = None;
}
if track.render_group != common.render_group {
common.render_group = None
}
if track.alt_group != common.alt_group {
common.alt_group = None;
}
}

// Loop again to remove the common fields from the tracks
for track in tracks {
if common.namespace.is_some() {
track.namespace = None;
}
if track.packaging.is_some() {
track.packaging = None;
}
if track.render_group.is_some() {
track.render_group = None;
}
if track.alt_group.is_some() {
track.alt_group = None;
}
}

common
}
}
3 changes: 2 additions & 1 deletion moq-pub/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = ["Mike English", "Luke Curley"]
repository = "https://github.com/kixelated/moq-rs"
license = "MIT OR Apache-2.0"

version = "0.5.1"
version = "0.6.0"
edition = "2021"

keywords = ["quic", "http3", "webtransport", "media", "live"]
Expand All @@ -16,6 +16,7 @@ categories = ["multimedia", "network-programming", "web-programming"]
[dependencies]
moq-native = { path = "../moq-native", version = "0.2" }
moq-transport = { path = "../moq-transport", version = "0.5" }
moq-catalog = { path = "../moq-catalog", version = "0.1" }

url = "2"
bytes = "1"
Expand Down
Loading
Loading