From 62813b8e1d5f01f9d966f1523035f47e82c29f96 Mon Sep 17 00:00:00 2001 From: quietvoid <39477805+quietvoid@users.noreply.github.com> Date: Fri, 16 Oct 2020 23:34:23 -0400 Subject: [PATCH] Major rework, fix parsing (#22) * WIP Fix spaghetti parsing, closes #16 * Major rework, use deku for parsing * Move indexes constants * Bump to 0.3.0 --- Cargo.toml | 20 +- assets/ToS-s15.h265 | Bin 3392 -> 2846 bytes assets/ToS-s57.h265 | Bin 0 -> 2850 bytes assets/ToS-s58.h265 | Bin 0 -> 2856 bytes assets/ToS-s59.h265 | Bin 0 -> 2858 bytes src/hdr10plus.rs | 709 ----------------- src/hdr10plus/metadata.rs | 224 ++++++ src/hdr10plus/mod.rs | 5 + src/hdr10plus/parser.rs | 303 ++++++++ src/hdr10plus/tests.rs | 1430 ++++++++++++++++++++++++++++++++++ src/lib.rs | 1524 ------------------------------------- src/main.rs | 26 +- 12 files changed, 1983 insertions(+), 2258 deletions(-) create mode 100644 assets/ToS-s57.h265 create mode 100644 assets/ToS-s58.h265 create mode 100644 assets/ToS-s59.h265 delete mode 100644 src/hdr10plus.rs create mode 100644 src/hdr10plus/metadata.rs create mode 100644 src/hdr10plus/mod.rs create mode 100644 src/hdr10plus/parser.rs create mode 100644 src/hdr10plus/tests.rs delete mode 100644 src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index c585038..705a58a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,16 @@ [package] name = "hdr10plus_parser" -version = "0.2.9" +version = "0.3.0" authors = ["quietvoid"] edition = "2018" license = "MIT" -[lib] -name = "tests" -path = "src/lib.rs" - [dependencies] -structopt = "0.3.11" -bitreader = "0.3.2" -serde = "1.0.104" -serde_json = "1.0.48" -indicatif = "0.14.0" +structopt = "0.3.20" +serde = "1.0.117" +serde_json = "1.0.59" +indicatif = "0.15.0" read-byte-slice = "0.1.2" -regex = "1.3.5" -ansi_term = "*" +regex = "1.4.1" +ansi_term = "0.12.1" +deku = "0.8.0" diff --git a/assets/ToS-s15.h265 b/assets/ToS-s15.h265 index ea3c1a14b8d2054d648a1c0d340819a1b517c648..5c177b93e00d9dc7f334d705726943e087dd0e37 100644 GIT binary patch delta 845 zcmZ8gOH9;281A&YxIDxd1rZ^R7!lDSrMo=MDuRic5DvzJ28qnJvuvU5ES+|N1IcN#ns7Ja93=lhKPQs=sbGozsU{2Y6K;> zcE5j}vqnk|7Uc>A*duUJp=&eoIcBE(=wy#RURiav@n1ys7K|3+K)2wgR0jV zunp%^w7{rEgkzgbWV>XocBL9}eP#x6&4kv{-id>d*k0gMVzFXSfJTn(+5ri|sFlU1 zNlYlK%T?`|7Pb1KUG7TnWC0feCE(t!a=FC>b{Y6Ym;*Gx@ToV!vRys$Mxs65;dWxM zIgJH#fQemVL{Og1U`Bmsj)*C{h~j@Iu~hf0^}c*seW0rL`HSg~$%dQ9%V0KCXeGIO3B$5c+tYRn vut`(c`Zk^(k5ElqkD=vT3@c@TLn>N~LH!EQs3wOa*qge#^G>#3%l_hTM)3*unYO*)F6bD@BlmRMM2JDH1!oGsv{FJIl=M z7JP8GwSknT2Dnf7&=Ax3)U*$_hQ!3Kr23>u^+AXjV|>x1e}E)5;+l(b&*MW!2yK+7g=K~WwA+LU0fMx zxO1TqH<^B>H?ei8mG3I>a>p7pHGc1<52CM%U#63kokmLm_7AjF_Ic^r5ou%o;jz&J z>sKGWR#uvl15EmyFD_PB1b6pGB>KrOHTRo`x4#&_^>=CG$>~`!F5^hLV3-;f67f#V zVW~&#mIN-ImSPD_PRnsE(KnGYa+-C?nVc9tbqe?Ph&{sOL_CJmhC8`@@5*zzLRRJS zmSsAM5GOMF;Gl#}y{ManawQPep{wWuB~psThy$2k{`yl0V{feT0=HNk!)l98Y|QcM@QtU7C}u1?Q_rvrPg zbYaRd-v5uw$QiD}_w?e7J>{iP&R4mSqnykIAC!7A?KbC3={7BfGnQ%DS=F_TS%s!e z+g4UJt&Af4%Q@G|E8i5%`8jA>WT#~6tmv)XuyqGtl)WR9lR0Pk6@uV19r)TqO z_@&UaW(zzf?}T4R@@GGWTTplPuX!0AsuBp7;jLEGGFUYcy*gu68c34SniGA;_pVd* zQhBo%j-b24CyhHRN8X*=oGfgf-?{Sp?#{!-g|C;lx@VT#m_&o15w*6Zb}IR)^kKdc z&)lHqi(&K^VFyRc9%q^P1&T+5wC2yA=V$;}H0co*hLRpK%)Ae^Z~B0-56YSkGyamU zZMq%0sr@f>3+VQS5bxhnubuqU?UbI~4uc*wq^^n|;+#{ff> zdlg_q3jpnys-R;4fha)37{GWE;Bgt4k0Epx4sJo-l}@`*0FafId@X zyrw7h>^%Vb_4tF!b#1}xH|%eI8tGUD2$^1E*Ju@%4FS~Cr|k_YxF%nns-E2m zi1Fk#{(%UJhzC7+F(7zRFN!BU2@2xTvzK@fk4e3QLkh$rXCwzx&R+Hzv?MHW>U*@!_GbE@!u?ciwv{`{FPyjgObGI~hDa_}YCw zJ`L*J;K=p<_xrJre!cPPoo9df^0|-ye)XHb&h2KK8*Fvl>Z)L)lUqj_XKTathqFyS z6S*eD%l!}P-W&2=``;R1NPu1i2QmX6jq9$Rcx9%aw8RnXEnwIiH5#-3_uaT$U=b^JK_Gc;}riLpVO#-C!+ zwz|ki_@!$n*~E!j@lZM?3ZJjD9cx)*xUF$&M|3aWIAXomHLJ{&S8ArJJR`3QWkZ>d zQl=Z*1}?qLM{Ht!o~<7r^+Kn7K02ADyIU!(3(8eOsyt=E1X1zmg$EnWa$QK!C4%Ka zD+hCJS@3ZIp;ME5jXV)mWp;RD8ZJ#UF|HPkR8U(b0xuDba-NB%QM==~ye;Tex&p^f z3@e2%VGg38YHJ*vsKlK17^@mSHI~)7;TP2$-XapVpf*wlC9jORDCig%8Tam^hFlcF zVm&BSOVqmPwS24v1?c3Str-Gd*x|m?5?R_{UaCgPHstG+10VQOfbF8FI=8*0^%MXc zbb=!>NOH+!Xmg;6oR=;4`jX1GXq8hk&|B1qOziT|E7vjxGM0q*mFxvDx)4;l)&W~6 zfWmC|)lXS5ZxEy84rv&ovanAG0nfaiHl^-B6#PXESh>zs@;{QOY}|qZdW4`GRdg#D zSkp{9hWpx>Q0itH{jQapDnOuf2~h)BbZ*BJY(1+LWWF8aoq=(p!Iq5^Y+34h26s#c zJ6^PrDQm@c6g606JF>%0BdYl&#XX8=we+k| zb1DTU%7QlA%fes-vV|m*<)v9U-nM3fB&JNdCFx`?-2{?Jo^1_Nwk=IHT(k2{X02pDahz_iInLqOP$7tC79#5SiAp)8vvt_O>83KyI$gsxV6pKNpfl^lwSW)1#Ffs}0;PwULZb{~&UbWEm>mdYh0Z*d z#?GtST0lg77RgbX0kLM9aS~aBA>ha8%UP>2;ovo49aD*TjHr(32SP+QrZ?ZV+*(he z6Ng#?^T19ObGT5|^flmCc;BtUhQ;{kN6;|c=*9{SeP5a?_HLZ1WEYq#R22k{qoZQM z=*vM&SvZXO1wjW8Q$+EC(}km1LkS1emBtK4_jv6gZM|BKj-}WO^v6EB$_PU3-hHTI zrO+WV7%FTBX(S9q`wtt3ORueGmmRLt|pHrgTuH^ZQ1@7MR%zOZb*{VBzZPTzDovIl9d;dl^>FoKa)du z(IVWHZi*|2 zZ~5fY?eCA=_1Z(Qu~+^teQ5U9&2O{)v`KR7>g)R}VMcv*p!$)Q4pJX}@gVK}za6Cg c;PL_5!5arCSAO1KdF1K+bvL~5AKmTtACK@=s{jB1 literal 0 HcmV?d00001 diff --git a/assets/ToS-s58.h265 b/assets/ToS-s58.h265 new file mode 100644 index 0000000000000000000000000000000000000000..1166a39761e8822217bcaace2b06f24867b83d81 GIT binary patch literal 2856 zcmaJ@O^75#7Orw;Kw;H`zZAP`;6YoQsL9IynV#8AP+L(!2QLl_<19u+Mped6W=3>G zWOdho*v^1n{YL~v#Dku^C}~h##fwb)y~wO`bm=aN%=Z)V;{AN@ zW%PQz{sa9#^!N9#W4+#y-plmBfA@{IZs#d}At?4`G;H{O0c{p=_$jgM!s zyVrlX|AqTx`~avk{bT#x?|;YN|KWyD?|Ah4&!7I_>hoXzd}cS@SZ6EaMwdAoo!Y#Q zake^KyFcCFQ?Z%K4S71h#Inv7OC9-C}M-p8J7%AlojYDYMAoIPIC;vxil`oszHXK36M z5@UllwLi_IZFHWE@Jm)tv56Cv;-PR#>V!`DY;-D3b~h7R7nCc7R9V7;38LiD3lBD$ zF#DtRKx((Lfs)Lfc+Vq7I^si3w>1YRH--lYAmaC%`d1qyhS8zL9HhYN?sasLC`TU zGVa_*4Y|mL#d=VvmZ)^zY578m*&x(Meq*YGIKyOhYGO^1;r(8`L$XF8IRk9Pn z=t5BHN(XGA0CKb4RX<_*yhe(U`;)38SX1%LZRzv^t)1SssMr3B}5Hi(YY;8u=T7`kojhecM8Ud8e7&+ zvSq2O8Qd`~?0DWprl=I#QPg0OZOIlpwJ7Ho756Bf)zY(EjY}ghWXb7-d0}GM!bC83 zDx?WMdQ~FpdWNmSpt+QA<($W4xHcv5L7>91gk&aWD$0mM0ZZe3sk{fEmW!zL!R4Ky z9C#IFm?M|grcC=1$bFAIYW$QF`JmX~Jbc-xu@l9({*mZX!JbQ4G>S-Lq)*tRs4 zg{2LU)(2$~j1MAszTcmzCW8>fiSb-OD9^>vRRzfW_KRfX=iPR{}ol5?44=36vgYa*Z;GIp5KB zZgwD$B|7tX5<9PKDghDoStLhE3dEXe%1LAmhJYWVFK3O$goD?FbxbAVF``P8@0p%mX`R%;7>+(bs@m;eERb8y4fE8$rWly&Wqw^nGE<*t>D2l3idf zS7i`5j*f~2qb~7X%$ZOdiDxPUnth4J8~=I+kKD&>sir zN+Srh*X~0VON9=R!BAmaNF!k=+Hcr6Tsmzv!#wC{%twyeVK+sEEr_6<9n{IBrAl;i zvlBC!V{~@gmu`o-CEQDVm1!v804l9$XyPv11FmC&7E^NBejXJ^6qFvyrkY74nn*v3 zDV=DA8w3g-KPS{nHE)p`TZI;O9|~z5Y>Lr#3I&_~480ef5<1aOI}K-f*yYcCh#F z!3%E=F8zIQ>6^i&tAoq84=(?Cu-AKjfB(OWdlKF~GPTnG_)mj>i06KKr}_4e)n`BT z&+Y$s=ITFtcYU3{e%t%^yxQH++I!ls&znB{X!~Es?tI~1*oarS|9c*py>{d4>>zEg zck{|i2P^chbXW6?qKDyCl1zK|F_@hZneJv DNl0z3 literal 0 HcmV?d00001 diff --git a/assets/ToS-s59.h265 b/assets/ToS-s59.h265 new file mode 100644 index 0000000000000000000000000000000000000000..4ed4f500b61b4abde611405182dc921f3fccd97c GIT binary patch literal 2858 zcmaJ@Nr)sx6s>Y*K*8nUO5qZC&=x0Zva*-y8BGvdQ9W&DChzC7+Q4qYS7r}$zML|Kl>Dh}HnfCq2ta22(o2K$F@qhf~{h!(E_4*I= zukP>fU%`64BfVGY2miZoy>nF$x(ECH|0zB=^3`5?y?X22$I>s3($Vu z$VLg%wQT~I-ew~nDa4!WVD{QBajN4ndS+PBzA>noo^om9F`DHAl3_ge|D`gh9zmW6le@22RFZ_~;=Q zxv)473f&Tw&O0q1Ye5M*d6{X7gcp9eFSSIK)|r>8RuFu+7DU0H*MOC4L#6m5iOxn7G|(djU8}r3 z!N8h&+A`c%#)LxG(-?Q9+*APqZAi!(z@mFwo?z=)r6BXo7|#@p6E#fMPqJmJs~N&E zE$n#SM5d?|+fg)Nk!{HqJGCh17Zmqsp4HN`T#ZX3&u7W$gn40N+QLLIb}Ez!F?v;^ z>UsuKVK7`uxN^>8FD-~tLp@F6GzEs`=P|HKq`rz`;Q4YL{GR#p+ z>*v%8Y?K9UwwH~80jh-}ljo&dIo`Hrf+8kNx+UpkCfx**NtSL76Sgf)W#MT9r1e2r zB;$h!p6@svXpUQswg?z)oxrxqMngc@ju*^o!o)VG7NISm&}CImX?IY-K)h3mT`;x6 zNH>_e2o4<55?f{L*!Hx=Ga!o;(2Oa81`z?z*~Td%blqA-Nb%WthW-%B%nYL~1!-ph zrHKn8VAxu0;C53QXPvGP8n9UV3DB9g;z}TfUE&I7DuLF+O|H=fG3PtF&dm-4vczN_ zPvYd2O(h_rIg8{dNr6~1O*x6I!4mLe%;l`n*l>uNu#T-nJXTc8bPFM(8{3<2TW+nV z)QLkcfq7u3j5S=SDta4mE4*({!C*%W3 zFnV(kQ{)b7enHR$#N<)D;B@Y2*HFO$b)~U`F+E;;NE@$~t79ql0`qZzt~7#Bd$}FD zSSn1242BxpLK+1_)BeN8<jtU*@UJ_i;Yah+J>@C<~lG9wP;92}?K&)dEf~i2@g91b7A{a58lm}d5 zT2Kiz<6jKz#qXV?Tc7vt@AZ%3b7~Wk_!ZR?AFo_H*c%S^o*L|ZKX~cw!Nq3>7k?aF zyfk?Eroqd%5B7R5?(hG;_)@~NN6uFIpWZfjUcB(vd(BU`R$u(pKfC|unM>dH?)V{n z^TrSFdVS%&y<_=%?Z=;Ne|PMbm+oF(zf^U^k=Yy9yvYtQ$C>L^UO89^z541<^?lDB orat=2VcI)?J52lj-XYrlYlkSW`1xSvvBwYAUHSBXbT`<403}~*DgXcg literal 0 HcmV?d00001 diff --git a/src/hdr10plus.rs b/src/hdr10plus.rs deleted file mode 100644 index 3cf7951..0000000 --- a/src/hdr10plus.rs +++ /dev/null @@ -1,709 +0,0 @@ -use bitreader::BitReader; -use indicatif::{ProgressBar, ProgressStyle}; -use read_byte_slice::{ByteSliceIter, FallibleStreamingIterator}; -use serde_json::{json, Value}; -use std::fs::File; -use std::io::{stdout, BufRead, BufReader, BufWriter, Write}; -use std::path::PathBuf; - -use ansi_term::Colour::{Blue, Green, Red, Yellow}; - -pub fn process_file( - is_stdin: bool, - input: &PathBuf, - output: PathBuf, - verify: bool, - force_single_profile: bool, -) { - let final_metadata: Vec; - - match parse_metadata(is_stdin, input, verify) { - Ok(vec) => { - //Match returned vec to check for --verify - if vec[0][0] == 1 && vec[0].len() == 1 { - println!("{}", Blue.paint("Dynamic HDR10+ metadata detected.")); - } else { - final_metadata = llc_read_metadata(vec); - //Sucessful parse & no --verify - if !final_metadata.is_empty() { - write_json(output, final_metadata, force_single_profile) - } else { - println!("{}", Red.paint("Failed reading parsed metadata.")); - } - } - } - Err(e) => println!("{}", e), - } -} - -pub struct Metadata { - pub bezier_curve_data: Vec, - pub knee_x: u16, - pub knee_y: u16, - pub average_maxrgb: u32, - pub maxscl: Vec, - pub distribution_index: Vec, - pub distribution_values: Vec, - pub targeted_system_display_maximum_luminance: u32, - pub num_windows: u8, -} - -pub fn parse_metadata( - is_stdin: bool, - input: &PathBuf, - verify: bool, -) -> Result>, std::io::Error> { - //BufReader & BufWriter - let stdin = std::io::stdin(); - let mut reader = Box::new(stdin.lock()) as Box; - let bytes_count; - - let pb: ProgressBar; - - if is_stdin { - pb = ProgressBar::hidden(); - } else { - let file = File::open(input).expect("No file found"); - - //Info for indicatif ProgressBar - let file_meta = file.metadata(); - bytes_count = file_meta.unwrap().len() / 100_000_000; - - reader = Box::new(BufReader::new(file)); - - if verify { - pb = ProgressBar::hidden(); - } else { - pb = ProgressBar::new(bytes_count); - pb.set_style( - ProgressStyle::default_bar() - .template("[{elapsed_precise}] {bar:60.cyan} {percent}%"), - ); - } - } - - //Byte chunk iterator - let mut iter = ByteSliceIter::new(reader, 100_000); - - //Bitstream blocks for SMPTE 2094-40 - let header: Vec = vec![0, 0, 1, 78, 1, 4]; - let mut current_sei: Vec = Vec::new(); - - println!( - "{}", - Blue.paint("Parsing HEVC file for dynamic metadata... ") - ); - stdout().flush().ok(); - - let mut final_sei_list: Vec> = Vec::new(); - - let mut dynamic_hdr_sei = false; - let mut dynamic_detected = false; - let mut cur_byte = 0; - - //Loop over iterator of byte chunks for faster I/O - while let Some(chunk) = iter.next()? { - for byte in chunk { - let byte = *byte; - - cur_byte += 1; - - let tuple = process_bytes( - &header, - byte, - &mut current_sei, - dynamic_hdr_sei, - &mut final_sei_list, - ); - dynamic_hdr_sei = tuple.0; - - if tuple.1 { - dynamic_detected = true; - } - } - - if !dynamic_detected { - pb.finish_and_clear(); - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "File doesn't contain dynamic metadata, stopping.", - )); - } else if verify { - pb.finish_and_clear(); - - let verified = vec![vec![1]]; - - return Ok(verified); - } - - if cur_byte >= 100_000_000 { - pb.inc(1); - cur_byte = 0; - } - } - - pb.finish_and_clear(); - - Ok(final_sei_list) -} - -fn process_bytes( - header: &[u8], - byte: u8, - current_sei: &mut Vec, - mut dynamic_hdr_sei: bool, - final_sei_list: &mut Vec>, -) -> (bool, bool) { - let mut dynamic_detected = false; - - current_sei.push(byte); - if dynamic_hdr_sei { - let last = current_sei.len() - 1; - - if current_sei[last - 3] == 128 - && current_sei[last - 2] == 0 - && current_sei[last - 1] == 0 - && (current_sei[last] == 1 || current_sei[last] == 0) - { - let final_sei = ¤t_sei[7..current_sei.len() - 3]; - - //Push SEI message to final vec - final_sei_list.push(final_sei.to_vec()); - - //Clear current vec for next pattern match - current_sei.clear(); - dynamic_hdr_sei = false; - dynamic_detected = true; - } - } else if byte == 0 || byte == 1 || byte == 78 || byte == 4 { - for i in 0..current_sei.len() { - if current_sei[i] == header[i] { - if current_sei == &header { - dynamic_hdr_sei = true; - break; - } - } else if current_sei.len() < 3 { - current_sei.clear(); - break; - } else { - current_sei.pop(); - break; - } - } - } else if !current_sei.is_empty() { - current_sei.clear(); - } - - (dynamic_hdr_sei, dynamic_detected) -} - -pub fn llc_read_metadata(input: Vec>) -> Vec { - let mut correct_indexes; - let expected_num_percentiles = 9; - - print!("{}", Blue.paint("Reading parsed dynamic metadata... ")); - stdout().flush().ok(); - - let mut complete_metadata: Vec = Vec::new(); - - //Loop over lines and read metadata, HDR10+ LLC format - for data in input.iter() { - let bytes = &data[..]; - - let mut reader = BitReader::new(bytes); - let mut temp_reader; - - reader.read_u8(8).unwrap(); //country_code - reader.read_u16(16).unwrap(); //terminal_provider_code - reader.read_u16(16).unwrap(); //terminal_provider_oriented_code - let application_identifier = reader.read_u8(8).unwrap(); //application_identifier - let application_version = reader.read_u8(8).unwrap(); //application_version - - // SMPTE ST-2094 Application 4, Version 1 - assert_eq!(application_identifier, 4); - assert_eq!(application_version, 1); - - let num_windows = reader.read_u8(2).unwrap(); - - // Versions up to 1.2 should be 1 - for _w in 1..num_windows { - println!("num_windows > 1"); - panic!("The value of num_windows shall be 1 in this version"); - } - - let targeted_system_display_maximum_luminance = reader.read_u32(27).unwrap(); - let targeted_system_display_actual_peak_luminance_flag = reader.read_u8(1).unwrap(); - - // The value of targeted_system_display_maximum_luminance shall be in the range of 0 to 10000, inclusive - assert!(targeted_system_display_maximum_luminance <= 10000); - - // For LLC, when 0, skip 1 byte - if targeted_system_display_maximum_luminance == 0 - || targeted_system_display_maximum_luminance == 8192 - { - temp_reader = reader.relative_reader(); - if temp_reader.read_u8(8).unwrap() != 0 - && targeted_system_display_maximum_luminance == 8192 - { - } else { - reader.read_u32(8).unwrap(); - } - } - - let mut targeted_system_display_actual_peak_luminance: Vec> = Vec::new(); - - // Versions up to 1.2 should be 0 - if targeted_system_display_actual_peak_luminance_flag == 1 { - let num_rows_targeted_system_display_actual_peak_luminance = reader.read_u8(5).unwrap(); - let num_cols_targeted_system_display_actual_peak_luminance = reader.read_u8(5).unwrap(); - - for i in 0..num_rows_targeted_system_display_actual_peak_luminance { - targeted_system_display_actual_peak_luminance.push(Vec::new()); - - for _j in 0..num_cols_targeted_system_display_actual_peak_luminance { - targeted_system_display_actual_peak_luminance[i as usize] - .push(reader.read_u8(4).unwrap()); - } - } - - println!("Targeted system display actual peak luminance flag enabled"); - panic!("The value of targeted_system_display_actual_peak_luminances shall be 0 in this version"); - } - - let mut average_maxrgb: u32 = 0; - let mut maxscl: Vec = Vec::new(); - let mut original_maxscl: Vec = Vec::new(); - - let mut distribution_index: Vec = Vec::new(); - let mut distribution_values: Vec = Vec::new(); - - for _w in 0..num_windows { - for i in 0..3 { - let mut maxscl_high = reader.read_u32(17).unwrap(); - - if i == 0 { - temp_reader = reader.relative_reader(); - let skipped_byte = temp_reader.read_u32(8).unwrap(); - let first_temp = temp_reader.read_u32(17).unwrap(); - - if maxscl_high == 0 - && skipped_byte == 1 - && first_temp >= 65536 - && first_temp <= 100_000 - && targeted_system_display_maximum_luminance != 8192 - { - reader.read_u32(8).unwrap(); - } else if maxscl_high == 1 - && (targeted_system_display_maximum_luminance == 0 - || targeted_system_display_maximum_luminance % 32 == 0) - { - reader.read_u32(1).unwrap(); - maxscl_high = reader.read_u32(7).unwrap(); - } else if maxscl_high == 32768 || maxscl_high == 65536 || maxscl_high == 98304 { - if maxscl_high >= 98304 && targeted_system_display_maximum_luminance == 8192 - { - if reader.remaining() == 353 && reader.position() == 103 { - } else { - maxscl_high -= 98304; - } - - if skipped_byte == 1 { - reader.read_u32(8).unwrap(); - } - } else if maxscl_high != 32768 - && maxscl_high != 65536 - && maxscl_high != 98304 - { - reader.read_u32(8).unwrap(); - } - } else if maxscl_high >= 98304 - && targeted_system_display_maximum_luminance == 8192 - { - if (reader.remaining() == 353 || reader.remaining() == 345) - && reader.position() == 103 - { - } else { - maxscl_high -= 98304; - } - } - - maxscl.push(maxscl_high); - } else if i == 1 { - temp_reader = reader.relative_reader(); - let second_temp = temp_reader.read_u32(8).unwrap(); - - if maxscl[i - 1] == 0 - || maxscl[i - 1] == 32768 - || maxscl[i - 1] == 65536 - || maxscl[i - 1] == 98304 - { - if maxscl_high >= 65536 { - let temp: u32 = maxscl_high - 65536; - - if temp == 0 && second_temp < 4 { - reader.read_u32(8).unwrap(); - } - - if (temp != 0 - && (targeted_system_display_maximum_luminance == 8192 - || maxscl[i - 1] == 32768 - || maxscl[i - 1] == 65536 - || maxscl[i - 1] == 98304)) - || ((targeted_system_display_maximum_luminance >= 4096 - && targeted_system_display_maximum_luminance < 8192) - && (reader.remaining() == 328 || reader.remaining() == 320)) - || (temp == 0 - && targeted_system_display_maximum_luminance == 8192 - && reader.position() == 136) - || (reader.remaining() == 320 && reader.position() == 120) - || (reader.remaining() == 368 && reader.position() == 128) - || (reader.remaining() == 376 && reader.position() == 136) - { - maxscl.push(maxscl_high); - } else { - maxscl.push(temp); - } - } else if (maxscl_high == 3 - && (targeted_system_display_maximum_luminance == 0 - || targeted_system_display_maximum_luminance % 32 == 0)) - || (reader.position() != 128 - && targeted_system_display_maximum_luminance != 8192 - && (maxscl[i - 1] == 32768 - || maxscl[i - 1] == 65536 - || maxscl[i - 1] == 98304) - && maxscl_high == 768) - || reader.remaining() > 336 - || (reader.remaining() == 336 - && targeted_system_display_maximum_luminance == 8192) - { - maxscl.push(reader.read_u32(8).unwrap()); - } else { - maxscl.push(maxscl_high); - } - } else if maxscl_high == 0 { - if second_temp < 4 { - reader.read_u32(8).unwrap(); - } - - maxscl.push(maxscl_high); - } else if maxscl_high == 3 - && (reader.remaining() == 344 - || reader.remaining() == 336 - || reader.remaining() == 328) - { - if maxscl[i - 1] < 2048 { - if maxscl[i - 1] >= 128 - && maxscl[i - 1] < 2048 - && maxscl[i - 1] % 128 == 0 - { - maxscl_high = reader.read_u32(8).unwrap(); - } - - maxscl.push(maxscl_high); - } else { - maxscl.push(reader.read_u32(8).unwrap()); - } - } else { - maxscl.push(maxscl_high); - } - } else if maxscl[i - 1] == 0 { - if (maxscl_high == 6 && reader.remaining() != 303) - || maxscl[0] == 32768 - || maxscl[0] == 65536 - || maxscl[0] == 98304 - { - maxscl.push(reader.read_u32(8).unwrap()); - } else { - maxscl.push(maxscl_high); - } - } else { - temp_reader = reader.relative_reader(); - let third_temp = temp_reader.read_u32(8).unwrap(); - - if maxscl_high == 6 && (reader.remaining() == 319 || reader.remaining() == 311) - { - if maxscl[i - 1] <= 2048 && third_temp != 6 { - maxscl.push(reader.read_u32(8).unwrap()); - } else { - if maxscl[i - 1] > 2048 && maxscl[i - 1] % 256 == 0 { - maxscl_high = reader.read_u32(8).unwrap(); - } else { - reader.read_u32(8).unwrap(); - } - - maxscl.push(maxscl_high); - } - } else { - if (maxscl_high == 0 && maxscl[i - 1] > 2048 && maxscl[i - 1] <= 4096) - || (maxscl_high == 0 && third_temp == 6 && reader.remaining() == 311) - { - reader.read_u32(8).unwrap(); - } - - maxscl.push(maxscl_high); - } - } - - original_maxscl.push(maxscl_high); - } - - // Shall be under 100000. - maxscl.iter().for_each(|&v| assert!(v <= 100_000)); - - if maxscl[2] == 0 { - temp_reader = reader.relative_reader(); - - // Skip a byte - temp_reader.read_u32(8).unwrap(); - - // Average max rgb - let temp_avg_maxrgb = temp_reader.read_u32(17).unwrap(); - - let mut future_reader = temp_reader.relative_reader(); - - // Skip another byte - let skipped_byte = future_reader.read_u32(8).unwrap(); - - if future_reader.read_u8(4).unwrap() == expected_num_percentiles - || temp_reader.read_u8(4).unwrap() == expected_num_percentiles - { - if skipped_byte == 144 && (temp_avg_maxrgb >= 3072 && temp_avg_maxrgb <= 3087) { - } else { - reader.read_u32(8).unwrap(); - } - } else if (temp_reader.remaining() == 322 && temp_reader.position() == 29) - || (temp_reader.remaining() == 330 && temp_reader.position() == 29) - { - reader.read_u32(8).unwrap(); - } - } - - // Read average max RGB - average_maxrgb = reader.read_u32(17).unwrap(); - - temp_reader = reader.relative_reader(); - - // Try to skip a byte - temp_reader.read_u32(8).unwrap(); - - // If the percentiles are correct, go ahead and use next value - if temp_reader.read_u8(4).unwrap() == expected_num_percentiles - || temp_reader.read_u8(4).unwrap() == 10 - { - average_maxrgb = reader.read_u32(8).unwrap(); - } - - // Shall be under 100000 - assert!(average_maxrgb <= 100_000); - - let num_distribution_maxrgb_percentiles = reader.read_u8(4).unwrap(); - - // The value of num_distribution_maxrgb_percentiles shall be 9 - // or 10 if your name is Amazon, apparently - if num_distribution_maxrgb_percentiles == 9 { - correct_indexes = vec![1, 5, 10, 25, 50, 75, 90, 95, 99]; - } else if num_distribution_maxrgb_percentiles == 10 { - correct_indexes = vec![1, 5, 10, 25, 50, 75, 90, 95, 98, 99]; - } else { - panic!( - "Invalid number of percentiles: {}", - num_distribution_maxrgb_percentiles - ); - } - - for _i in 0..num_distribution_maxrgb_percentiles { - distribution_index.push(reader.read_u8(7).unwrap()); - distribution_values.push(reader.read_u32(17).unwrap()); - } - - // Distribution indexes should be equal to: - // 9 indexes: [1, 5, 10, 25, 50, 75, 90, 95, 99] - // 10 indexes: [1, 5, 10, 25, 50, 75, 90, 95, 98, 99] - assert_eq!(distribution_index, correct_indexes); - - reader.read_u16(10).unwrap(); //fraction_bright_pixels, unused for now - } - - let mastering_display_actual_peak_luminance_flag = reader.read_u8(1).unwrap(); - let mut mastering_display_actual_peak_luminance: Vec> = Vec::new(); - - // Versions up to 1.2 should be 0 - if mastering_display_actual_peak_luminance_flag == 1 { - let num_rows_mastering_display_actual_peak_luminance = reader.read_u8(5).unwrap(); - let num_cols_mastering_display_actuak_peak_luminance = reader.read_u8(5).unwrap(); - - for i in 0..num_rows_mastering_display_actual_peak_luminance { - mastering_display_actual_peak_luminance.push(Vec::new()); - - for _j in 0..num_cols_mastering_display_actuak_peak_luminance { - mastering_display_actual_peak_luminance[i as usize] - .push(reader.read_u8(4).unwrap()); - } - } - - println!("Mastering display actual peak luminance flag enabled"); - panic!("The value of mastering_display_actual_peak_luminance_flag shall be 0 for this version"); - } - - let mut knee_point_x: u16 = 0; - let mut knee_point_y: u16 = 0; - - let mut bezier_curve_anchors: Vec = Vec::new(); - - for _w in 0..num_windows { - let tone_mapping_flag = reader.read_u8(1).unwrap(); - - if tone_mapping_flag == 1 { - knee_point_x = reader.read_u16(12).unwrap(); - knee_point_y = reader.read_u16(12).unwrap(); - - // The value of knee_point_x shall be in the range of 0 to 1, and in multiples of 1/4095 - assert!(knee_point_x <= 4095); - assert!(knee_point_y <= 4095); - - let num_bezier_curve_anchors = reader.read_u8(4).unwrap(); - - for _i in 0..num_bezier_curve_anchors { - bezier_curve_anchors.push(reader.read_u16(10).unwrap()); - } - } - } - - let color_saturation_mapping_flag = reader.read_u8(1).unwrap(); - - // Versions up to 1.2 should be 0 - if color_saturation_mapping_flag == 1 { - println!("Color saturation mapping flag enabled"); - panic!("The value of color_saturation_mapping_flag shall be 0 for this version"); - } - - /* Debug - println!("NumWindows: {}, Targeted Display Luminance: {}", num_windows, targeted_system_display_maximum_luminance); - println!("AverageRGB: {}, MaxScl: {:?}", average_maxrgb, maxscl); - println!("NumPercentiles: {}\nDistributionIndex: {:?}\nDistributionValues: {:?}", num_distribution_maxrgb_percentiles, distribution_index, distribution_values); - println!("Knee_X: {}, Knee_Y: {}, Anchors: {:?}\n", knee_point_x, knee_point_y, bezier_curve_anchors); - */ - - let meta = Metadata { - num_windows, - targeted_system_display_maximum_luminance, - average_maxrgb, - maxscl, - distribution_index, - distribution_values, - knee_x: knee_point_x, - knee_y: knee_point_y, - bezier_curve_data: bezier_curve_anchors, - }; - - complete_metadata.push(meta); - } - - println!("{}", Green.paint("Done.")); - - complete_metadata -} - -fn write_json(output: PathBuf, metadata: Vec, force_single_profile: bool) { - let save_file = File::create(output).expect("Can't create file"); - let mut writer = BufWriter::with_capacity(10_000_000, save_file); - - print!("{}", Blue.paint("Writing metadata to JSON file... ")); - stdout().flush().ok(); - - // Get highest number of anchors (should be constant across frames other than empty) - let num_bezier_curve_anchors = match metadata.iter().map(|m| m.bezier_curve_data.len()).max() { - Some(max) => max, - None => 0, - }; - - // Use max with 0s instead of empty - let replacement_curve_data = vec![0; num_bezier_curve_anchors]; - let mut warning = None; - - let mut profile = "A"; - - let frame_json_list: Vec = metadata - .iter() - .map(|m| { - // Profile A, no bezier curve data - if m.targeted_system_display_maximum_luminance == 0 && m.bezier_curve_data.is_empty() && num_bezier_curve_anchors == 0 { - json!({ - "LuminanceParameters": { - "AverageRGB": m.average_maxrgb, - "LuminanceDistributions": { - "DistributionIndex": m.distribution_index, - "DistributionValues": m.distribution_values, - }, - "MaxScl": m.maxscl - }, - "NumberOfWindows": m.num_windows, - "TargetedSystemDisplayMaximumLuminance": m.targeted_system_display_maximum_luminance - }) - } else { // Profile B - if profile != "B" { - profile = "B"; - } - - // Don't insert empty vec when profile B and forcing single profile - let bezier_curve_data = if force_single_profile && m.bezier_curve_data.is_empty() && num_bezier_curve_anchors != 0 { - if warning.is_none() { - warning = Some(format!("{}", Yellow.paint("Forced profile B."))); - } - - &replacement_curve_data - } else { - if warning.is_none() && m.bezier_curve_data.is_empty() && num_bezier_curve_anchors != 0 { - warning = Some(format!("{} Different profiles appear to be present in the metadata, this can cause errors when used with x265.\nUse {} to \"fix\".", Yellow.paint("Warning:"), Yellow.paint("--force-single-profile"))); - } - - &m.bezier_curve_data - }; - - json!({ - "BezierCurveData": { - "Anchors": bezier_curve_data, - "KneePointX": m.knee_x, - "KneePointY": m.knee_y - }, - "LuminanceParameters": { - "AverageRGB": m.average_maxrgb, - "LuminanceDistributions": { - "DistributionIndex": m.distribution_index, - "DistributionValues": m.distribution_values, - }, - "MaxScl": m.maxscl - }, - "NumberOfWindows": m.num_windows, - "TargetedSystemDisplayMaximumLuminance": m.targeted_system_display_maximum_luminance - }) - } - - }) - .collect::>(); - - let json_info = json!({ - "HDR10plusProfile": profile, - "Version": "1.0", - }); - - let final_json = json!({ - "JSONInfo": json_info, - "SceneInfo": frame_json_list - }); - - assert!(writeln!( - writer, - "{}", - serde_json::to_string_pretty(&final_json).unwrap() - ) - .is_ok()); - - println!("{}", Green.paint("Done.")); - - if warning.is_some() { - println!("{}", warning.unwrap()); - } - - writer.flush().ok(); -} diff --git a/src/hdr10plus/metadata.rs b/src/hdr10plus/metadata.rs new file mode 100644 index 0000000..5bdbcce --- /dev/null +++ b/src/hdr10plus/metadata.rs @@ -0,0 +1,224 @@ +use ansi_term::Colour::Yellow; +use deku::prelude::*; +use serde_json::{json, Value}; + +const DISTRIBUTION_INDEXES_9: &[u8] = &[1, 5, 10, 25, 50, 75, 90, 95, 99]; +const DISTRIBUTION_INDEXES_10: &[u8] = &[1, 5, 10, 25, 50, 75, 90, 95, 98, 99]; + +#[derive(Debug, DekuRead, Clone)] +#[deku(endian = "big")] +pub struct Metadata { + #[deku(bits = "8")] + pub country_code: u8, + + #[deku(bits = "16")] + pub terminal_provider_code: u16, + + #[deku(bits = "16")] + pub terminal_provider_oriented_code: u16, + + #[deku(bits = "8")] + pub application_identifier: u8, + + #[deku(bits = "8")] + pub application_version: u8, + + #[deku(bits = "2")] + pub num_windows: u8, + + #[deku(bits = "27")] + pub targeted_system_display_maximum_luminance: u32, + + #[deku(bits = "1")] + pub targeted_system_display_actual_peak_luminance_flag: u8, + + #[deku(count = "3", bits = "17")] + pub maxscl: Vec, + + #[deku(bits = "17")] + pub average_maxrgb: u32, + + #[deku(bits = "4")] + pub num_distribution_maxrgb_percentiles: u8, + + #[deku(count = "num_distribution_maxrgb_percentiles")] + pub distribution_maxrgb: Vec, + + #[deku(bits = "10")] + pub fraction_bright_pixels: u16, + + #[deku(bits = "1")] + pub mastering_display_actual_peak_luminance_flag: u8, + + #[deku(bits = "1")] + pub tone_mapping_flag: u8, + + #[deku(bits = "12")] + pub knee_point_x: u16, + + #[deku(bits = "12")] + pub knee_point_y: u16, + + #[deku(bits = "4")] + pub num_bezier_curve_anchors: u8, + + #[deku(count = "num_bezier_curve_anchors", bits = "10")] + pub bezier_curve_anchors: Vec, + + #[deku(bits = "1")] + pub color_saturation_mapping_flag: u8, +} + +#[derive(Debug, PartialEq, DekuRead, Clone)] +#[deku(endian = "endian", ctx = "endian: deku::ctx::Endian")] +pub struct DistributionMaxRgb { + #[deku(bits = "7")] + percentage: u8, + #[deku(bits = "17")] + percentile: u32, +} + +impl Metadata { + pub fn validate(&self) { + // SMPTE ST-2094 Application 4, Version 1 + assert_eq!(self.application_identifier, 4); + assert_eq!(self.application_version, 1); + + // The value of targeted_system_display_maximum_luminance shall be in the range of 0 to 10000, inclusive + assert!(self.targeted_system_display_maximum_luminance <= 10000); + + // Shall be under 100000, inclusive + self.maxscl.iter().for_each(|&v| assert!(v <= 100_000)); + + // Shall be under 100000, inclusive + assert!(self.average_maxrgb <= 100_000); + + // Shall be under 100000, inclusive + DistributionMaxRgb::validate( + &self.distribution_maxrgb, + self.num_distribution_maxrgb_percentiles, + ); + + // The value of knee_point_x shall be in the range of 0 to 1, and in multiples of 1/4095 + assert!(self.knee_point_x < 4096); + assert!(self.knee_point_y < 4096); + + // THe maximum value shall be 9 + assert!(self.num_bezier_curve_anchors <= 9); + + // Shall be under 1024 + self.bezier_curve_anchors + .iter() + .for_each(|&v| assert!(v < 1024)); + } + + pub fn json_list( + list: &[Self], + force_single_profile: bool, + ) -> (&str, Vec, Option) { + // Get highest number of anchors (should be constant across frames other than empty) + let num_bezier_curve_anchors = match list.iter().map(|m| m.bezier_curve_anchors.len()).max() + { + Some(max) => max, + None => 0, + }; + + // Use max with 0s instead of empty + let replacement_curve_data = vec![0; num_bezier_curve_anchors]; + let mut warning = None; + + let mut profile = "A"; + + let metadata_json_array = list + .iter() + .map(|m| { + // Profile A, no bezier curve data + if m.targeted_system_display_maximum_luminance == 0 && m.bezier_curve_anchors.is_empty() && num_bezier_curve_anchors == 0 { + json!({ + "LuminanceParameters": { + "AverageRGB": m.average_maxrgb, + "LuminanceDistributions": DistributionMaxRgb::separate_json(&m.distribution_maxrgb), + "MaxScl": m.maxscl + }, + "NumberOfWindows": m.num_windows, + "TargetedSystemDisplayMaximumLuminance": m.targeted_system_display_maximum_luminance + }) + } else { // Profile B + if profile != "B" { + profile = "B"; + } + + // Don't insert empty vec when profile B and forcing single profile + let bezier_curve_anchors = if force_single_profile && m.bezier_curve_anchors.is_empty() && num_bezier_curve_anchors != 0 { + if warning.is_none() { + warning = Some(format!("{}", Yellow.paint("Forced profile B."))); + } + + &replacement_curve_data + } else { + if warning.is_none() && m.bezier_curve_anchors.is_empty() && num_bezier_curve_anchors != 0 { + warning = Some(format!("{} Different profiles appear to be present in the metadata, this can cause errors when used with x265.\nUse {} to \"fix\".", Yellow.paint("Warning:"), Yellow.paint("--force-single-profile"))); + } + + &m.bezier_curve_anchors + }; + + json!({ + "BezierCurveData": { + "Anchors": bezier_curve_anchors, + "KneePointX": m.knee_point_x, + "KneePointY": m.knee_point_y + }, + "LuminanceParameters": { + "AverageRGB": m.average_maxrgb, + "LuminanceDistributions": DistributionMaxRgb::separate_json(&m.distribution_maxrgb), + "MaxScl": m.maxscl + }, + "NumberOfWindows": m.num_windows, + "TargetedSystemDisplayMaximumLuminance": m.targeted_system_display_maximum_luminance + }) + } + }) + .collect::>(); + + (profile, metadata_json_array, warning) + } +} + +impl DistributionMaxRgb { + pub fn distribution_index(list: &[Self]) -> Vec { + list.iter().map(|v| v.percentage).collect::>() + } + + pub fn distribution_values(list: &[Self]) -> Vec { + list.iter().map(|v| v.percentile).collect::>() + } + + fn separate_json(list: &[Self]) -> Value { + json!({ + "DistributionIndex": Self::distribution_index(list), + "DistributionValues": Self::distribution_values(list), + }) + } + + pub fn validate(list: &[Self], num_distribution_maxrgb_percentiles: u8) { + // The value of num_distribution_maxrgb_percentiles shall be 9 or 10 (for all we know) + let correct_indexes = match num_distribution_maxrgb_percentiles { + 9 => DISTRIBUTION_INDEXES_9, + 10 => DISTRIBUTION_INDEXES_10, + _ => panic!( + "Invalid number of percentiles: {}", + num_distribution_maxrgb_percentiles + ), + }; + + // Distribution indexes should be equal to: + // 9 indexes: [1, 5, 10, 25, 50, 75, 90, 95, 99] + // 10 indexes: [1, 5, 10, 25, 50, 75, 90, 95, 98, 99] + assert_eq!(Self::distribution_index(list), correct_indexes); + + Self::distribution_values(list) + .iter() + .for_each(|&v| assert!(v <= 100_000)); + } +} diff --git a/src/hdr10plus/mod.rs b/src/hdr10plus/mod.rs new file mode 100644 index 0000000..50dc25c --- /dev/null +++ b/src/hdr10plus/mod.rs @@ -0,0 +1,5 @@ +pub mod metadata; +pub mod parser; + +#[cfg(test)] +mod tests; diff --git a/src/hdr10plus/parser.rs b/src/hdr10plus/parser.rs new file mode 100644 index 0000000..5cff30a --- /dev/null +++ b/src/hdr10plus/parser.rs @@ -0,0 +1,303 @@ +use std::fs::File; +use std::io::{stdout, BufRead, BufReader, BufWriter, Write}; +use std::path::PathBuf; + +use ansi_term::Colour::{Blue, Green, Red}; +use deku::prelude::*; +use indicatif::{ProgressBar, ProgressStyle}; +use read_byte_slice::{ByteSliceIter, FallibleStreamingIterator}; +use serde_json::{json, Value}; + +use super::metadata::Metadata; + +pub struct Parser { + is_stdin: bool, + input: PathBuf, + output: Option, + verify: bool, + force_single_profile: bool, +} + +impl Parser { + pub fn new( + is_stdin: bool, + input: PathBuf, + output: Option, + verify: bool, + force_single_profile: bool, + ) -> Self { + Self { + is_stdin, + input, + output, + verify, + force_single_profile, + } + } + + pub fn process_file(&self) { + let final_metadata: Vec; + + match self.parse_metadata() { + Ok(vec) => { + //Match returned vec to check for --verify + if vec[0][0] == 1 && vec[0].len() == 1 { + println!("{}", Blue.paint("Dynamic HDR10+ metadata detected.")); + } else { + final_metadata = Self::llc_read_metadata(vec); + //Sucessful parse & no --verify + if !final_metadata.is_empty() { + self.write_json(final_metadata) + } else { + println!("{}", Red.paint("Failed reading parsed metadata.")); + } + } + } + Err(e) => println!("{}", e), + } + } + + pub fn parse_metadata(&self) -> Result>, std::io::Error> { + //BufReader & BufWriter + let stdin = std::io::stdin(); + let mut reader = Box::new(stdin.lock()) as Box; + let bytes_count; + + let pb: ProgressBar; + + if self.is_stdin { + pb = ProgressBar::hidden(); + } else { + let file = File::open(&self.input).expect("No file found"); + + //Info for indicatif ProgressBar + let file_meta = file.metadata(); + bytes_count = file_meta.unwrap().len() / 100_000_000; + + reader = Box::new(BufReader::new(file)); + + if self.verify { + pb = ProgressBar::hidden(); + } else { + pb = ProgressBar::new(bytes_count); + pb.set_style( + ProgressStyle::default_bar() + .template("[{elapsed_precise}] {bar:60.cyan} {percent}%"), + ); + } + } + + //Byte chunk iterator + let mut iter = ByteSliceIter::new(reader, 100_000); + + //Bitstream blocks for SMPTE 2094-40 + let header: Vec = vec![0, 0, 1, 78, 1, 4]; + let mut current_sei: Vec = Vec::new(); + + println!( + "{}", + Blue.paint("Parsing HEVC file for dynamic metadata... ") + ); + stdout().flush().ok(); + + let mut final_sei_list: Vec> = Vec::new(); + + let mut dynamic_hdr_sei = false; + let mut dynamic_detected = false; + let mut cur_byte = 0; + + //Loop over iterator of byte chunks for faster I/O + while let Some(chunk) = iter.next()? { + for byte in chunk { + let byte = *byte; + + cur_byte += 1; + + let tuple = Self::process_bytes( + &header, + byte, + &mut current_sei, + dynamic_hdr_sei, + &mut final_sei_list, + ); + dynamic_hdr_sei = tuple.0; + + if tuple.1 { + dynamic_detected = true; + } + } + + if !dynamic_detected { + pb.finish_and_clear(); + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "File doesn't contain dynamic metadata, stopping.", + )); + } else if self.verify { + pb.finish_and_clear(); + + let verified = vec![vec![1]]; + + return Ok(verified); + } + + if cur_byte >= 100_000_000 { + pb.inc(1); + cur_byte = 0; + } + } + + pb.finish_and_clear(); + + Ok(final_sei_list) + } + + fn process_bytes( + header: &[u8], + byte: u8, + current_sei: &mut Vec, + mut dynamic_hdr_sei: bool, + final_sei_list: &mut Vec>, + ) -> (bool, bool) { + let mut dynamic_detected = false; + + current_sei.push(byte); + if dynamic_hdr_sei { + let last = current_sei.len() - 1; + + if current_sei[last - 3] == 128 + && current_sei[last - 2] == 0 + && current_sei[last - 1] == 0 + && (current_sei[last] == 1 || current_sei[last] == 0) + { + let final_sei = ¤t_sei[7..current_sei.len() - 3]; + + //Push SEI message to final vec + final_sei_list.push(final_sei.to_vec()); + + //Clear current vec for next pattern match + current_sei.clear(); + dynamic_hdr_sei = false; + dynamic_detected = true; + } + } else if byte == 0 || byte == 1 || byte == 78 || byte == 4 { + for i in 0..current_sei.len() { + if current_sei[i] == header[i] { + if current_sei == &header { + dynamic_hdr_sei = true; + break; + } + } else if current_sei.len() < 3 { + current_sei.clear(); + break; + } else { + current_sei.pop(); + break; + } + } + } else if !current_sei.is_empty() { + current_sei.clear(); + } + + (dynamic_hdr_sei, dynamic_detected) + } + + pub fn llc_read_metadata(input: Vec>) -> Vec { + print!("{}", Blue.paint("Reading parsed dynamic metadata... ")); + stdout().flush().ok(); + + let mut complete_metadata: Vec = Vec::new(); + + //Loop over lines and read metadata, HDR10+ LLC format + for data in input.iter() { + // Clear x265's injected 0x03 byte if it is present + // See https://bitbucket.org/multicoreware/x265_git/src/a82c6c7a7d5f5ef836c82941788a37c6a443e0fe/source/encoder/nal.cpp?at=master#lines-119:136 + let bytes = data + .iter() + .enumerate() + .filter_map(|(index, value)| { + if index > 2 + && index < data.len() - 2 + && data[index - 2] == 0 + && data[index - 1] == 0 + && data[index] <= 3 + { + None + } else { + Some(*value) + } + }) + .collect::>(); + + // Parse metadata + let (_rest, metadata) = Metadata::from_bytes((&bytes, 0)).unwrap(); + + // Validate values + metadata.validate(); + + // Debug + // println!("{:?}", metadata); + + complete_metadata.push(metadata); + } + + println!("{}", Green.paint("Done.")); + + complete_metadata + } + + fn write_json(&self, metadata: Vec) { + match &self.output { + Some(path) => { + let save_file = File::create(path).expect("Can't create file"); + let mut writer = BufWriter::with_capacity(10_000_000, save_file); + + print!("{}", Blue.paint("Writing metadata to JSON file... ")); + stdout().flush().ok(); + + let (profile, frame_json_list, warning): (&str, Vec, Option) = + Metadata::json_list(&metadata, self.force_single_profile); + + let json_info = json!({ + "HDR10plusProfile": profile, + "Version": format!("{}.0", &metadata[0].application_version), + }); + + let final_json = json!({ + "JSONInfo": json_info, + "SceneInfo": frame_json_list + }); + + assert!(writeln!( + writer, + "{}", + serde_json::to_string_pretty(&final_json).unwrap() + ) + .is_ok()); + + println!("{}", Green.paint("Done.")); + + if warning.is_some() { + println!("{}", warning.unwrap()); + } + + writer.flush().ok(); + } + None => panic!("Output path required!"), + } + } + + pub fn _test(&self) -> Option { + let mut metadata: Vec = Vec::new(); + match self.parse_metadata() { + Ok(vec) => metadata = Parser::llc_read_metadata(vec), + Err(e) => println!("{}", e), + } + + if !metadata.is_empty() { + metadata.first().cloned() + } else { + None + } + } +} diff --git a/src/hdr10plus/tests.rs b/src/hdr10plus/tests.rs new file mode 100644 index 0000000..37e3e98 --- /dev/null +++ b/src/hdr10plus/tests.rs @@ -0,0 +1,1430 @@ +use std::path::PathBuf; + +use super::metadata::DistributionMaxRgb; +use super::parser::Parser; + +// x265 Tool_Verification_new_hdr10plus_llc.json 1st frame +#[test] +fn sample1() { + let input_file = PathBuf::from("./assets/ToS-s1.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 1037); + assert_eq!(result.maxscl, vec![17830, 16895, 14252]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![3, 14024, 43, 56, 219, 1036, 2714, 4668, 14445] + ); + assert_eq!(result.knee_point_x, 17); + assert_eq!(result.knee_point_y, 64); + assert_eq!( + result.bezier_curve_anchors, + vec![265, 666, 741, 800, 848, 887, 920, 945, 957] + ); +} + +// All 0 values except arrays +#[test] +fn sample2() { + let input_file = PathBuf::from("./assets/ToS-s2.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![3, 14024, 43, 56, 219, 1036, 2714, 4668, 14445] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![265, 666, 741, 800, 848, 887, 920, 945, 957] + ); +} + +// Some small values +#[test] +fn sample3() { + let input_file = PathBuf::from("./assets/ToS-s3.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![0, 1, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![3, 14024, 43, 56, 219, 1036, 2714, 4668, 14445] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![265, 666, 741, 800, 848, 887, 920, 945, 957] + ); +} + +// More random values +#[test] +fn sample4() { + let input_file = PathBuf::from("./assets/ToS-s4.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10); + assert_eq!(result.average_maxrgb, 1); + assert_eq!(result.maxscl, vec![0, 1, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 14024, 43, 56, 219, 0, 2714, 4668, 14445] + ); + assert_eq!(result.knee_point_x, 1); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![0, 666, 741, 0, 848, 887, 920, 945, 957] + ); +} + +// Some 0 values except targeted display maximum luminance +#[test] +fn sample5() { + let input_file = PathBuf::from("./assets/ToS-s5.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 500); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 3, 4, 5, 6, 7, 8] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +// More random values +#[test] +fn sample6() { + let input_file = PathBuf::from("./assets/ToS-s6.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 500); + assert_eq!(result.average_maxrgb, 1); + assert_eq!(result.maxscl, vec![1, 3, 6]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 3, 4, 5, 6, 7, 8] + ); + assert_eq!(result.knee_point_x, 2048); + assert_eq!(result.knee_point_y, 85); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +// Edge case with averageRGB +#[test] +fn sample7() { + let input_file = PathBuf::from("./assets/ToS-s7.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![3790, 5508, 3584]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +// Low averageRGB and MaxScl 0s +#[test] +fn sample8() { + let input_file = PathBuf::from("./assets/ToS-s8.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 3); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +// Low averageRGB, MaxScl 0s and TargetedSystemDisplayMaximumLuminance 0 +#[test] +fn sample9() { + let input_file = PathBuf::from("./assets/ToS-s9.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 3); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample10() { + let input_file = PathBuf::from("./assets/ToS-s10.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 13); + assert_eq!(result.maxscl, vec![1, 3, 6]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 1); + assert_eq!(result.knee_point_y, 1); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample11() { + let input_file = PathBuf::from("./assets/ToS-s11.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![69700, 67280, 89012]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample12() { + let input_file = PathBuf::from("./assets/ToS-s12.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample13() { + let input_file = PathBuf::from("./assets/ToS-s13.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 78023); + assert_eq!(result.maxscl, vec![69700, 67280, 89012]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 2305); + assert_eq!(result.knee_point_y, 1203); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample14() { + let input_file = PathBuf::from("./assets/ToS-s14.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 9998); + assert_eq!(result.average_maxrgb, 78023); + assert_eq!(result.maxscl, vec![69700, 67280, 89012]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 572, 100, 1, 1, 2, 12, 35, 491] + ); + assert_eq!(result.knee_point_x, 2305); + assert_eq!(result.knee_point_y, 1203); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample15() { + let input_file = PathBuf::from("./assets/ToS-s15.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 9998); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample16() { + let input_file = PathBuf::from("./assets/ToS-s16.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 1); + assert_eq!(result.maxscl, vec![450, 26, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] + ); + assert_eq!(result.knee_point_x, 35); + assert_eq!(result.knee_point_y, 86); + assert_eq!( + result.bezier_curve_anchors, + vec![203, 411, 624, 721, 773, 821, 875, 924, 953] + ); +} + +#[test] +fn sample17() { + let input_file = PathBuf::from("./assets/ToS-s17.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 11); + assert_eq!(result.maxscl, vec![0, 0, 3584]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample18() { + let input_file = PathBuf::from("./assets/ToS-s18.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 3584); + assert_eq!(result.maxscl, vec![0, 0, 8]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample19() { + let input_file = PathBuf::from("./assets/ToS-s19.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 4096); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![4096, 8192, 16384]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] + ); + assert_eq!(result.knee_point_x, 3823); + assert_eq!(result.knee_point_y, 1490); + assert_eq!( + result.bezier_curve_anchors, + vec![102, 205, 307, 410, 512, 614, 717, 819, 922] + ); +} + +#[test] +fn sample20() { + let input_file = PathBuf::from("./assets/ToS-s20.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![0, 5582, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample21() { + let input_file = PathBuf::from("./assets/ToS-s21.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 9); + assert_eq!(result.maxscl, vec![0, 0, 3584]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample22() { + let input_file = PathBuf::from("./assets/ToS-s22.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![7, 0, 3584]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample23() { + let input_file = PathBuf::from("./assets/ToS-s23.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![1, 0, 6]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample24() { + let input_file = PathBuf::from("./assets/ToS-s24.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 1); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![0, 5582, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample25() { + let input_file = PathBuf::from("./assets/ToS-s25.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![3584, 0, 3584]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample26() { + let input_file = PathBuf::from("./assets/ToS-s26.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 100000); + assert_eq!(result.maxscl, vec![2048, 2048, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample27() { + let input_file = PathBuf::from("./assets/ToS-s27.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![2048, 2048, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample28() { + let input_file = PathBuf::from("./assets/ToS-s28.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![2048, 2048, 2048]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample29() { + let input_file = PathBuf::from("./assets/ToS-s29.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![2049, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample30() { + let input_file = PathBuf::from("./assets/ToS-s30.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![12, 3, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample31() { + let input_file = PathBuf::from("./assets/ToS-s31.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![1, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample32() { + let input_file = PathBuf::from("./assets/ToS-s32.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 11); + assert_eq!(result.maxscl, vec![1152, 2, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample33() { + let input_file = PathBuf::from("./assets/ToS-s33.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![32768, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample34() { + let input_file = PathBuf::from("./assets/ToS-s34.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![1, 2304, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample35() { + let input_file = PathBuf::from("./assets/ToS-s35.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 11); + assert_eq!(result.maxscl, vec![158, 1, 1]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample36() { + let input_file = PathBuf::from("./assets/ToS-s36.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 11); + assert_eq!(result.maxscl, vec![4096, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample37() { + let input_file = PathBuf::from("./assets/ToS-s37.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample38() { + let input_file = PathBuf::from("./assets/ToS-s38.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![0, 2048, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample39() { + let input_file = PathBuf::from("./assets/ToS-s39.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![0, 98304, 98304]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample40() { + let input_file = PathBuf::from("./assets/ToS-s40.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![0, 70000, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample41() { + let input_file = PathBuf::from("./assets/ToS-s41.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 1); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![32768, 98304, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample42() { + let input_file = PathBuf::from("./assets/ToS-s42.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 0); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![98304, 98304, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample43() { + let input_file = PathBuf::from("./assets/ToS-s43.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 1); + assert_eq!(result.average_maxrgb, 1024); + assert_eq!(result.maxscl, vec![65536, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample44() { + let input_file = PathBuf::from("./assets/ToS-s44.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 65535); + assert_eq!(result.maxscl, vec![0, 4097, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample45() { + let input_file = PathBuf::from("./assets/ToS-s45.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 4096); + assert_eq!(result.average_maxrgb, 1); + assert_eq!(result.maxscl, vec![0, 65536, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample46() { + let input_file = PathBuf::from("./assets/ToS-s46.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 4096); + assert_eq!(result.average_maxrgb, 65536); + assert_eq!(result.maxscl, vec![0, 65536, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample47() { + let input_file = PathBuf::from("./assets/ToS-s47.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 65536); + assert_eq!(result.maxscl, vec![32768, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample48() { + let input_file = PathBuf::from("./assets/ToS-s48.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 65536); + assert_eq!(result.maxscl, vec![0, 65536, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample49() { + let input_file = PathBuf::from("./assets/ToS-s49.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 12); + assert_eq!(result.maxscl, vec![99000, 98304, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample50() { + let input_file = PathBuf::from("./assets/ToS-s50.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 8192); + assert_eq!(result.average_maxrgb, 99999); + assert_eq!(result.maxscl, vec![99000, 98304, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample51() { + let input_file = PathBuf::from("./assets/ToS-s51.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 32847); + assert_eq!(result.maxscl, vec![32768, 32768, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample52() { + let input_file = PathBuf::from("./assets/ToS-s52.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample53() { + let input_file = PathBuf::from("./assets/ToS-s53.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 400); + assert_eq!(result.average_maxrgb, 100000); + assert_eq!(result.maxscl, vec![0, 99999, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample54() { + let input_file = PathBuf::from("./assets/ToS-s54.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 100000); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 100, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, Vec::::new()); +} + +#[test] +fn sample55() { + let input_file = PathBuf::from("./assets/ToS-s55.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 350); + assert_eq!(result.average_maxrgb, 1); + assert_eq!(result.maxscl, vec![4425, 3984, 3292]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 98, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 0, 0, 0, 0, 0, 1, 5, 2756] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, vec![256, 512, 767]); +} + +#[test] +fn sample56() { + let input_file = PathBuf::from("./assets/ToS-s56.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 350); + assert_eq!(result.average_maxrgb, 1); + assert_eq!(result.maxscl, vec![0, 65536, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 98, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 0, 0, 0, 0, 0, 1, 5, 2756] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, vec![256, 512, 767]); +} + +#[test] +fn sample57() { + let input_file = PathBuf::from("./assets/ToS-s57.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 9998); + assert_eq!(result.average_maxrgb, 0); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![0, 0, 0, 0, 0, 0, 0, 0, 0] + ); + assert_eq!(result.knee_point_x, 0); + assert_eq!(result.knee_point_y, 0); + assert_eq!(result.bezier_curve_anchors, vec![0, 0, 0]); +} + +#[test] +fn sample58() { + let input_file = PathBuf::from("./assets/ToS-s58.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 100000); + assert_eq!(result.maxscl, vec![100000, 100000, 100000]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 98, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000] + ); + assert_eq!(result.knee_point_x, 4095); + assert_eq!(result.knee_point_y, 4095); + assert_eq!( + result.bezier_curve_anchors, + vec![1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023] + ); +} + +#[test] +fn sample59() { + let input_file = PathBuf::from("./assets/ToS-s59.h265"); + let parser = Parser::new(false, input_file, None, false, false); + let result = parser._test().unwrap(); + + assert_eq!(result.num_windows, 1); + assert_eq!(result.targeted_system_display_maximum_luminance, 10000); + assert_eq!(result.average_maxrgb, 100000); + assert_eq!(result.maxscl, vec![0, 0, 0]); + assert_eq!( + DistributionMaxRgb::distribution_index(&result.distribution_maxrgb), + vec![1, 5, 10, 25, 50, 75, 90, 95, 98, 99] + ); + assert_eq!( + DistributionMaxRgb::distribution_values(&result.distribution_maxrgb), + vec![100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000, 100000] + ); + assert_eq!(result.knee_point_x, 4095); + assert_eq!(result.knee_point_y, 4095); + assert_eq!( + result.bezier_curve_anchors, + vec![1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023] + ); +} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index e3ae632..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,1524 +0,0 @@ -mod hdr10plus; - -//Regression tests -#[cfg(test)] -mod tests { - use crate::hdr10plus::{llc_read_metadata, parse_metadata, Metadata}; - use std::path::PathBuf; - - // x265 Tool_Verification_new_hdr10plus_llc.json 1st frame - #[test] - fn sample1() { - let sample1_file = PathBuf::from("./assets/ToS-s1.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample1_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 1037); - assert_eq!(test[0].maxscl, vec![17830, 16895, 14252]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![3, 14024, 43, 56, 219, 1036, 2714, 4668, 14445] - ); - assert_eq!(test[0].knee_x, 17); - assert_eq!(test[0].knee_y, 64); - assert_eq!( - test[0].bezier_curve_data, - vec![265, 666, 741, 800, 848, 887, 920, 945, 957] - ); - } - - // All 0 values except arrays - #[test] - fn sample2() { - let sample2_file = PathBuf::from("./assets/ToS-s2.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample2_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![3, 14024, 43, 56, 219, 1036, 2714, 4668, 14445] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![265, 666, 741, 800, 848, 887, 920, 945, 957] - ); - } - - // Some small values - #[test] - fn sample3() { - let sample3_file = PathBuf::from("./assets/ToS-s3.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample3_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![0, 1, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![3, 14024, 43, 56, 219, 1036, 2714, 4668, 14445] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![265, 666, 741, 800, 848, 887, 920, 945, 957] - ); - } - - // More random values - #[test] - fn sample4() { - let sample4_file = PathBuf::from("./assets/ToS-s4.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample4_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 10); - assert_eq!(test[0].average_maxrgb, 1); - assert_eq!(test[0].maxscl, vec![0, 1, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 14024, 43, 56, 219, 0, 2714, 4668, 14445] - ); - assert_eq!(test[0].knee_x, 1); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![0, 666, 741, 0, 848, 887, 920, 945, 957] - ); - } - - // Some 0 values except targeted display maximum luminance - #[test] - fn sample5() { - let sample5_file = PathBuf::from("./assets/ToS-s5.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample5_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 500); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 3, 4, 5, 6, 7, 8] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - // More random values - #[test] - fn sample6() { - let sample6_file = PathBuf::from("./assets/ToS-s6.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample6_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 500); - assert_eq!(test[0].average_maxrgb, 1); - assert_eq!(test[0].maxscl, vec![1, 3, 6]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 3, 4, 5, 6, 7, 8] - ); - assert_eq!(test[0].knee_x, 2048); - assert_eq!(test[0].knee_y, 85); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - // Edge case with averageRGB - #[test] - fn sample7() { - let sample7_file = PathBuf::from("./assets/ToS-s7.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample7_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![3790, 5508, 3584]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - // Low averageRGB and MaxScl 0s - #[test] - fn sample8() { - let sample8_file = PathBuf::from("./assets/ToS-s8.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample8_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 3); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - // Low averageRGB, MaxScl 0s and TargetedSystemDisplayMaximumLuminance 0 - #[test] - fn sample9() { - let sample9_file = PathBuf::from("./assets/ToS-s9.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample9_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 3); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample10() { - let sample10_file = PathBuf::from("./assets/ToS-s10.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample10_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 13); - assert_eq!(test[0].maxscl, vec![1, 3, 6]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 1); - assert_eq!(test[0].knee_y, 1); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample11() { - let sample11_file = PathBuf::from("./assets/ToS-s11.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample11_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![69700, 67280, 89012]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample12() { - let sample12_file = PathBuf::from("./assets/ToS-s12.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample12_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample13() { - let sample13_file = PathBuf::from("./assets/ToS-s13.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample13_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 78023); - assert_eq!(test[0].maxscl, vec![69700, 67280, 89012]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 2305); - assert_eq!(test[0].knee_y, 1203); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample14() { - let sample14_file = PathBuf::from("./assets/ToS-s14.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample14_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 9998); - assert_eq!(test[0].average_maxrgb, 78023); - assert_eq!(test[0].maxscl, vec![69700, 67280, 89012]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 572, 100, 1, 1, 2, 12, 35, 491] - ); - assert_eq!(test[0].knee_x, 2305); - assert_eq!(test[0].knee_y, 1203); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample15() { - let sample15_file = PathBuf::from("./assets/ToS-s15.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample15_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 9998); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!(test[0].distribution_values, vec![0, 0, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample16() { - let sample16_file = PathBuf::from("./assets/ToS-s16.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample16_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 1); - assert_eq!(test[0].maxscl, vec![450, 26, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] - ); - assert_eq!(test[0].knee_x, 35); - assert_eq!(test[0].knee_y, 86); - assert_eq!( - test[0].bezier_curve_data, - vec![203, 411, 624, 721, 773, 821, 875, 924, 953] - ); - } - - #[test] - fn sample17() { - let sample17_file = PathBuf::from("./assets/ToS-s17.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample17_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 11); - assert_eq!(test[0].maxscl, vec![0, 0, 3584]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample18() { - let sample18_file = PathBuf::from("./assets/ToS-s18.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample18_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 3584); - assert_eq!(test[0].maxscl, vec![0, 0, 8]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample19() { - let sample19_file = PathBuf::from("./assets/ToS-s19.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample19_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 4096); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![4096, 8192, 16384]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 9791, 100, 0, 1, 9, 32, 56, 9740] - ); - assert_eq!(test[0].knee_x, 3823); - assert_eq!(test[0].knee_y, 1490); - assert_eq!( - test[0].bezier_curve_data, - vec![102, 205, 307, 410, 512, 614, 717, 819, 922] - ); - } - - #[test] - fn sample20() { - let sample20_file = PathBuf::from("./assets/ToS-s20.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample20_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![0, 5582, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample21() { - let sample21_file = PathBuf::from("./assets/ToS-s21.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample21_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 9); - assert_eq!(test[0].maxscl, vec![0, 0, 3584]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample22() { - let sample22_file = PathBuf::from("./assets/ToS-s22.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample22_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![7, 0, 3584]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample23() { - let sample23_file = PathBuf::from("./assets/ToS-s23.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample23_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![1, 0, 6]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample24() { - let sample24_file = PathBuf::from("./assets/ToS-s24.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample24_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 1); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![0, 5582, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample25() { - let sample25_file = PathBuf::from("./assets/ToS-s25.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample25_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![3584, 0, 3584]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample26() { - let sample26_file = PathBuf::from("./assets/ToS-s26.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample26_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 10000); - assert_eq!(test[0].average_maxrgb, 100000); - assert_eq!(test[0].maxscl, vec![2048, 2048, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample27() { - let sample27_file = PathBuf::from("./assets/ToS-s27.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample27_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 10000); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![2048, 2048, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample28() { - let sample28_file = PathBuf::from("./assets/ToS-s28.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample28_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 10000); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![2048, 2048, 2048]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample29() { - let sample29_file = PathBuf::from("./assets/ToS-s29.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample29_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 10000); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![2049, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample30() { - let sample30_file = PathBuf::from("./assets/ToS-s30.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample30_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![12, 3, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample31() { - let sample31_file = PathBuf::from("./assets/ToS-s31.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample31_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![1, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample32() { - let sample32_file = PathBuf::from("./assets/ToS-s32.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample32_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 11); - assert_eq!(test[0].maxscl, vec![1152, 2, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample33() { - let sample33_file = PathBuf::from("./assets/ToS-s33.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample33_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![32768, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample34() { - let sample34_file = PathBuf::from("./assets/ToS-s34.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample34_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![1, 2304, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample35() { - let sample35_file = PathBuf::from("./assets/ToS-s35.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample35_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 11); - assert_eq!(test[0].maxscl, vec![158, 1, 1]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample36() { - let sample36_file = PathBuf::from("./assets/ToS-s36.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample36_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 11); - assert_eq!(test[0].maxscl, vec![4096, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample37() { - let sample37_file = PathBuf::from("./assets/ToS-s37.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample37_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample38() { - let sample38_file = PathBuf::from("./assets/ToS-s38.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample38_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![0, 2048, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample39() { - let sample39_file = PathBuf::from("./assets/ToS-s39.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample39_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![0, 98304, 98304]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample40() { - let sample40_file = PathBuf::from("./assets/ToS-s40.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample40_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![0, 70000, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample41() { - let sample41_file = PathBuf::from("./assets/ToS-s41.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample41_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 1); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![32768, 98304, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample42() { - let sample42_file = PathBuf::from("./assets/ToS-s42.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample42_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 0); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![98304, 98304, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample43() { - let sample43_file = PathBuf::from("./assets/ToS-s43.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample43_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 1); - assert_eq!(test[0].average_maxrgb, 1024); - assert_eq!(test[0].maxscl, vec![65536, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample44() { - let sample44_file = PathBuf::from("./assets/ToS-s44.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample44_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 10000); - assert_eq!(test[0].average_maxrgb, 65535); - assert_eq!(test[0].maxscl, vec![0, 4097, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample45() { - let sample45_file = PathBuf::from("./assets/ToS-s45.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample45_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 4096); - assert_eq!(test[0].average_maxrgb, 1); - assert_eq!(test[0].maxscl, vec![0, 65536, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample46() { - let sample46_file = PathBuf::from("./assets/ToS-s46.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample46_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 4096); - assert_eq!(test[0].average_maxrgb, 65536); - assert_eq!(test[0].maxscl, vec![0, 65536, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample47() { - let sample47_file = PathBuf::from("./assets/ToS-s47.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample47_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 65536); - assert_eq!(test[0].maxscl, vec![32768, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample48() { - let sample48_file = PathBuf::from("./assets/ToS-s48.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample48_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 65536); - assert_eq!(test[0].maxscl, vec![0, 65536, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample49() { - let sample49_file = PathBuf::from("./assets/ToS-s49.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample49_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 12); - assert_eq!(test[0].maxscl, vec![99000, 98304, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample50() { - let sample50_file = PathBuf::from("./assets/ToS-s50.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample50_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 8192); - assert_eq!(test[0].average_maxrgb, 99999); - assert_eq!(test[0].maxscl, vec![99000, 98304, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample51() { - let sample51_file = PathBuf::from("./assets/ToS-s51.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample51_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 32847); - assert_eq!(test[0].maxscl, vec![32768, 32768, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample52() { - let sample52_file = PathBuf::from("./assets/ToS-s52.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample52_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 0); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample53() { - let sample53_file = PathBuf::from("./assets/ToS-s53.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample53_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 400); - assert_eq!(test[0].average_maxrgb, 100000); - assert_eq!(test[0].maxscl, vec![0, 99999, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample54() { - let sample54_file = PathBuf::from("./assets/ToS-s54.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample54_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 10000); - assert_eq!(test[0].average_maxrgb, 100000); - assert_eq!(test[0].maxscl, vec![0, 0, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 100, 0, 0, 0, 0, 0, 0] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, Vec::::new()); - } - - #[test] - fn sample55() { - let sample55_file = PathBuf::from("./assets/ToS-s55.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample55_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 350); - assert_eq!(test[0].average_maxrgb, 1); - assert_eq!(test[0].maxscl, vec![4425, 3984, 3292]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 98, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 0, 0, 0, 0, 0, 1, 5, 2756] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, vec![256, 512, 767]); - } - - #[test] - fn sample56() { - let sample56_file = PathBuf::from("./assets/ToS-s56.h265"); - let mut test: Vec = Vec::new(); - match parse_metadata(false, &sample56_file, false) { - Ok(vec) => test = llc_read_metadata(vec), - Err(e) => println!("{}", e), - } - - assert_eq!(test[0].num_windows, 1); - assert_eq!(test[0].targeted_system_display_maximum_luminance, 350); - assert_eq!(test[0].average_maxrgb, 1); - assert_eq!(test[0].maxscl, vec![0, 65536, 0]); - assert_eq!( - test[0].distribution_index, - vec![1, 5, 10, 25, 50, 75, 90, 95, 98, 99] - ); - assert_eq!( - test[0].distribution_values, - vec![0, 0, 0, 0, 0, 0, 0, 1, 5, 2756] - ); - assert_eq!(test[0].knee_x, 0); - assert_eq!(test[0].knee_y, 0); - assert_eq!(test[0].bezier_curve_data, vec![256, 512, 767]); - } -} diff --git a/src/main.rs b/src/main.rs index 1eb4e66..44efd7e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use structopt::StructOpt; mod hdr10plus; -use crate::hdr10plus::process_file; +use hdr10plus::parser::Parser; #[derive(StructOpt, Debug)] #[structopt( @@ -58,22 +58,22 @@ fn main() -> std::io::Result<()> { }, }; - let mut verify = opt.verify; - - let output = match opt.output { - Some(out) => out, - None => { - verify = true; - PathBuf::new() - } - }; + let verify = opt.verify || opt.output.is_none(); match verify_input(&input) { - Ok(is_stdin) => process_file(is_stdin, &input, output, verify, opt.force_single_profile), - Err(msg) => { - println!("{}", msg); + Ok(is_stdin) => { + let parser = Parser::new( + is_stdin, + input, + opt.output, + verify, + opt.force_single_profile, + ); + parser.process_file(); } + Err(msg) => println!("{}", msg), } + Ok(()) }