chore(video): sample decoded frames periodically
This commit is contained in:
@@ -12,4 +12,9 @@ pub trait VideoDecoder: Send {
|
|||||||
/// Returns `Ok(Some(frame))` when a frame is ready, `Ok(None)` if more
|
/// Returns `Ok(Some(frame))` when a frame is ready, `Ok(None)` if more
|
||||||
/// data is needed (e.g., for reordering), or an error.
|
/// data is needed (e.g., for reordering), or an error.
|
||||||
fn decode(&mut self, access_unit: &[u8]) -> Result<Option<VideoFrame>, VideoError>;
|
fn decode(&mut self, access_unit: &[u8]) -> Result<Option<VideoFrame>, VideoError>;
|
||||||
|
|
||||||
|
/// Compact implementation-specific state useful for field diagnostics.
|
||||||
|
fn debug_snapshot(&self) -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -359,6 +359,17 @@ impl VideoDecoder for MediaCodecDecoder {
|
|||||||
Err(VideoError::NotInitialized)
|
Err(VideoError::NotInitialized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug_snapshot(&self) -> Option<String> {
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
{
|
||||||
|
media_codec_debug_snapshot(self.codec.as_ref())
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -847,6 +858,17 @@ impl VideoDecoder for MediaCodecHevcDecoder {
|
|||||||
Err(VideoError::NotInitialized)
|
Err(VideoError::NotInitialized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug_snapshot(&self) -> Option<String> {
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
{
|
||||||
|
media_codec_debug_snapshot(self.codec.as_ref())
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Android MediaCodec AV1 decoder.
|
/// Android MediaCodec AV1 decoder.
|
||||||
@@ -987,6 +1009,35 @@ impl VideoDecoder for MediaCodecAv1Decoder {
|
|||||||
Err(VideoError::NotInitialized)
|
Err(VideoError::NotInitialized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug_snapshot(&self) -> Option<String> {
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
{
|
||||||
|
media_codec_debug_snapshot(self.codec.as_ref())
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
fn media_codec_debug_snapshot(codec: Option<&MediaCodec>) -> Option<String> {
|
||||||
|
let codec = codec?;
|
||||||
|
let format = codec.output_format();
|
||||||
|
Some(format!(
|
||||||
|
"color_format={:?} width={:?} height={:?} stride={:?} slice_height={:?} crop=({:?},{:?},{:?},{:?})",
|
||||||
|
format.i32("color-format"),
|
||||||
|
format.i32("width"),
|
||||||
|
format.i32("height"),
|
||||||
|
format.i32("stride"),
|
||||||
|
format.i32("slice-height"),
|
||||||
|
format.i32("crop-left"),
|
||||||
|
format.i32("crop-top"),
|
||||||
|
format.i32("crop-right"),
|
||||||
|
format.i32("crop-bottom"),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
|
|||||||
@@ -177,6 +177,10 @@ fn i420_sample(data: &[u8], width: u32, height: u32) -> serde_json::Value {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn should_log_video_sample(frame_no: u64, is_keyframe: bool) -> bool {
|
||||||
|
frame_no <= 5 || is_keyframe || frame_no % 30 == 0
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve a quality string from the UI to a QualityProfile.
|
/// Resolve a quality string from the UI to a QualityProfile.
|
||||||
/// Returns None for "auto" (use default adaptive behavior).
|
/// Returns None for "auto" (use default adaptive behavior).
|
||||||
fn resolve_quality(quality: &str) -> Option<QualityProfile> {
|
fn resolve_quality(quality: &str) -> Option<QualityProfile> {
|
||||||
@@ -1321,7 +1325,7 @@ impl CallEngine {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if video_reassembled_samples <= 5 {
|
if should_log_video_sample(video_reassembled_samples, is_kf) {
|
||||||
crate::emit_call_debug(
|
crate::emit_call_debug(
|
||||||
&recv_app,
|
&recv_app,
|
||||||
"video:reassembled_frame",
|
"video:reassembled_frame",
|
||||||
@@ -1401,6 +1405,8 @@ impl CallEngine {
|
|||||||
"yuv_bytes": yuv_frame.data.len(),
|
"yuv_bytes": yuv_frame.data.len(),
|
||||||
"jpeg_ok": jpeg_ok,
|
"jpeg_ok": jpeg_ok,
|
||||||
"platform": "android",
|
"platform": "android",
|
||||||
|
"source_is_keyframe": is_kf,
|
||||||
|
"decoder_debug": dec.debug_snapshot(),
|
||||||
"i420_sample": i420_sample(
|
"i420_sample": i420_sample(
|
||||||
&yuv_frame.data,
|
&yuv_frame.data,
|
||||||
yuv_frame.width,
|
yuv_frame.width,
|
||||||
@@ -1409,7 +1415,7 @@ impl CallEngine {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if video_decoded_samples <= 5 {
|
if should_log_video_sample(video_decoded_samples, is_kf) {
|
||||||
crate::emit_call_debug(
|
crate::emit_call_debug(
|
||||||
&recv_app,
|
&recv_app,
|
||||||
"video:decoded_frame_sample",
|
"video:decoded_frame_sample",
|
||||||
@@ -1422,6 +1428,8 @@ impl CallEngine {
|
|||||||
"yuv_bytes": yuv_frame.data.len(),
|
"yuv_bytes": yuv_frame.data.len(),
|
||||||
"jpeg_ok": jpeg_ok,
|
"jpeg_ok": jpeg_ok,
|
||||||
"platform": "android",
|
"platform": "android",
|
||||||
|
"source_is_keyframe": is_kf,
|
||||||
|
"decoder_debug": dec.debug_snapshot(),
|
||||||
"i420_sample": i420_sample(
|
"i420_sample": i420_sample(
|
||||||
&yuv_frame.data,
|
&yuv_frame.data,
|
||||||
yuv_frame.width,
|
yuv_frame.width,
|
||||||
@@ -2608,7 +2616,7 @@ impl CallEngine {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if video_reassembled_samples <= 5 {
|
if should_log_video_sample(video_reassembled_samples, is_kf) {
|
||||||
crate::emit_call_debug(
|
crate::emit_call_debug(
|
||||||
&recv_app,
|
&recv_app,
|
||||||
"video:reassembled_frame",
|
"video:reassembled_frame",
|
||||||
@@ -2692,6 +2700,8 @@ impl CallEngine {
|
|||||||
"yuv_bytes": yuv_frame.data.len(),
|
"yuv_bytes": yuv_frame.data.len(),
|
||||||
"jpeg_ok": jpeg_ok,
|
"jpeg_ok": jpeg_ok,
|
||||||
"platform": "desktop",
|
"platform": "desktop",
|
||||||
|
"source_is_keyframe": is_kf,
|
||||||
|
"decoder_debug": dec.debug_snapshot(),
|
||||||
"i420_sample": i420_sample(
|
"i420_sample": i420_sample(
|
||||||
&yuv_frame.data,
|
&yuv_frame.data,
|
||||||
yuv_frame.width,
|
yuv_frame.width,
|
||||||
@@ -2700,7 +2710,7 @@ impl CallEngine {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if video_decoded_samples <= 5 {
|
if should_log_video_sample(video_decoded_samples, is_kf) {
|
||||||
crate::emit_call_debug(
|
crate::emit_call_debug(
|
||||||
&recv_app,
|
&recv_app,
|
||||||
"video:decoded_frame_sample",
|
"video:decoded_frame_sample",
|
||||||
@@ -2713,6 +2723,8 @@ impl CallEngine {
|
|||||||
"yuv_bytes": yuv_frame.data.len(),
|
"yuv_bytes": yuv_frame.data.len(),
|
||||||
"jpeg_ok": jpeg_ok,
|
"jpeg_ok": jpeg_ok,
|
||||||
"platform": "desktop",
|
"platform": "desktop",
|
||||||
|
"source_is_keyframe": is_kf,
|
||||||
|
"decoder_debug": dec.debug_snapshot(),
|
||||||
"i420_sample": i420_sample(
|
"i420_sample": i420_sample(
|
||||||
&yuv_frame.data,
|
&yuv_frame.data,
|
||||||
yuv_frame.width,
|
yuv_frame.width,
|
||||||
|
|||||||
Reference in New Issue
Block a user