Skip to content
Draft
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
28 changes: 28 additions & 0 deletions Cargo.lock

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

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ hdr10plus = { version = "2.1.5", features = ["json"] }
anyhow = "1.0.102"
clap = { version = "4.6.0", features = ["derive", "wrap_help", "deprecated"] }
clap_lex = "*"
csv = "1.4.0"
indicatif = "0.18.4"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.149", features = ["preserve_order"] }
itertools = "0.14.0"
plotters = { version = "0.3.7", default-features = false, features = ["bitmap_backend", "bitmap_encoder", "all_series"] }

serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.149", features = ["preserve_order"] }
[dev-dependencies]
assert_cmd = "2.2.0"
assert_fs = "1.1.3"
Expand Down
21 changes: 20 additions & 1 deletion dolby_vision/src/rpu/extension_metadata/blocks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bitvec_helpers::{
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize, Serializer};

pub mod level1;
pub mod level10;
Expand Down Expand Up @@ -221,4 +221,23 @@ impl ExtMetadataBlock {

Ok(())
}

#[cfg(feature = "serde")]
pub fn serialize_inner<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
ExtMetadataBlock::Level1(b) => b.serialize(serializer),
ExtMetadataBlock::Level2(b) => b.serialize(serializer),
ExtMetadataBlock::Level3(b) => b.serialize(serializer),
ExtMetadataBlock::Level4(b) => b.serialize(serializer),
ExtMetadataBlock::Level5(b) => b.serialize(serializer),
ExtMetadataBlock::Level6(b) => b.serialize(serializer),
ExtMetadataBlock::Level8(b) => b.serialize(serializer),
ExtMetadataBlock::Level9(b) => b.serialize(serializer),
ExtMetadataBlock::Level10(b) => b.serialize(serializer),
ExtMetadataBlock::Level11(b) => b.serialize(serializer),
ExtMetadataBlock::Level254(b) => b.serialize(serializer),
ExtMetadataBlock::Level255(b) => b.serialize(serializer),
ExtMetadataBlock::Reserved(b) => b.serialize(serializer),
}
}
}
165 changes: 143 additions & 22 deletions src/commands/export.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::PathBuf;

use clap::{
Args, ValueEnum, ValueHint,
Args, ValueHint,
builder::{EnumValueParser, PossibleValue, TypedValueParser},
};
use clap_lex::OsStrExt as _;
Expand Down Expand Up @@ -34,11 +34,30 @@ pub struct ExportArgs {
long,
short = 'd',
conflicts_with = "output",
value_parser = ExportOptionParser,
value_parser = ExportDataOptionParser,
value_delimiter = ','
)]
pub data: Vec<(ExportData, Option<PathBuf>)>,

#[arg(
id = "levels-format",
help = "Format to output levels exports",
long,
short = 'f',
default_value = "csv"
)]
pub levels_format: LevelsOutputFormat,

#[arg(
id = "levels",
help = "List of key-value export parameters formatted as `key=output`, where `output` is an output file path.\nSupports multiple occurences prefixed by --levels or delimited by ','",
long,
short = 'l',
value_parser = ExportLevelsOptionParser,
value_delimiter = ','
)]
pub levels: Vec<(ExportLevel, Option<PathBuf>)>,

// FIXME: export single output deprecation
#[arg(
id = "output",
Expand All @@ -62,19 +81,86 @@ pub enum ExportData {
Level5,
}

#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum LevelsOutputFormat {
Json,
#[default]
Csv,
}

#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportLevel {
#[value(alias = "l1")]
Level1,
#[value(alias = "l2")]
Level2,
#[value(alias = "l3")]
Level3,
#[value(alias = "l4")]
Level4,
#[value(alias = "l5")]
Level5,
#[value(alias = "l6")]
Level6,
#[value(alias = "l8")]
Level8,
#[value(alias = "l9")]
Level9,
#[value(alias = "l10")]
Level10,
#[value(alias = "l11")]
Level11,
}

impl ExportData {
pub fn default_output_file(&self) -> &'static str {
pub const fn default_output_file(&self) -> &'static str {
match self {
Self::All => "RPU_export.json",
Self::Scenes => "RPU_scenes.txt",
Self::Level5 => "RPU_L5_edit_config.json",
}
}
}

impl ExportLevel {
pub const fn level(&self) -> u8 {
match self {
Self::Level1 => 1,
Self::Level2 => 2,
Self::Level3 => 3,
Self::Level4 => 4,
Self::Level5 => 5,
Self::Level6 => 6,
Self::Level8 => 8,
Self::Level9 => 9,
Self::Level10 => 10,
Self::Level11 => 11,
}
}
pub fn default_output_file(&self, format: LevelsOutputFormat) -> String {
let level = self.level();
let ext = format.ext();

format!("L{level}_export.{ext}")
}
}

impl LevelsOutputFormat {
pub const fn ext(&self) -> &'static str {
match self {
ExportData::All => "RPU_export.json",
ExportData::Scenes => "RPU_scenes.txt",
ExportData::Level5 => "RPU_L5_edit_config.json",
Self::Json => "json",
Self::Csv => "csv",
}
}
}

#[derive(Clone)]
struct ExportOptionParser;
impl TypedValueParser for ExportOptionParser {
pub struct ExportDataOptionParser;

#[derive(Clone)]
pub struct ExportLevelsOptionParser;

impl TypedValueParser for ExportDataOptionParser {
type Value = (ExportData, Option<PathBuf>);

fn parse_ref(
Expand All @@ -83,23 +169,58 @@ impl TypedValueParser for ExportOptionParser {
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
let data_parser = EnumValueParser::<ExportData>::new();

if let Some((data_str, output_str)) = value.split_once("=") {
Ok((
data_parser.parse_ref(cmd, arg, data_str)?,
output_str.to_str().map(str::parse).and_then(Result::ok),
))
} else {
Ok((data_parser.parse_ref(cmd, arg, value)?, None))
}
export_option_parse_ref(cmd, arg, value)
}

fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
Some(Box::new(
ExportData::value_variants()
.iter()
.filter_map(|v| v.to_possible_value()),
export_option_possible_values::<ExportData>()
}
}

impl TypedValueParser for ExportLevelsOptionParser {
type Value = (ExportLevel, Option<PathBuf>);

fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
export_option_parse_ref(cmd, arg, value)
}

fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
export_option_possible_values::<ExportLevel>()
}
}

fn export_option_parse_ref<E>(
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<(E, Option<PathBuf>), clap::Error>
where
E: clap::ValueEnum + Clone + Send + Sync + 'static,
{
let data_parser = EnumValueParser::<E>::new();

if let Some((data_str, output_str)) = value.split_once("=") {
Ok((
data_parser.parse_ref(cmd, arg, data_str)?,
output_str.to_str().map(str::parse).and_then(Result::ok),
))
} else {
Ok((data_parser.parse_ref(cmd, arg, value)?, None))
}
}

fn export_option_possible_values<E>() -> Option<Box<dyn Iterator<Item = PossibleValue>>>
where
E: clap::ValueEnum + Clone + Send + Sync + 'static,
{
Some(Box::new(
E::value_variants()
.iter()
.filter_map(|v| v.to_possible_value()),
))
}
2 changes: 1 addition & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod remove;
pub use convert::ConvertArgs;
pub use demux::DemuxArgs;
pub use editor::EditorArgs;
pub use export::{ExportArgs, ExportData};
pub use export::{ExportArgs, ExportData, ExportLevel, LevelsOutputFormat};
pub use extract_rpu::ExtractRpuArgs;
pub use generate::GenerateArgs;
pub use info::InfoArgs;
Expand Down
Loading