Skip to content

Commit c0794d9

Browse files
authored
Better video stream errors for missing samples & key frames (#11310)
1 parent eee28a7 commit c0794d9

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

crates/viewer/re_renderer/src/video/mod.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,33 @@ use crate::{
1616
resource_managers::{GpuTexture2D, SourceImageDataFormat},
1717
};
1818

19+
/// Detailed error for lack of sample data.
20+
#[derive(thiserror::Error, Debug, Clone)]
21+
pub enum InsufficientSampleDataError {
22+
#[error("Video doesn't have any key frames.")]
23+
NoKeyFrames,
24+
25+
#[error("Video doesn't have any samples.")]
26+
NoSamples,
27+
28+
#[error("No key frames prior to current time.")]
29+
NoKeyFramesPriorToRequestedTimestamp,
30+
31+
#[error("No frames prior to current time.")]
32+
NoSamplesPriorToRequestedTimestamp,
33+
34+
#[error("The requested frame data is not, or no longer, available.")]
35+
ExpectedSampleNotAvailable,
36+
}
37+
1938
/// Error that can occur during playing videos.
2039
#[derive(thiserror::Error, Debug, Clone)]
2140
pub enum VideoPlayerError {
2241
#[error("The decoder is lagging behind")]
2342
EmptyBuffer,
2443

25-
#[error("Video is empty.")]
26-
EmptyVideo,
44+
#[error(transparent)]
45+
InsufficientSampleData(#[from] InsufficientSampleDataError),
2746

2847
/// e.g. unsupported codec
2948
#[error("Failed to create video chunk: {0}")]
@@ -40,9 +59,6 @@ pub enum VideoPlayerError {
4059
#[error("The timestamp passed was negative.")]
4160
NegativeTimestamp,
4261

43-
#[error("The requested frame data is not, or no longer, available.")]
44-
MissingSample,
45-
4662
/// e.g. bad mp4, or bug in mp4 parse
4763
#[error("Bad data.")]
4864
BadData,

crates/viewer/re_renderer/src/video/player.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ use super::{VideoFrameTexture, chunk_decoder::VideoSampleDecoder};
1010
use crate::{
1111
RenderContext,
1212
resource_managers::{GpuTexture2D, SourceImageDataFormat},
13-
video::{DecoderDelayState, VideoPlayerError, chunk_decoder::update_video_texture_with_frame},
13+
video::{
14+
DecoderDelayState, InsufficientSampleDataError, VideoPlayerError,
15+
chunk_decoder::update_video_texture_with_frame,
16+
},
1417
};
1518

1619
pub struct PlayerConfiguration {
@@ -200,14 +203,20 @@ impl VideoPlayer {
200203
video_description: &re_video::VideoDataDescription,
201204
video_buffers: &StableIndexDeque<&[u8]>,
202205
) -> Result<VideoFrameTexture, VideoPlayerError> {
206+
if video_description.gops.is_empty() {
207+
return Err(InsufficientSampleDataError::NoKeyFrames.into());
208+
}
209+
if video_description.samples.is_empty() {
210+
return Err(InsufficientSampleDataError::NoSamples.into());
211+
}
203212
if requested_pts.0 < 0 {
204213
return Err(VideoPlayerError::NegativeTimestamp);
205214
}
206215

207216
// Find which sample best represents the requested PTS.
208217
let requested_sample_idx = video_description
209218
.latest_sample_index_at_presentation_timestamp(requested_pts)
210-
.ok_or(VideoPlayerError::EmptyVideo)?;
219+
.ok_or(InsufficientSampleDataError::NoSamplesPriorToRequestedTimestamp)?;
211220
let requested_sample = video_description.samples.get(requested_sample_idx); // This is only `None` if we no longer have the sample around.
212221
let requested_sample_pts =
213222
requested_sample.map_or(requested_pts, |s| s.presentation_timestamp);
@@ -330,7 +339,7 @@ impl VideoPlayer {
330339
.gop_index_containing_decode_timestamp(
331340
video_description.samples[requested_sample_idx].decode_timestamp,
332341
)
333-
.ok_or(VideoPlayerError::EmptyVideo)?;
342+
.ok_or(InsufficientSampleDataError::NoKeyFramesPriorToRequestedTimestamp)?;
334343

335344
let requested = SampleAndGopIndex {
336345
sample_idx: requested_sample_idx,
@@ -508,7 +517,7 @@ impl VideoPlayer {
508517
video_buffers: &StableIndexDeque<&[u8]>,
509518
) -> Result<(), VideoPlayerError> {
510519
let Some(gop) = video_description.gops.get(gop_idx) else {
511-
return Err(VideoPlayerError::MissingSample);
520+
return Err(InsufficientSampleDataError::ExpectedSampleNotAvailable.into());
512521
};
513522

514523
self.enqueue_samples_of_gop(video_description, gop_idx, &gop.sample_range, video_buffers)

0 commit comments

Comments
 (0)