Skip to content

Commit 57c9560

Browse files
committed
examples/ccdec: Add example for v4l2 backend
1 parent 2c4ff99 commit 57c9560

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ gbm = { version = "0.14", default-features = false, features = ["drm-support"] }
3737
name = "ccdec"
3838
required-features = ["vaapi"]
3939

40+
[[example]]
41+
name = "ccdec-v4l2-stateless"
42+
required-features = ["v4l2"]
43+
4044
[[example]]
4145
name = "ccenc"
4246
required-features = ["vaapi"]

examples/ccdec-v4l2-stateless.rs

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
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::borrow::Cow;
6+
use std::fs::File;
7+
use std::io::Read;
8+
use std::io::Write;
9+
use std::path::PathBuf;
10+
use std::str::FromStr;
11+
12+
use argh::FromArgs;
13+
use cros_codecs::backend::v4l2::decoder::stateless::V4l2StatelessDecoderHandle;
14+
use cros_codecs::codec::h264::parser::Nalu as H264Nalu;
15+
use cros_codecs::decoder::stateless::h264::H264;
16+
use cros_codecs::decoder::stateless::StatelessDecoder;
17+
use cros_codecs::decoder::stateless::StatelessVideoDecoder;
18+
use cros_codecs::decoder::BlockingMode;
19+
use cros_codecs::decoder::DecodedHandle;
20+
use cros_codecs::multiple_desc_type;
21+
use cros_codecs::utils::simple_playback_loop;
22+
use cros_codecs::utils::simple_playback_loop_owned_frames;
23+
use cros_codecs::utils::DmabufFrame;
24+
use cros_codecs::utils::NalIterator;
25+
use cros_codecs::utils::UserPtrFrame;
26+
use cros_codecs::DecodedFormat;
27+
28+
multiple_desc_type! {
29+
enum BufferDescriptor {
30+
Managed(()),
31+
Dmabuf(DmabufFrame),
32+
User(UserPtrFrame),
33+
}
34+
}
35+
36+
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
37+
enum EncodedFormat {
38+
H264,
39+
H265,
40+
VP8,
41+
VP9,
42+
AV1,
43+
}
44+
45+
impl FromStr for EncodedFormat {
46+
type Err = &'static str;
47+
48+
fn from_str(s: &str) -> Result<Self, Self::Err> {
49+
match s {
50+
"h264" | "H264" => Ok(EncodedFormat::H264),
51+
"h265" | "H265" => Ok(EncodedFormat::H265),
52+
"vp8" | "VP8" => Ok(EncodedFormat::VP8),
53+
"vp9" | "VP9" => Ok(EncodedFormat::VP9),
54+
"av1" | "AV1" => Ok(EncodedFormat::AV1),
55+
_ => Err("unrecognized input format. Valid values: h264, h265, vp8, vp9, av1"),
56+
}
57+
}
58+
}
59+
60+
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
61+
enum FrameMemoryType {
62+
Managed,
63+
Prime,
64+
User,
65+
}
66+
67+
impl FromStr for FrameMemoryType {
68+
type Err = &'static str;
69+
70+
fn from_str(s: &str) -> Result<Self, Self::Err> {
71+
match s {
72+
"managed" => Ok(FrameMemoryType::Managed),
73+
"prime" => Ok(FrameMemoryType::Prime),
74+
"user" => Ok(FrameMemoryType::User),
75+
_ => Err("unrecognized memory type. Valid values: managed, prime, user"),
76+
}
77+
}
78+
}
79+
80+
/// Simple player using cros-codecs
81+
#[derive(Debug, FromArgs)]
82+
struct Args {
83+
/// input file
84+
#[argh(positional)]
85+
input: PathBuf,
86+
87+
/// output file to write the decoded frames to
88+
#[argh(option)]
89+
output: Option<PathBuf>,
90+
91+
/// input format to decode from.
92+
#[argh(option)]
93+
input_format: EncodedFormat,
94+
95+
//TODO /// pixel format to decode into. Default: i420
96+
//TODO #[argh(option, default = "DecodedFormat::I420")]
97+
//TODO output_format: DecodedFormat,
98+
/// origin of the memory for decoded buffers (managed, prime or user). Default: managed.
99+
#[argh(option, default = "FrameMemoryType::Managed")]
100+
frame_memory: FrameMemoryType,
101+
102+
//TODO /// path to the GBM device to use if frame-memory=prime
103+
//TODO #[argh(option)]
104+
//TODO gbm_device: Option<PathBuf>,
105+
/// whether to decode frames synchronously
106+
#[argh(switch)]
107+
synchronous: bool,
108+
//TODO /// whether to display the MD5 of the decoded stream, and at which granularity (stream or
109+
//TODO /// frame)
110+
//TODO #[argh(option)]
111+
//TODO compute_md5: Option<Md5Computation>,
112+
}
113+
114+
fn main() {
115+
env_logger::init();
116+
117+
let args: Args = argh::from_env();
118+
119+
let input = {
120+
let mut buf = Vec::new();
121+
File::open(args.input)
122+
.expect("error opening input file")
123+
.read_to_end(&mut buf)
124+
.expect("error reading input file");
125+
buf
126+
};
127+
128+
let mut output = args
129+
.output
130+
.as_ref()
131+
.map(|p| File::create(p).expect("Failed to create output file"));
132+
133+
let blocking_mode = if args.synchronous {
134+
todo!() // BlockingMode::Blocking
135+
} else {
136+
BlockingMode::NonBlocking
137+
};
138+
139+
let (mut decoder, frame_iter) = match args.input_format {
140+
EncodedFormat::H264 => {
141+
let frame_iter = Box::new(NalIterator::<H264Nalu>::new(&input))
142+
as Box<dyn Iterator<Item = Cow<[u8]>>>;
143+
144+
let decoder = Box::new(StatelessDecoder::<H264, _>::new_v4l2(blocking_mode))
145+
as Box<dyn StatelessVideoDecoder<_>>;
146+
147+
(decoder, frame_iter)
148+
}
149+
EncodedFormat::VP8 => todo!(),
150+
EncodedFormat::VP9 => todo!(),
151+
EncodedFormat::H265 => todo!(),
152+
EncodedFormat::AV1 => todo!(),
153+
};
154+
155+
let mut on_new_frame = |handle: V4l2StatelessDecoderHandle| {
156+
let picture = handle.dyn_picture();
157+
let mut handle = picture.dyn_mappable_handle().unwrap();
158+
let buffer_size = handle.image_size();
159+
let mut frame_data = vec![0; buffer_size];
160+
handle.read(&mut frame_data).unwrap();
161+
if let Some(output) = &mut output {
162+
output
163+
.write_all(&frame_data)
164+
.expect("Failed to write output file");
165+
}
166+
};
167+
168+
simple_playback_loop(
169+
decoder.as_mut(),
170+
frame_iter,
171+
&mut on_new_frame,
172+
&mut |stream_info, nb_frames| {
173+
Ok(match args.frame_memory {
174+
FrameMemoryType::Managed => {
175+
simple_playback_loop_owned_frames(stream_info, nb_frames)?
176+
.into_iter()
177+
.collect()
178+
}
179+
FrameMemoryType::Prime => todo!(),
180+
FrameMemoryType::User => todo!(),
181+
})
182+
},
183+
DecodedFormat::NV12,
184+
blocking_mode,
185+
)
186+
.expect("error during playback loop");
187+
}

0 commit comments

Comments
 (0)