Skip to content

Commit

Permalink
Merge pull request #159 from quietvoid/p84_mode
Browse files Browse the repository at this point in the history
Add profile 8.4 conversion mode
  • Loading branch information
quietvoid authored May 24, 2022
2 parents cec69a4 + 270c19a commit 4328182
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 41 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ For working with an HEVC source file, there are multiple options that apply to m
* `0` - Parses the RPU, rewrites it untouched.
* `1` - Converts the RPU to be MEL compatible.
* `2` - Converts the RPU to be profile 8.1 compatible.
* `3` - Converts profile 5 to 8.
* `3` - Converts profile 5 to 8.1.
* `4` - Converts to profile 8.4.
* `-c`, `--crop` Set active area offsets to 0 (meaning no letterbox bars).
* `--drop-hdr10plus` Ignore HDR10+ metadata when writing the output HEVC.
* `--edit-config` Path to editor config JSON file.
Expand Down
Binary file added assets/tests/profile84.bin
Binary file not shown.
7 changes: 5 additions & 2 deletions dolby_vision/src/capi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
slice,
};

use crate::rpu::dovi_rpu::DoviRpu;
use crate::rpu::{dovi_rpu::DoviRpu, ConversionMode};

use super::c_structs::*;

Expand Down Expand Up @@ -155,7 +155,8 @@ pub unsafe extern "C" fn dovi_write_unspec62_nalu(ptr: *mut RpuOpaque) -> *const
/// 0: Don't modify the RPU
/// 1: Converts the RPU to be MEL compatible
/// 2: Converts the RPU to be profile 8.1 compatible
/// 3: Converts profile 5 to 8
/// 3: Converts profile 5 to 8.1
/// 4: Converts to static profile 8.4
///
/// If an error occurs, it is logged to RpuOpaque.error.
/// Returns 0 if successful, -1 otherwise.
Expand All @@ -168,6 +169,8 @@ pub unsafe extern "C" fn dovi_convert_rpu_with_mode(ptr: *mut RpuOpaque, mode: u
let opaque = &mut *ptr;

let ret = if let Some(rpu) = &mut opaque.rpu {
let mode = ConversionMode::from(mode);

match rpu.convert_with_mode(mode) {
Ok(_) => 0,
Err(e) => {
Expand Down
68 changes: 46 additions & 22 deletions dolby_vision/src/rpu/dovi_rpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use bitvec_helpers::{bitvec_reader::BitVecReader, bitvec_writer::BitVecWriter};
#[cfg(feature = "serde_feature")]
use serde::Serialize;

use super::compute_crc32;
use super::extension_metadata::blocks::{
ExtMetadataBlock, ExtMetadataBlockLevel11, ExtMetadataBlockLevel5, ExtMetadataBlockLevel9,
};
Expand All @@ -17,7 +16,7 @@ use super::rpu_data_header::{rpu_data_header, RpuDataHeader};
use super::rpu_data_mapping::RpuDataMapping;
use super::rpu_data_nlq::RpuDataNlq;
use super::vdr_dm_data::VdrDmData;
use super::{FEL_STR, MEL_STR};
use super::{compute_crc32, ConversionMode, FEL_STR, MEL_STR};

use crate::rpu::rpu_data_mapping::vdr_rpu_data_payload;
use crate::rpu::vdr_dm_data::vdr_dm_data_payload;
Expand Down Expand Up @@ -316,29 +315,45 @@ impl DoviRpu {
/// 0: Don't modify the RPU
/// 1: Converts the RPU to be MEL compatible
/// 2: Converts the RPU to be profile 8.1 compatible
/// 3: Converts profile 5 to 8
/// 3: Converts profile 5 to 8.1
/// 4: Converts to static profile 8.4
///
/// noop when profile 8 and mode 2 is used
pub fn convert_with_mode(&mut self, mode: u8) -> Result<()> {
if mode != 0 {
pub fn convert_with_mode<T: Into<ConversionMode>>(&mut self, mode: T) -> Result<()> {
let mode: ConversionMode = mode.into();

if mode != ConversionMode::Lossless {
self.modified = true;
}

if self.dovi_profile == 7 {
match mode {
1 => self.convert_to_mel()?,
2 => self.convert_to_81(),
_ => (),
};
} else if self.dovi_profile == 5 && mode == 3 {
self.p5_to_p81()?;
} else if self.dovi_profile == 8 && (mode == 1 || mode == 2) {
match mode {
1 => self.convert_to_mel()?,
2 => self.modified = false, // Ignore conversion
_ => (),
};
} else if mode != 0 {
let valid_conversion = match mode {
ConversionMode::Lossless => true,
ConversionMode::ToMel => {
if matches!(self.dovi_profile, 7 | 8) {
self.convert_to_mel()?;
true
} else {
false
}
}
ConversionMode::To81 => match self.dovi_profile {
7 | 8 => {
self.convert_to_p81();
true
}
5 => {
self.p5_to_p81()?;
true
}
_ => false,
},
ConversionMode::To84 => {
self.convert_to_p84();
true
}
};

if !valid_conversion {
bail!("Invalid profile for mode {} conversion!", mode);
}

Expand Down Expand Up @@ -372,7 +387,9 @@ impl DoviRpu {
Ok(())
}

fn convert_to_81(&mut self) {
fn convert_to_p81(&mut self) {
self.modified = true;

let header = &mut self.header;

// Change to 8.1
Expand All @@ -397,7 +414,7 @@ impl DoviRpu {
self.modified = true;

if self.dovi_profile == 5 {
self.convert_to_81();
self.convert_to_p81();

self.dovi_profile = 8;

Expand Down Expand Up @@ -494,4 +511,11 @@ impl DoviRpu {
..Default::default()
})
}

fn convert_to_p84(&mut self) {
self.convert_to_p81();

self.header = Profile84::rpu_data_header();
self.rpu_data_mapping = Some(Profile84::rpu_data_mapping());
}
}
41 changes: 39 additions & 2 deletions dolby_vision/src/rpu/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crc::{Crc, CRC_32_MPEG_2};

pub mod dovi_rpu;
pub mod extension_metadata;
pub mod generate;
Expand All @@ -7,13 +9,19 @@ pub mod rpu_data_mapping;
pub mod rpu_data_nlq;
pub mod vdr_dm_data;

use crc::{Crc, CRC_32_MPEG_2};

pub const NUM_COMPONENTS: usize = 3;

pub const FEL_STR: &str = "FEL";
pub const MEL_STR: &str = "MEL";

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ConversionMode {
Lossless = 0,
ToMel,
To81,
To84,
}

#[inline(always)]
fn compute_crc32(data: &[u8]) -> u32 {
let crc = Crc::<u32>::new(&CRC_32_MPEG_2);
Expand All @@ -22,3 +30,32 @@ fn compute_crc32(data: &[u8]) -> u32 {

digest.finalize()
}

impl From<u8> for ConversionMode {
fn from(mode: u8) -> ConversionMode {
match mode {
0 => ConversionMode::Lossless,
1 => ConversionMode::ToMel,
2 | 3 => ConversionMode::To81,
4 => ConversionMode::To84,
_ => ConversionMode::Lossless,
}
}
}

impl std::fmt::Display for ConversionMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConversionMode::Lossless => write!(f, "Lossless"),
ConversionMode::ToMel => write!(f, "To MEL"),
ConversionMode::To81 => write!(f, "To 8.1"),
ConversionMode::To84 => write!(f, "To 8.4"),
}
}
}

impl Default for ConversionMode {
fn default() -> Self {
Self::Lossless
}
}
3 changes: 2 additions & 1 deletion src/dovi/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use std::io::{stdout, Write};
use std::{collections::HashMap, path::PathBuf};

use anyhow::{bail, ensure, Result};
use serde::{Deserialize, Serialize};

use dolby_vision::rpu::extension_metadata::blocks::{
ExtMetadataBlock, ExtMetadataBlockLevel11, ExtMetadataBlockLevel5, ExtMetadataBlockLevel6,
ExtMetadataBlockLevel9,
};
use dolby_vision::rpu::extension_metadata::MasteringDisplayPrimaries;
use dolby_vision::rpu::generate::GenerateConfig;
use serde::{Deserialize, Serialize};

use utilities_dovi::parse_rpu_file;

Expand Down
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use dovi::{
CliOptions, WriteStartCodePreset,
};

const POSSIBLE_MODES: &[&str] = &["0", "1", "2", "3", "4"];

#[derive(Parser, Debug)]
#[clap(name = env!("CARGO_PKG_NAME"), about = "CLI tool combining multiple utilities for working with Dolby Vision", author = "quietvoid", version = env!("CARGO_PKG_VERSION"))]
struct Opt {
Expand All @@ -35,7 +37,9 @@ struct Opt {
Mode 0: Parses the RPU, rewrites it untouched\n \
Mode 1: Converts the RPU to be MEL compatible\n \
Mode 2: Converts the RPU to be profile 8.1 compatible\n \
Mode 3: Converts profile 5 to 8.1"
Mode 3: Converts profile 5 to 8.1\n \
Mode 4: Converts to profile 8.4",
possible_values = POSSIBLE_MODES,
)]
mode: Option<u8>,

Expand Down
Loading

0 comments on commit 4328182

Please sign in to comment.