xref: /aosp_15_r20/external/webrtc/video/video_stream_decoder_impl.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2018 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 #include "video/video_stream_decoder_impl.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <memory>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
16*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/mod_ops.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
20*d9f75844SAndroid Build Coastguard Worker 
VideoStreamDecoderImpl(VideoStreamDecoderInterface::Callbacks * callbacks,VideoDecoderFactory * decoder_factory,TaskQueueFactory * task_queue_factory,std::map<int,std::pair<SdpVideoFormat,int>> decoder_settings,const FieldTrialsView * field_trials)21*d9f75844SAndroid Build Coastguard Worker VideoStreamDecoderImpl::VideoStreamDecoderImpl(
22*d9f75844SAndroid Build Coastguard Worker     VideoStreamDecoderInterface::Callbacks* callbacks,
23*d9f75844SAndroid Build Coastguard Worker     VideoDecoderFactory* decoder_factory,
24*d9f75844SAndroid Build Coastguard Worker     TaskQueueFactory* task_queue_factory,
25*d9f75844SAndroid Build Coastguard Worker     std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings,
26*d9f75844SAndroid Build Coastguard Worker     const FieldTrialsView* field_trials)
27*d9f75844SAndroid Build Coastguard Worker     : field_trials_(field_trials),
28*d9f75844SAndroid Build Coastguard Worker       timing_(Clock::GetRealTimeClock(), *field_trials_),
29*d9f75844SAndroid Build Coastguard Worker       decode_callbacks_(this),
30*d9f75844SAndroid Build Coastguard Worker       next_frame_info_index_(0),
31*d9f75844SAndroid Build Coastguard Worker       callbacks_(callbacks),
32*d9f75844SAndroid Build Coastguard Worker       keyframe_required_(true),
33*d9f75844SAndroid Build Coastguard Worker       decoder_factory_(decoder_factory),
34*d9f75844SAndroid Build Coastguard Worker       decoder_settings_(std::move(decoder_settings)),
35*d9f75844SAndroid Build Coastguard Worker       shut_down_(false),
36*d9f75844SAndroid Build Coastguard Worker       frame_buffer_(Clock::GetRealTimeClock(), &timing_, *field_trials_),
37*d9f75844SAndroid Build Coastguard Worker       bookkeeping_queue_(task_queue_factory->CreateTaskQueue(
38*d9f75844SAndroid Build Coastguard Worker           "video_stream_decoder_bookkeeping_queue",
39*d9f75844SAndroid Build Coastguard Worker           TaskQueueFactory::Priority::NORMAL)),
40*d9f75844SAndroid Build Coastguard Worker       decode_queue_(task_queue_factory->CreateTaskQueue(
41*d9f75844SAndroid Build Coastguard Worker           "video_stream_decoder_decode_queue",
42*d9f75844SAndroid Build Coastguard Worker           TaskQueueFactory::Priority::NORMAL)) {
43*d9f75844SAndroid Build Coastguard Worker   bookkeeping_queue_.PostTask([this]() {
44*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
45*d9f75844SAndroid Build Coastguard Worker     StartNextDecode();
46*d9f75844SAndroid Build Coastguard Worker   });
47*d9f75844SAndroid Build Coastguard Worker }
48*d9f75844SAndroid Build Coastguard Worker 
~VideoStreamDecoderImpl()49*d9f75844SAndroid Build Coastguard Worker VideoStreamDecoderImpl::~VideoStreamDecoderImpl() {
50*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&shut_down_mutex_);
51*d9f75844SAndroid Build Coastguard Worker   shut_down_ = true;
52*d9f75844SAndroid Build Coastguard Worker }
53*d9f75844SAndroid Build Coastguard Worker 
OnFrame(std::unique_ptr<EncodedFrame> frame)54*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::OnFrame(std::unique_ptr<EncodedFrame> frame) {
55*d9f75844SAndroid Build Coastguard Worker   if (!bookkeeping_queue_.IsCurrent()) {
56*d9f75844SAndroid Build Coastguard Worker     bookkeeping_queue_.PostTask([this, frame = std::move(frame)]() mutable {
57*d9f75844SAndroid Build Coastguard Worker       OnFrame(std::move(frame));
58*d9f75844SAndroid Build Coastguard Worker       return true;
59*d9f75844SAndroid Build Coastguard Worker     });
60*d9f75844SAndroid Build Coastguard Worker 
61*d9f75844SAndroid Build Coastguard Worker     return;
62*d9f75844SAndroid Build Coastguard Worker   }
63*d9f75844SAndroid Build Coastguard Worker 
64*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
65*d9f75844SAndroid Build Coastguard Worker 
66*d9f75844SAndroid Build Coastguard Worker   int64_t continuous_frame_id = frame_buffer_.InsertFrame(std::move(frame));
67*d9f75844SAndroid Build Coastguard Worker   if (last_continuous_frame_id_ < continuous_frame_id) {
68*d9f75844SAndroid Build Coastguard Worker     last_continuous_frame_id_ = continuous_frame_id;
69*d9f75844SAndroid Build Coastguard Worker     callbacks_->OnContinuousUntil(last_continuous_frame_id_);
70*d9f75844SAndroid Build Coastguard Worker   }
71*d9f75844SAndroid Build Coastguard Worker }
72*d9f75844SAndroid Build Coastguard Worker 
SetMinPlayoutDelay(TimeDelta min_delay)73*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::SetMinPlayoutDelay(TimeDelta min_delay) {
74*d9f75844SAndroid Build Coastguard Worker   timing_.set_min_playout_delay(min_delay);
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker 
SetMaxPlayoutDelay(TimeDelta max_delay)77*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::SetMaxPlayoutDelay(TimeDelta max_delay) {
78*d9f75844SAndroid Build Coastguard Worker   timing_.set_max_playout_delay(max_delay);
79*d9f75844SAndroid Build Coastguard Worker }
80*d9f75844SAndroid Build Coastguard Worker 
GetDecoder(int payload_type)81*d9f75844SAndroid Build Coastguard Worker VideoDecoder* VideoStreamDecoderImpl::GetDecoder(int payload_type) {
82*d9f75844SAndroid Build Coastguard Worker   if (current_payload_type_ == payload_type) {
83*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(decoder_);
84*d9f75844SAndroid Build Coastguard Worker     return decoder_.get();
85*d9f75844SAndroid Build Coastguard Worker   }
86*d9f75844SAndroid Build Coastguard Worker 
87*d9f75844SAndroid Build Coastguard Worker   current_payload_type_.reset();
88*d9f75844SAndroid Build Coastguard Worker   decoder_.reset();
89*d9f75844SAndroid Build Coastguard Worker 
90*d9f75844SAndroid Build Coastguard Worker   auto decoder_settings_it = decoder_settings_.find(payload_type);
91*d9f75844SAndroid Build Coastguard Worker   if (decoder_settings_it == decoder_settings_.end()) {
92*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Payload type " << payload_type
93*d9f75844SAndroid Build Coastguard Worker                         << " not registered.";
94*d9f75844SAndroid Build Coastguard Worker     return nullptr;
95*d9f75844SAndroid Build Coastguard Worker   }
96*d9f75844SAndroid Build Coastguard Worker 
97*d9f75844SAndroid Build Coastguard Worker   const SdpVideoFormat& video_format = decoder_settings_it->second.first;
98*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<VideoDecoder> decoder =
99*d9f75844SAndroid Build Coastguard Worker       decoder_factory_->CreateVideoDecoder(video_format);
100*d9f75844SAndroid Build Coastguard Worker   if (!decoder) {
101*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to create decoder for payload type "
102*d9f75844SAndroid Build Coastguard Worker                         << payload_type << ".";
103*d9f75844SAndroid Build Coastguard Worker     return nullptr;
104*d9f75844SAndroid Build Coastguard Worker   }
105*d9f75844SAndroid Build Coastguard Worker 
106*d9f75844SAndroid Build Coastguard Worker   VideoDecoder::Settings settings;
107*d9f75844SAndroid Build Coastguard Worker   settings.set_number_of_cores(decoder_settings_it->second.second);
108*d9f75844SAndroid Build Coastguard Worker   if (!decoder->Configure(settings)) {
109*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to initialize decoder for payload type "
110*d9f75844SAndroid Build Coastguard Worker                         << payload_type << ".";
111*d9f75844SAndroid Build Coastguard Worker     return nullptr;
112*d9f75844SAndroid Build Coastguard Worker   }
113*d9f75844SAndroid Build Coastguard Worker 
114*d9f75844SAndroid Build Coastguard Worker   int32_t register_result =
115*d9f75844SAndroid Build Coastguard Worker       decoder->RegisterDecodeCompleteCallback(&decode_callbacks_);
116*d9f75844SAndroid Build Coastguard Worker   if (register_result != WEBRTC_VIDEO_CODEC_OK) {
117*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to register decode callback.";
118*d9f75844SAndroid Build Coastguard Worker     return nullptr;
119*d9f75844SAndroid Build Coastguard Worker   }
120*d9f75844SAndroid Build Coastguard Worker 
121*d9f75844SAndroid Build Coastguard Worker   current_payload_type_.emplace(payload_type);
122*d9f75844SAndroid Build Coastguard Worker   decoder_ = std::move(decoder);
123*d9f75844SAndroid Build Coastguard Worker   return decoder_.get();
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker 
SaveFrameInfo(const EncodedFrame & frame)126*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::SaveFrameInfo(const EncodedFrame& frame) {
127*d9f75844SAndroid Build Coastguard Worker   FrameInfo* frame_info = &frame_info_[next_frame_info_index_];
128*d9f75844SAndroid Build Coastguard Worker   frame_info->timestamp = frame.Timestamp();
129*d9f75844SAndroid Build Coastguard Worker   frame_info->decode_start_time_ms = rtc::TimeMillis();
130*d9f75844SAndroid Build Coastguard Worker   frame_info->render_time_us = frame.RenderTimeMs() * 1000;
131*d9f75844SAndroid Build Coastguard Worker   frame_info->content_type = frame.EncodedImage().content_type_;
132*d9f75844SAndroid Build Coastguard Worker 
133*d9f75844SAndroid Build Coastguard Worker   next_frame_info_index_ = Add<kFrameInfoMemory>(next_frame_info_index_, 1);
134*d9f75844SAndroid Build Coastguard Worker }
135*d9f75844SAndroid Build Coastguard Worker 
StartNextDecode()136*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::StartNextDecode() {
137*d9f75844SAndroid Build Coastguard Worker   int64_t max_wait_time = keyframe_required_ ? 200 : 3000;
138*d9f75844SAndroid Build Coastguard Worker 
139*d9f75844SAndroid Build Coastguard Worker   frame_buffer_.NextFrame(max_wait_time, keyframe_required_,
140*d9f75844SAndroid Build Coastguard Worker                           bookkeeping_queue_.Get(),
141*d9f75844SAndroid Build Coastguard Worker                           [this](std::unique_ptr<EncodedFrame> frame) {
142*d9f75844SAndroid Build Coastguard Worker                             RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
143*d9f75844SAndroid Build Coastguard Worker                             OnNextFrameCallback(std::move(frame));
144*d9f75844SAndroid Build Coastguard Worker                           });
145*d9f75844SAndroid Build Coastguard Worker }
146*d9f75844SAndroid Build Coastguard Worker 
OnNextFrameCallback(std::unique_ptr<EncodedFrame> frame)147*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::OnNextFrameCallback(
148*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<EncodedFrame> frame) {
149*d9f75844SAndroid Build Coastguard Worker   if (frame) {
150*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(frame);
151*d9f75844SAndroid Build Coastguard Worker     SaveFrameInfo(*frame);
152*d9f75844SAndroid Build Coastguard Worker 
153*d9f75844SAndroid Build Coastguard Worker     MutexLock lock(&shut_down_mutex_);
154*d9f75844SAndroid Build Coastguard Worker     if (shut_down_) {
155*d9f75844SAndroid Build Coastguard Worker       return;
156*d9f75844SAndroid Build Coastguard Worker     }
157*d9f75844SAndroid Build Coastguard Worker 
158*d9f75844SAndroid Build Coastguard Worker     decode_queue_.PostTask([this, frame = std::move(frame)]() mutable {
159*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_RUN_ON(&decode_queue_);
160*d9f75844SAndroid Build Coastguard Worker       DecodeResult decode_result = DecodeFrame(std::move(frame));
161*d9f75844SAndroid Build Coastguard Worker       bookkeeping_queue_.PostTask([this, decode_result]() {
162*d9f75844SAndroid Build Coastguard Worker         RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
163*d9f75844SAndroid Build Coastguard Worker         switch (decode_result) {
164*d9f75844SAndroid Build Coastguard Worker           case kOk: {
165*d9f75844SAndroid Build Coastguard Worker             keyframe_required_ = false;
166*d9f75844SAndroid Build Coastguard Worker             break;
167*d9f75844SAndroid Build Coastguard Worker           }
168*d9f75844SAndroid Build Coastguard Worker           case kOkRequestKeyframe: {
169*d9f75844SAndroid Build Coastguard Worker             callbacks_->OnNonDecodableState();
170*d9f75844SAndroid Build Coastguard Worker             keyframe_required_ = false;
171*d9f75844SAndroid Build Coastguard Worker             break;
172*d9f75844SAndroid Build Coastguard Worker           }
173*d9f75844SAndroid Build Coastguard Worker           case kDecodeFailure: {
174*d9f75844SAndroid Build Coastguard Worker             callbacks_->OnNonDecodableState();
175*d9f75844SAndroid Build Coastguard Worker             keyframe_required_ = true;
176*d9f75844SAndroid Build Coastguard Worker             break;
177*d9f75844SAndroid Build Coastguard Worker           }
178*d9f75844SAndroid Build Coastguard Worker         }
179*d9f75844SAndroid Build Coastguard Worker         StartNextDecode();
180*d9f75844SAndroid Build Coastguard Worker       });
181*d9f75844SAndroid Build Coastguard Worker     });
182*d9f75844SAndroid Build Coastguard Worker   } else {
183*d9f75844SAndroid Build Coastguard Worker     callbacks_->OnNonDecodableState();
184*d9f75844SAndroid Build Coastguard Worker     // The `frame_buffer_` requires the frame callback function to complete
185*d9f75844SAndroid Build Coastguard Worker     // before NextFrame is called again. For this reason we call
186*d9f75844SAndroid Build Coastguard Worker     // StartNextDecode in a later task to allow this task to complete first.
187*d9f75844SAndroid Build Coastguard Worker     bookkeeping_queue_.PostTask([this]() {
188*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
189*d9f75844SAndroid Build Coastguard Worker       StartNextDecode();
190*d9f75844SAndroid Build Coastguard Worker     });
191*d9f75844SAndroid Build Coastguard Worker   }
192*d9f75844SAndroid Build Coastguard Worker }
193*d9f75844SAndroid Build Coastguard Worker 
DecodeFrame(std::unique_ptr<EncodedFrame> frame)194*d9f75844SAndroid Build Coastguard Worker VideoStreamDecoderImpl::DecodeResult VideoStreamDecoderImpl::DecodeFrame(
195*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<EncodedFrame> frame) {
196*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(frame);
197*d9f75844SAndroid Build Coastguard Worker 
198*d9f75844SAndroid Build Coastguard Worker   VideoDecoder* decoder = GetDecoder(frame->PayloadType());
199*d9f75844SAndroid Build Coastguard Worker   if (!decoder) {
200*d9f75844SAndroid Build Coastguard Worker     return kDecodeFailure;
201*d9f75844SAndroid Build Coastguard Worker   }
202*d9f75844SAndroid Build Coastguard Worker 
203*d9f75844SAndroid Build Coastguard Worker   int32_t decode_result = decoder->Decode(frame->EncodedImage(),     //
204*d9f75844SAndroid Build Coastguard Worker                                           /*missing_frames=*/false,  //
205*d9f75844SAndroid Build Coastguard Worker                                           frame->RenderTimeMs());
206*d9f75844SAndroid Build Coastguard Worker   switch (decode_result) {
207*d9f75844SAndroid Build Coastguard Worker     case WEBRTC_VIDEO_CODEC_OK: {
208*d9f75844SAndroid Build Coastguard Worker       return kOk;
209*d9f75844SAndroid Build Coastguard Worker     }
210*d9f75844SAndroid Build Coastguard Worker     case WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME: {
211*d9f75844SAndroid Build Coastguard Worker       return kOkRequestKeyframe;
212*d9f75844SAndroid Build Coastguard Worker     }
213*d9f75844SAndroid Build Coastguard Worker     default:
214*d9f75844SAndroid Build Coastguard Worker       return kDecodeFailure;
215*d9f75844SAndroid Build Coastguard Worker   }
216*d9f75844SAndroid Build Coastguard Worker }
217*d9f75844SAndroid Build Coastguard Worker 
GetFrameInfo(int64_t timestamp)218*d9f75844SAndroid Build Coastguard Worker VideoStreamDecoderImpl::FrameInfo* VideoStreamDecoderImpl::GetFrameInfo(
219*d9f75844SAndroid Build Coastguard Worker     int64_t timestamp) {
220*d9f75844SAndroid Build Coastguard Worker   int start_time_index = next_frame_info_index_;
221*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kFrameInfoMemory; ++i) {
222*d9f75844SAndroid Build Coastguard Worker     start_time_index = Subtract<kFrameInfoMemory>(start_time_index, 1);
223*d9f75844SAndroid Build Coastguard Worker 
224*d9f75844SAndroid Build Coastguard Worker     if (frame_info_[start_time_index].timestamp == timestamp)
225*d9f75844SAndroid Build Coastguard Worker       return &frame_info_[start_time_index];
226*d9f75844SAndroid Build Coastguard Worker   }
227*d9f75844SAndroid Build Coastguard Worker 
228*d9f75844SAndroid Build Coastguard Worker   return nullptr;
229*d9f75844SAndroid Build Coastguard Worker }
230*d9f75844SAndroid Build Coastguard Worker 
OnDecodedFrameCallback(VideoFrame & decoded_image,absl::optional<int32_t> decode_time_ms,absl::optional<uint8_t> qp)231*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::OnDecodedFrameCallback(
232*d9f75844SAndroid Build Coastguard Worker     VideoFrame& decoded_image,
233*d9f75844SAndroid Build Coastguard Worker     absl::optional<int32_t> decode_time_ms,
234*d9f75844SAndroid Build Coastguard Worker     absl::optional<uint8_t> qp) {
235*d9f75844SAndroid Build Coastguard Worker   int64_t decode_stop_time_ms = rtc::TimeMillis();
236*d9f75844SAndroid Build Coastguard Worker 
237*d9f75844SAndroid Build Coastguard Worker   bookkeeping_queue_.PostTask([this, decode_stop_time_ms, decoded_image,
238*d9f75844SAndroid Build Coastguard Worker                                decode_time_ms, qp]() mutable {
239*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
240*d9f75844SAndroid Build Coastguard Worker 
241*d9f75844SAndroid Build Coastguard Worker     FrameInfo* frame_info = GetFrameInfo(decoded_image.timestamp());
242*d9f75844SAndroid Build Coastguard Worker     if (!frame_info) {
243*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "No frame information found for frame with timestamp"
244*d9f75844SAndroid Build Coastguard Worker                         << decoded_image.timestamp();
245*d9f75844SAndroid Build Coastguard Worker       return;
246*d9f75844SAndroid Build Coastguard Worker     }
247*d9f75844SAndroid Build Coastguard Worker 
248*d9f75844SAndroid Build Coastguard Worker     Callbacks::FrameInfo callback_info;
249*d9f75844SAndroid Build Coastguard Worker     callback_info.content_type = frame_info->content_type;
250*d9f75844SAndroid Build Coastguard Worker 
251*d9f75844SAndroid Build Coastguard Worker     if (qp)
252*d9f75844SAndroid Build Coastguard Worker       callback_info.qp.emplace(*qp);
253*d9f75844SAndroid Build Coastguard Worker 
254*d9f75844SAndroid Build Coastguard Worker     if (!decode_time_ms) {
255*d9f75844SAndroid Build Coastguard Worker       decode_time_ms = decode_stop_time_ms - frame_info->decode_start_time_ms;
256*d9f75844SAndroid Build Coastguard Worker     }
257*d9f75844SAndroid Build Coastguard Worker     decoded_image.set_processing_time(
258*d9f75844SAndroid Build Coastguard Worker         {Timestamp::Millis(frame_info->decode_start_time_ms),
259*d9f75844SAndroid Build Coastguard Worker          Timestamp::Millis(frame_info->decode_start_time_ms +
260*d9f75844SAndroid Build Coastguard Worker                            *decode_time_ms)});
261*d9f75844SAndroid Build Coastguard Worker     decoded_image.set_timestamp_us(frame_info->render_time_us);
262*d9f75844SAndroid Build Coastguard Worker     timing_.StopDecodeTimer(TimeDelta::Millis(*decode_time_ms),
263*d9f75844SAndroid Build Coastguard Worker                             Timestamp::Millis(decode_stop_time_ms));
264*d9f75844SAndroid Build Coastguard Worker 
265*d9f75844SAndroid Build Coastguard Worker     callbacks_->OnDecodedFrame(decoded_image, callback_info);
266*d9f75844SAndroid Build Coastguard Worker   });
267*d9f75844SAndroid Build Coastguard Worker }
268*d9f75844SAndroid Build Coastguard Worker 
DecodeCallbacks(VideoStreamDecoderImpl * video_stream_decoder_impl)269*d9f75844SAndroid Build Coastguard Worker VideoStreamDecoderImpl::DecodeCallbacks::DecodeCallbacks(
270*d9f75844SAndroid Build Coastguard Worker     VideoStreamDecoderImpl* video_stream_decoder_impl)
271*d9f75844SAndroid Build Coastguard Worker     : video_stream_decoder_impl_(video_stream_decoder_impl) {}
272*d9f75844SAndroid Build Coastguard Worker 
Decoded(VideoFrame & decoded_image)273*d9f75844SAndroid Build Coastguard Worker int32_t VideoStreamDecoderImpl::DecodeCallbacks::Decoded(
274*d9f75844SAndroid Build Coastguard Worker     VideoFrame& decoded_image) {
275*d9f75844SAndroid Build Coastguard Worker   Decoded(decoded_image, absl::nullopt, absl::nullopt);
276*d9f75844SAndroid Build Coastguard Worker   return WEBRTC_VIDEO_CODEC_OK;
277*d9f75844SAndroid Build Coastguard Worker }
278*d9f75844SAndroid Build Coastguard Worker 
Decoded(VideoFrame & decoded_image,int64_t decode_time_ms)279*d9f75844SAndroid Build Coastguard Worker int32_t VideoStreamDecoderImpl::DecodeCallbacks::Decoded(
280*d9f75844SAndroid Build Coastguard Worker     VideoFrame& decoded_image,
281*d9f75844SAndroid Build Coastguard Worker     int64_t decode_time_ms) {
282*d9f75844SAndroid Build Coastguard Worker   Decoded(decoded_image, decode_time_ms, absl::nullopt);
283*d9f75844SAndroid Build Coastguard Worker   return WEBRTC_VIDEO_CODEC_OK;
284*d9f75844SAndroid Build Coastguard Worker }
285*d9f75844SAndroid Build Coastguard Worker 
Decoded(VideoFrame & decoded_image,absl::optional<int32_t> decode_time_ms,absl::optional<uint8_t> qp)286*d9f75844SAndroid Build Coastguard Worker void VideoStreamDecoderImpl::DecodeCallbacks::Decoded(
287*d9f75844SAndroid Build Coastguard Worker     VideoFrame& decoded_image,
288*d9f75844SAndroid Build Coastguard Worker     absl::optional<int32_t> decode_time_ms,
289*d9f75844SAndroid Build Coastguard Worker     absl::optional<uint8_t> qp) {
290*d9f75844SAndroid Build Coastguard Worker   video_stream_decoder_impl_->OnDecodedFrameCallback(decoded_image,
291*d9f75844SAndroid Build Coastguard Worker                                                      decode_time_ms, qp);
292*d9f75844SAndroid Build Coastguard Worker }
293*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
294