1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::ffi::OsStr;
6 use std::fs::File;
7 use std::io::Read;
8 use std::path::Path;
9 use std::path::PathBuf;
10 use std::str::FromStr;
11
12 use argh::FromArgs;
13
14 use cros_codecs::DecodedFormat;
15 use cros_codecs::EncodedFormat;
16 use cros_codecs::FrameMemoryType;
17
18 #[derive(Debug, Eq, PartialEq)]
19 pub enum Md5Computation {
20 Stream,
21 Frame,
22 }
23
24 impl FromStr for Md5Computation {
25 type Err = &'static str;
26
from_str(s: &str) -> Result<Self, Self::Err>27 fn from_str(s: &str) -> Result<Self, Self::Err> {
28 match s {
29 "stream" => Ok(Md5Computation::Stream),
30 "frame" => Ok(Md5Computation::Frame),
31 _ => Err("unrecognized MD5 computation option. Valid values: stream, frame"),
32 }
33 }
34 }
35
36 /// Simple player using cros-codecs
37 #[derive(Debug, FromArgs)]
38 pub struct Args {
39 /// input file
40 #[argh(positional)]
41 pub input: PathBuf,
42
43 /// output file to write the decoded frames to
44 #[argh(option)]
45 pub output: Option<PathBuf>,
46
47 /// whether to decode a frame per file. Requires "output" to be set.
48 #[argh(switch)]
49 pub multiple_output_files: bool,
50
51 /// input format to decode from.
52 #[argh(option)]
53 pub input_format: EncodedFormat,
54
55 /// pixel format to decode into. Default: i420
56 #[argh(option, default = "DecodedFormat::I420")]
57 pub output_format: DecodedFormat,
58
59 /// origin of the memory for decoded buffers (managed, prime or user). Default: managed.
60 #[allow(dead_code)]
61 #[argh(option, default = "FrameMemoryType::Managed")]
62 pub frame_memory: FrameMemoryType,
63
64 /// path to the GBM device to use if frame-memory=prime
65 #[allow(dead_code)]
66 #[argh(option)]
67 pub gbm_device: Option<PathBuf>,
68
69 /// path to VA-API device. This option is ignored on V4L2 systems.
70 #[argh(option)]
71 #[allow(dead_code)]
72 pub libva_device: Option<PathBuf>,
73
74 /// whether to display the MD5 of the decoded stream, and at which granularity (stream or
75 /// frame)
76 #[argh(option)]
77 pub compute_md5: Option<Md5Computation>,
78
79 /// path to JSON file containing golden MD5 sums of each frame.
80 #[argh(option)]
81 pub golden: Option<PathBuf>,
82 }
83
84 /// Decide the output file name when multiple_output_files is set
decide_output_file_name<'a>(output: &'a Path, index: i32) -> PathBuf85 pub fn decide_output_file_name<'a>(output: &'a Path, index: i32) -> PathBuf {
86 let extract_str = |s: Option<&'a OsStr>| s.and_then(|s| s.to_str()).expect("malformed file");
87
88 let [file_name, stem] = [output.file_name(), output.file_stem()].map(extract_str);
89
90 if output.extension().is_some() {
91 let [extension] = [output.extension()].map(extract_str);
92 let new_file_name = format!("{}_{}.{}", stem, index, extension);
93 PathBuf::from(String::from(output.to_str().unwrap()).replace(file_name, &new_file_name))
94 } else {
95 let new_file_name = format!("{}_{}", stem, index);
96 PathBuf::from(String::from(output.to_str().unwrap()).replace(file_name, &new_file_name))
97 }
98 }
99
100 // Vector of per frame md5 sums
golden_md5s(path: &Option<PathBuf>) -> Vec<String>101 pub fn golden_md5s(path: &Option<PathBuf>) -> Vec<String> {
102 let golden_md5s: Vec<String> = match path {
103 None => vec![],
104 Some(ref path) => {
105 let mut golden_file_content = String::new();
106 File::open(path)
107 .expect("error opening golden file")
108 .read_to_string(&mut golden_file_content)
109 .expect("error reading golden file");
110 let parsed_json: serde_json::Value =
111 serde_json::from_str(&golden_file_content).expect("error parsing golden file");
112 match &parsed_json["md5_checksums"] {
113 serde_json::Value::Array(checksums) => checksums
114 .iter()
115 .map(|x| match x {
116 serde_json::Value::String(checksum) => String::from(checksum),
117 _ => panic!("error parsing golden file"),
118 })
119 .collect(),
120 _ => panic!("error parsing golden file"),
121 }
122 }
123 };
124 golden_md5s
125 }
126