| /* |
| * Copyright (c) 2025 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #ifndef VIDEO_TIMING_SIMULATOR_RENDERING_TRACKER_H_ |
| #define VIDEO_TIMING_SIMULATOR_RENDERING_TRACKER_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| |
| #include "absl/base/nullability.h" |
| #include "api/environment/environment.h" |
| #include "api/sequence_checker.h" |
| #include "api/task_queue/pending_task_safety_flag.h" |
| #include "api/task_queue/task_queue_base.h" |
| #include "api/units/time_delta.h" |
| #include "api/video/encoded_frame.h" |
| #include "api/video/video_content_type.h" |
| #include "api/video/video_frame.h" |
| #include "api/video/video_sink_interface.h" |
| #include "api/video/video_timing.h" |
| #include "modules/video_coding/timing/timing.h" |
| #include "rtc_base/thread_annotations.h" |
| #include "video/timing/simulator/assembler.h" |
| #include "video/video_stream_buffer_controller.h" |
| |
| namespace webrtc::video_timing_simulator { |
| |
| // Callback for observer events. Implemented by the metadata collector. |
| class RenderingTrackerEvents { |
| public: |
| virtual ~RenderingTrackerEvents() = default; |
| virtual void OnDecodedFrame(const EncodedFrame& decoded_frame, |
| int frames_dropped, |
| TimeDelta jitter_buffer_minimum_delay, |
| TimeDelta jitter_buffer_target_delay, |
| TimeDelta jitter_buffer_delay) = 0; |
| virtual void OnRenderedFrame(const VideoFrame& rendered_frame) = 0; |
| }; |
| |
| // The `RenderingTracker` takes a sequence of assembled `EncodedFrame`s |
| // belonging to the same stream and produces a sequence of decoded and rendered |
| // `VideoFrame`s. This is done by calling the `VideoStreamBufferController` and |
| // passing the (fake) decoded frames through the `IncomingVideoStream`. |
| // |
| // The outputs of this class are interesting for evaluating the performance of |
| // the dejittering components of the video jitter buffer. |
| class RenderingTracker : public AssembledFrameCallback, |
| public FrameSchedulingReceiver, |
| public VideoStreamBufferControllerStatsObserver, |
| public VideoSinkInterface<VideoFrame> { |
| public: |
| // All members of the config should be explicitly set by the user. |
| struct Config { |
| uint32_t ssrc = 0; |
| // Fixed render delay term added to the render timestamps. |
| TimeDelta render_delay = TimeDelta::MinusInfinity(); |
| }; |
| |
| RenderingTracker(const Environment& env, |
| const Config& config, |
| std::unique_ptr<VCMTiming> video_timing, |
| RenderingTrackerEvents* absl_nonnull observer); |
| ~RenderingTracker() override; |
| |
| RenderingTracker(const RenderingTracker&) = delete; |
| RenderingTracker& operator=(const RenderingTracker&) = delete; |
| |
| void SetDecodedFrameIdCallback( |
| DecodedFrameIdCallback* absl_nonnull decoded_id_cb); |
| |
| // Inserts `assembled_frame` into the `VideoStreamBufferController` and logs |
| // any rendered frames to the `observer_`. |
| void OnAssembledFrame(std::unique_ptr<EncodedFrame> assembled_frame) override; |
| |
| private: |
| struct VideoStreamBufferControllerObserverDecodableStats { |
| TimeDelta jitter_buffer_delay = TimeDelta::Zero(); |
| TimeDelta jitter_buffer_target_delay = TimeDelta::Zero(); |
| TimeDelta jitter_buffer_minimum_delay = TimeDelta::Zero(); |
| }; |
| |
| // Implements `FrameSchedulingReceiver`. |
| void OnEncodedFrame(std::unique_ptr<EncodedFrame> encoded_frame) override; |
| void OnDecodableFrameTimeout(TimeDelta wait_time) override; |
| |
| // Implements `VideoStreamBufferControllerStatsObserver`. |
| void OnCompleteFrame(bool, size_t, VideoContentType) override {} |
| void OnDroppedFrames(uint32_t frames_dropped) override; |
| void OnDecodableFrame(TimeDelta jitter_buffer_delay, |
| TimeDelta jitter_buffer_target_delay, |
| TimeDelta jitter_buffer_minimum_delay) override; |
| void OnFrameBufferTimingsUpdated(int, int, int, int, int, int) override {} |
| void OnTimingFrameInfoUpdated(const TimingFrameInfo&) override {} |
| |
| // Implements `VideoSinkInterface<VideoFrame>`. |
| void OnFrame(const VideoFrame& decoded_frame) override; |
| |
| void ResetVideoStreamBufferControllerObserverStats(); |
| |
| // Environment. |
| SequenceChecker sequence_checker_; |
| const Environment env_; |
| const Config config_; |
| TaskQueueBase* const simulator_queue_; |
| |
| // Worker objects. |
| std::unique_ptr<VCMTiming> video_timing_ RTC_GUARDED_BY(sequence_checker_); |
| VideoStreamBufferController video_stream_buffer_controller_ |
| RTC_GUARDED_BY(sequence_checker_); |
| std::unique_ptr<VideoSinkInterface<VideoFrame>> incoming_video_stream_ |
| RTC_GUARDED_BY(sequence_checker_); |
| |
| // Stats state. This is needed since the stats and the decodable frame are |
| // provided by the VSBC on different callbacks, but we want to log the |
| // the corresponding information simultaneously to our callback. |
| std::optional<int> vsbc_frames_dropped_; |
| std::optional<VideoStreamBufferControllerObserverDecodableStats> |
| vsbc_decodable_stats_; |
| |
| // Outputs. |
| RenderingTrackerEvents& observer_; |
| DecodedFrameIdCallback* absl_nullable decoded_frame_id_cb_ |
| RTC_GUARDED_BY(sequence_checker_); |
| |
| // Task safety. By having this member be destroyed first, any outstanding |
| // task referring to other members should not run. |
| ScopedTaskSafety safety_; |
| }; |
| |
| } // namespace webrtc::video_timing_simulator |
| |
| #endif // VIDEO_TIMING_SIMULATOR_RENDERING_TRACKER_H_ |