xref: /aosp_15_r20/external/webrtc/video/decode_synchronizer.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #ifndef VIDEO_DECODE_SYNCHRONIZER_H_
12*d9f75844SAndroid Build Coastguard Worker #define VIDEO_DECODE_SYNCHRONIZER_H_
13*d9f75844SAndroid Build Coastguard Worker 
14*d9f75844SAndroid Build Coastguard Worker #include <stdint.h>
15*d9f75844SAndroid Build Coastguard Worker 
16*d9f75844SAndroid Build Coastguard Worker #include <functional>
17*d9f75844SAndroid Build Coastguard Worker #include <memory>
18*d9f75844SAndroid Build Coastguard Worker #include <set>
19*d9f75844SAndroid Build Coastguard Worker #include <utility>
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/metronome/metronome.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/sequence_checker.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/task_queue_base.h"
25*d9f75844SAndroid Build Coastguard Worker #include "api/units/timestamp.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
27*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread_annotations.h"
28*d9f75844SAndroid Build Coastguard Worker #include "video/frame_decode_scheduler.h"
29*d9f75844SAndroid Build Coastguard Worker #include "video/frame_decode_timing.h"
30*d9f75844SAndroid Build Coastguard Worker 
31*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
32*d9f75844SAndroid Build Coastguard Worker 
33*d9f75844SAndroid Build Coastguard Worker // DecodeSynchronizer synchronizes the frame scheduling by coalescing decoding
34*d9f75844SAndroid Build Coastguard Worker // on the metronome.
35*d9f75844SAndroid Build Coastguard Worker //
36*d9f75844SAndroid Build Coastguard Worker // A video receive stream can use the DecodeSynchronizer by receiving a
37*d9f75844SAndroid Build Coastguard Worker // FrameDecodeScheduler instance with `CreateSynchronizedFrameScheduler()`.
38*d9f75844SAndroid Build Coastguard Worker // This instance implements FrameDecodeScheduler and can be used as a normal
39*d9f75844SAndroid Build Coastguard Worker // scheduler. This instance is owned by the receive stream, and is borrowed by
40*d9f75844SAndroid Build Coastguard Worker // the DecodeSynchronizer. The DecodeSynchronizer will stop borrowing the
41*d9f75844SAndroid Build Coastguard Worker // instance when `FrameDecodeScheduler::Stop()` is called, after which the
42*d9f75844SAndroid Build Coastguard Worker // scheduler may be destroyed by the receive stream.
43*d9f75844SAndroid Build Coastguard Worker //
44*d9f75844SAndroid Build Coastguard Worker // When a frame is scheduled for decode by a receive stream using the
45*d9f75844SAndroid Build Coastguard Worker // DecodeSynchronizer, it will instead be executed on the metronome during the
46*d9f75844SAndroid Build Coastguard Worker // tick interval where `max_decode_time` occurs. For example, if a frame is
47*d9f75844SAndroid Build Coastguard Worker // scheduled for decode in 50ms and the tick interval is 20ms, then the frame
48*d9f75844SAndroid Build Coastguard Worker // will be released for decoding in 2 ticks. See below for illustration,
49*d9f75844SAndroid Build Coastguard Worker //
50*d9f75844SAndroid Build Coastguard Worker // In the case where the decode time is in the past, or must occur before the
51*d9f75844SAndroid Build Coastguard Worker // next metronome tick then the frame will be released right away, allowing a
52*d9f75844SAndroid Build Coastguard Worker // delayed stream to catch up quickly.
53*d9f75844SAndroid Build Coastguard Worker //
54*d9f75844SAndroid Build Coastguard Worker // DecodeSynchronizer is single threaded - all method calls must run on the
55*d9f75844SAndroid Build Coastguard Worker // `worker_queue_`.
56*d9f75844SAndroid Build Coastguard Worker class DecodeSynchronizer {
57*d9f75844SAndroid Build Coastguard Worker  public:
58*d9f75844SAndroid Build Coastguard Worker   DecodeSynchronizer(Clock* clock,
59*d9f75844SAndroid Build Coastguard Worker                      Metronome* metronome,
60*d9f75844SAndroid Build Coastguard Worker                      TaskQueueBase* worker_queue);
61*d9f75844SAndroid Build Coastguard Worker   ~DecodeSynchronizer();
62*d9f75844SAndroid Build Coastguard Worker   DecodeSynchronizer(const DecodeSynchronizer&) = delete;
63*d9f75844SAndroid Build Coastguard Worker   DecodeSynchronizer& operator=(const DecodeSynchronizer&) = delete;
64*d9f75844SAndroid Build Coastguard Worker 
65*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<FrameDecodeScheduler> CreateSynchronizedFrameScheduler();
66*d9f75844SAndroid Build Coastguard Worker 
67*d9f75844SAndroid Build Coastguard Worker  private:
68*d9f75844SAndroid Build Coastguard Worker   class ScheduledFrame {
69*d9f75844SAndroid Build Coastguard Worker    public:
70*d9f75844SAndroid Build Coastguard Worker     ScheduledFrame(uint32_t rtp_timestamp,
71*d9f75844SAndroid Build Coastguard Worker                    FrameDecodeTiming::FrameSchedule schedule,
72*d9f75844SAndroid Build Coastguard Worker                    FrameDecodeScheduler::FrameReleaseCallback callback);
73*d9f75844SAndroid Build Coastguard Worker 
74*d9f75844SAndroid Build Coastguard Worker     // Disallow copy since `callback` should only be moved.
75*d9f75844SAndroid Build Coastguard Worker     ScheduledFrame(const ScheduledFrame&) = delete;
76*d9f75844SAndroid Build Coastguard Worker     ScheduledFrame& operator=(const ScheduledFrame&) = delete;
77*d9f75844SAndroid Build Coastguard Worker     ScheduledFrame(ScheduledFrame&&) = default;
78*d9f75844SAndroid Build Coastguard Worker     ScheduledFrame& operator=(ScheduledFrame&&) = default;
79*d9f75844SAndroid Build Coastguard Worker 
80*d9f75844SAndroid Build Coastguard Worker     // Executes `callback_`.
81*d9f75844SAndroid Build Coastguard Worker     void RunFrameReleaseCallback() &&;
82*d9f75844SAndroid Build Coastguard Worker 
rtp_timestamp()83*d9f75844SAndroid Build Coastguard Worker     uint32_t rtp_timestamp() const { return rtp_timestamp_; }
84*d9f75844SAndroid Build Coastguard Worker     Timestamp LatestDecodeTime() const;
85*d9f75844SAndroid Build Coastguard Worker 
86*d9f75844SAndroid Build Coastguard Worker    private:
87*d9f75844SAndroid Build Coastguard Worker     uint32_t rtp_timestamp_;
88*d9f75844SAndroid Build Coastguard Worker     FrameDecodeTiming::FrameSchedule schedule_;
89*d9f75844SAndroid Build Coastguard Worker     FrameDecodeScheduler::FrameReleaseCallback callback_;
90*d9f75844SAndroid Build Coastguard Worker   };
91*d9f75844SAndroid Build Coastguard Worker 
92*d9f75844SAndroid Build Coastguard Worker   class SynchronizedFrameDecodeScheduler : public FrameDecodeScheduler {
93*d9f75844SAndroid Build Coastguard Worker    public:
94*d9f75844SAndroid Build Coastguard Worker     explicit SynchronizedFrameDecodeScheduler(DecodeSynchronizer* sync);
95*d9f75844SAndroid Build Coastguard Worker     ~SynchronizedFrameDecodeScheduler() override;
96*d9f75844SAndroid Build Coastguard Worker 
97*d9f75844SAndroid Build Coastguard Worker     // Releases the outstanding frame for decoding. This invalidates
98*d9f75844SAndroid Build Coastguard Worker     // `next_frame_`. There must be a frame scheduled.
99*d9f75844SAndroid Build Coastguard Worker     ScheduledFrame ReleaseNextFrame();
100*d9f75844SAndroid Build Coastguard Worker 
101*d9f75844SAndroid Build Coastguard Worker     // Returns `next_frame_.schedule.max_decode_time`. There must be a frame
102*d9f75844SAndroid Build Coastguard Worker     // scheduled when this is called.
103*d9f75844SAndroid Build Coastguard Worker     Timestamp LatestDecodeTime();
104*d9f75844SAndroid Build Coastguard Worker 
105*d9f75844SAndroid Build Coastguard Worker     // FrameDecodeScheduler implementation.
106*d9f75844SAndroid Build Coastguard Worker     absl::optional<uint32_t> ScheduledRtpTimestamp() override;
107*d9f75844SAndroid Build Coastguard Worker     void ScheduleFrame(uint32_t rtp,
108*d9f75844SAndroid Build Coastguard Worker                        FrameDecodeTiming::FrameSchedule schedule,
109*d9f75844SAndroid Build Coastguard Worker                        FrameReleaseCallback cb) override;
110*d9f75844SAndroid Build Coastguard Worker     void CancelOutstanding() override;
111*d9f75844SAndroid Build Coastguard Worker     void Stop() override;
112*d9f75844SAndroid Build Coastguard Worker 
113*d9f75844SAndroid Build Coastguard Worker    private:
114*d9f75844SAndroid Build Coastguard Worker     DecodeSynchronizer* sync_;
115*d9f75844SAndroid Build Coastguard Worker     absl::optional<ScheduledFrame> next_frame_;
116*d9f75844SAndroid Build Coastguard Worker     bool stopped_ = false;
117*d9f75844SAndroid Build Coastguard Worker   };
118*d9f75844SAndroid Build Coastguard Worker 
119*d9f75844SAndroid Build Coastguard Worker   void OnFrameScheduled(SynchronizedFrameDecodeScheduler* scheduler);
120*d9f75844SAndroid Build Coastguard Worker   void RemoveFrameScheduler(SynchronizedFrameDecodeScheduler* scheduler);
121*d9f75844SAndroid Build Coastguard Worker 
122*d9f75844SAndroid Build Coastguard Worker   void ScheduleNextTick();
123*d9f75844SAndroid Build Coastguard Worker   void OnTick();
124*d9f75844SAndroid Build Coastguard Worker 
125*d9f75844SAndroid Build Coastguard Worker   Clock* const clock_;
126*d9f75844SAndroid Build Coastguard Worker   TaskQueueBase* const worker_queue_;
127*d9f75844SAndroid Build Coastguard Worker   Metronome* const metronome_;
128*d9f75844SAndroid Build Coastguard Worker 
129*d9f75844SAndroid Build Coastguard Worker   Timestamp expected_next_tick_ = Timestamp::PlusInfinity();
130*d9f75844SAndroid Build Coastguard Worker   std::set<SynchronizedFrameDecodeScheduler*> schedulers_
131*d9f75844SAndroid Build Coastguard Worker       RTC_GUARDED_BY(worker_queue_);
132*d9f75844SAndroid Build Coastguard Worker   ScopedTaskSafetyDetached safety_;
133*d9f75844SAndroid Build Coastguard Worker };
134*d9f75844SAndroid Build Coastguard Worker 
135*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
136*d9f75844SAndroid Build Coastguard Worker 
137*d9f75844SAndroid Build Coastguard Worker #endif  // VIDEO_DECODE_SYNCHRONIZER_H_
138