Skip to content

Commit d66ce14

Browse files
authored
Small video-related refactor (#7660)
### What Some small improvements in service of coming ffmpeg stuff * Extracted from #7658 * Part of #7606 ### Checklist * [x] I have read and agree to [Contributor Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and the [Code of Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md) * [x] I've included a screenshot or gif (if applicable) * [x] I have tested the web demo (if applicable): * Using examples from latest `main` build: [rerun.io/viewer](https://rerun.io/viewer/pr/7660?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [rerun.io/viewer](https://rerun.io/viewer/pr/7660?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [x] The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG * [x] If applicable, add a new check to the [release checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)! * [x] If have noted any breaking changes to the log API in `CHANGELOG.md` and the migration guide - [PR Build Summary](https://build.rerun.io/pr/7660) - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) To run all checks from `main`, comment on the PR with `@rerun-bot full-check`.
1 parent 14590be commit d66ce14

File tree

5 files changed

+53
-14
lines changed

5 files changed

+53
-14
lines changed

crates/store/re_video/examples/frames.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use std::{
1313
use indicatif::ProgressBar;
1414
use parking_lot::Mutex;
1515

16+
use re_video::{decode::SyncDecoder, VideoData};
17+
1618
fn main() {
1719
// frames <video.mp4>
1820
let args: Vec<_> = std::env::args().collect();
@@ -27,17 +29,33 @@ fn main() {
2729
let video = std::fs::read(video_path).expect("failed to read video");
2830
let video = re_video::VideoData::load_mp4(&video).expect("failed to load video");
2931

30-
let sync_decoder = Box::new(
31-
re_video::decode::av1::SyncDav1dDecoder::new().expect("Failed to start AV1 decoder"),
32-
);
33-
3432
println!(
3533
"{} {}x{}",
3634
video.gops.len(),
3735
video.config.coded_width,
3836
video.config.coded_height
3937
);
4038

39+
let mut decoder = create_decoder(&video);
40+
41+
write_video_frames(&video, decoder.as_mut(), &output_dir);
42+
}
43+
44+
fn create_decoder(video: &VideoData) -> Box<dyn SyncDecoder> {
45+
if video.config.is_av1() {
46+
Box::new(
47+
re_video::decode::av1::SyncDav1dDecoder::new().expect("Failed to start AV1 decoder"),
48+
)
49+
} else {
50+
panic!("Unsupported codec: {}", video.human_readable_codec_string());
51+
}
52+
}
53+
54+
fn write_video_frames(
55+
video: &re_video::VideoData,
56+
decoder: &mut dyn re_video::decode::SyncDecoder,
57+
output_dir: &PathBuf,
58+
) {
4159
let progress = ProgressBar::new(video.samples.len() as u64).with_message("Decoding video");
4260
progress.enable_steady_tick(Duration::from_millis(100));
4361

@@ -50,16 +68,14 @@ fn main() {
5068
frames.lock().push(frame);
5169
}
5270
};
53-
let mut decoder =
54-
re_video::decode::AsyncDecoder::new("debug_name".to_owned(), sync_decoder, on_output);
5571

5672
let start = Instant::now();
5773
for sample in &video.samples {
58-
decoder.decode(video.get(sample).unwrap());
74+
let should_stop = std::sync::atomic::AtomicBool::new(false);
75+
let chunk = video.get(sample).unwrap();
76+
decoder.submit_chunk(&should_stop, chunk, &on_output);
5977
}
6078

61-
decoder.flush();
62-
drop(decoder);
6379
let end = Instant::now();
6480
progress.finish();
6581

@@ -72,7 +88,7 @@ fn main() {
7288
);
7389

7490
println!("Writing frames to {}", output_dir.display());
75-
std::fs::create_dir_all(&output_dir).expect("failed to create output directory");
91+
std::fs::create_dir_all(output_dir).expect("failed to create output directory");
7692

7793
let width = num_digits(frames.len());
7894
for (i, frame) in frames.iter().enumerate() {

crates/store/re_video/src/decode/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ pub trait SyncDecoder {
3838
}
3939

4040
/// One chunk of encoded video data; usually one frame.
41+
///
42+
/// One loaded [`crate::Sample`].
4143
pub struct Chunk {
44+
/// The start of a new [`crate::demux::GroupOfPictures`]?
45+
pub is_sync: bool,
46+
4247
pub data: Vec<u8>,
4348
pub timestamp: Time,
4449
pub duration: Time,
@@ -55,5 +60,6 @@ pub struct Frame {
5560
}
5661

5762
pub enum PixelFormat {
63+
Rgb8Unorm,
5864
Rgba8Unorm,
5965
}

crates/store/re_video/src/demux/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ impl VideoData {
144144
data: data.to_vec(),
145145
timestamp: sample.decode_timestamp,
146146
duration: sample.duration,
147+
is_sync: sample.is_sync,
147148
})
148149
}
149150
}
@@ -174,6 +175,9 @@ impl GroupOfPictures {
174175
/// A single sample in a video.
175176
#[derive(Debug, Clone)]
176177
pub struct Sample {
178+
/// Is t his the start of a new [`GroupOfPictures`]?
179+
pub is_sync: bool,
180+
177181
/// Time at which this sample appears in the decoded bitstream, in time units.
178182
///
179183
/// Samples should be decoded in this order.

crates/store/re_video/src/demux/mp4.rs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ impl VideoData {
5858
let byte_length = sample.size as u32;
5959

6060
samples.push(Sample {
61+
is_sync: sample.is_sync,
6162
decode_timestamp,
6263
composition_timestamp,
6364
duration,

crates/viewer/re_renderer/src/video/decoder/native_decoder.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,22 @@ fn copy_video_frame_to_texture(
129129
frame: &Frame,
130130
texture: &wgpu::Texture,
131131
) -> Result<(), DecodingError> {
132+
let format = match frame.format {
133+
re_video::PixelFormat::Rgb8Unorm => {
134+
return copy_video_frame_to_texture(
135+
queue,
136+
&Frame {
137+
data: crate::pad_rgb_to_rgba(&frame.data, 255_u8),
138+
format: re_video::PixelFormat::Rgba8Unorm,
139+
..*frame
140+
},
141+
texture,
142+
);
143+
}
144+
145+
re_video::PixelFormat::Rgba8Unorm => wgpu::TextureFormat::Rgba8Unorm,
146+
};
147+
132148
re_tracing::profile_function!();
133149

134150
let size = wgpu::Extent3d {
@@ -137,10 +153,6 @@ fn copy_video_frame_to_texture(
137153
depth_or_array_layers: 1,
138154
};
139155

140-
let format = match frame.format {
141-
re_video::PixelFormat::Rgba8Unorm => wgpu::TextureFormat::Rgba8Unorm,
142-
};
143-
144156
let width_blocks = frame.width / format.block_dimensions().0;
145157

146158
#[allow(clippy::unwrap_used)] // block_copy_size can only fail for weird compressed formats

0 commit comments

Comments
 (0)