OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/video/video_receive_stream.h" | 11 #include "webrtc/video/video_receive_stream.h" |
12 | 12 |
13 #include <stdlib.h> | 13 #include <stdlib.h> |
14 | 14 |
15 #include <set> | 15 #include <set> |
16 #include <string> | 16 #include <string> |
17 #include <utility> | 17 #include <utility> |
18 | 18 |
19 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
20 #include "webrtc/base/logging.h" | 20 #include "webrtc/base/logging.h" |
21 #include "webrtc/base/optional.h" | 21 #include "webrtc/base/optional.h" |
22 #include "webrtc/common_video/h264/profile_level_id.h" | 22 #include "webrtc/common_video/h264/profile_level_id.h" |
23 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 23 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
24 #include "webrtc/modules/congestion_controller/include/congestion_controller.h" | 24 #include "webrtc/modules/congestion_controller/include/congestion_controller.h" |
| 25 #include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h" |
| 26 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" |
25 #include "webrtc/modules/utility/include/process_thread.h" | 27 #include "webrtc/modules/utility/include/process_thread.h" |
26 #include "webrtc/modules/video_coding/frame_object.h" | 28 #include "webrtc/modules/video_coding/frame_object.h" |
27 #include "webrtc/modules/video_coding/include/video_coding.h" | 29 #include "webrtc/modules/video_coding/include/video_coding.h" |
28 #include "webrtc/modules/video_coding/jitter_estimator.h" | 30 #include "webrtc/modules/video_coding/jitter_estimator.h" |
29 #include "webrtc/modules/video_coding/timing.h" | 31 #include "webrtc/modules/video_coding/timing.h" |
30 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" | 32 #include "webrtc/modules/video_coding/utility/ivf_file_writer.h" |
31 #include "webrtc/system_wrappers/include/clock.h" | 33 #include "webrtc/system_wrappers/include/clock.h" |
32 #include "webrtc/system_wrappers/include/field_trial.h" | 34 #include "webrtc/system_wrappers/include/field_trial.h" |
33 #include "webrtc/video/call_stats.h" | 35 #include "webrtc/video/call_stats.h" |
34 #include "webrtc/video/receive_statistics_proxy.h" | 36 #include "webrtc/video/receive_statistics_proxy.h" |
35 #include "webrtc/video_receive_stream.h" | 37 #include "webrtc/video_receive_stream.h" |
36 #include "webrtc/voice_engine/include/voe_video_sync.h" | |
37 | 38 |
38 namespace webrtc { | 39 namespace webrtc { |
39 | 40 |
40 static bool UseSendSideBwe(const VideoReceiveStream::Config& config) { | 41 static bool UseSendSideBwe(const VideoReceiveStream::Config& config) { |
41 if (!config.rtp.transport_cc) | 42 if (!config.rtp.transport_cc) |
42 return false; | 43 return false; |
43 for (const auto& extension : config.rtp.extensions) { | 44 for (const auto& extension : config.rtp.extensions) { |
44 if (extension.uri == RtpExtension::kTransportSequenceNumberUri) | 45 if (extension.uri == RtpExtension::kTransportSequenceNumberUri) |
45 return true; | 46 return true; |
46 } | 47 } |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 } // namespace | 184 } // namespace |
184 | 185 |
185 namespace internal { | 186 namespace internal { |
186 | 187 |
187 VideoReceiveStream::VideoReceiveStream( | 188 VideoReceiveStream::VideoReceiveStream( |
188 int num_cpu_cores, | 189 int num_cpu_cores, |
189 bool protected_by_flexfec, | 190 bool protected_by_flexfec, |
190 CongestionController* congestion_controller, | 191 CongestionController* congestion_controller, |
191 PacketRouter* packet_router, | 192 PacketRouter* packet_router, |
192 VideoReceiveStream::Config config, | 193 VideoReceiveStream::Config config, |
193 webrtc::VoiceEngine* voice_engine, | |
194 ProcessThread* process_thread, | 194 ProcessThread* process_thread, |
195 CallStats* call_stats, | 195 CallStats* call_stats, |
196 VieRemb* remb) | 196 VieRemb* remb) |
197 : transport_adapter_(config.rtcp_send_transport), | 197 : transport_adapter_(config.rtcp_send_transport), |
198 config_(std::move(config)), | 198 config_(std::move(config)), |
199 num_cpu_cores_(num_cpu_cores), | 199 num_cpu_cores_(num_cpu_cores), |
200 protected_by_flexfec_(protected_by_flexfec), | 200 protected_by_flexfec_(protected_by_flexfec), |
201 process_thread_(process_thread), | 201 process_thread_(process_thread), |
202 clock_(Clock::GetRealTimeClock()), | 202 clock_(Clock::GetRealTimeClock()), |
203 decode_thread_(DecodeThreadFunction, this, "DecodingThread"), | 203 decode_thread_(DecodeThreadFunction, this, "DecodingThread"), |
204 congestion_controller_(congestion_controller), | 204 congestion_controller_(congestion_controller), |
205 call_stats_(call_stats), | 205 call_stats_(call_stats), |
206 timing_(new VCMTiming(clock_)), | 206 timing_(new VCMTiming(clock_)), |
207 video_receiver_(clock_, nullptr, this, timing_.get(), this, this), | 207 video_receiver_(clock_, nullptr, this, timing_.get(), this, this), |
208 stats_proxy_(&config_, clock_), | 208 stats_proxy_(&config_, clock_), |
209 rtp_stream_receiver_(&video_receiver_, | 209 rtp_stream_receiver_(&video_receiver_, |
210 congestion_controller_->GetRemoteBitrateEstimator( | 210 congestion_controller_->GetRemoteBitrateEstimator( |
211 UseSendSideBwe(config_)), | 211 UseSendSideBwe(config_)), |
212 &transport_adapter_, | 212 &transport_adapter_, |
213 call_stats_->rtcp_rtt_stats(), | 213 call_stats_->rtcp_rtt_stats(), |
214 packet_router, | 214 packet_router, |
215 remb, | 215 remb, |
216 &config_, | 216 &config_, |
217 &stats_proxy_, | 217 &stats_proxy_, |
218 process_thread_, | 218 process_thread_, |
219 this, // NackSender | 219 this, // NackSender |
220 this, // KeyFrameRequestSender | 220 this, // KeyFrameRequestSender |
221 this, // OnCompleteFrameCallback | 221 this, // OnCompleteFrameCallback |
222 timing_.get()), | 222 timing_.get()), |
223 rtp_stream_sync_(&video_receiver_, &rtp_stream_receiver_), | 223 rtp_stream_sync_(this), |
224 jitter_buffer_experiment_( | 224 jitter_buffer_experiment_( |
225 field_trial::FindFullName("WebRTC-NewVideoJitterBuffer") == | 225 field_trial::FindFullName("WebRTC-NewVideoJitterBuffer") == |
226 "Enabled") { | 226 "Enabled") { |
227 LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString(); | 227 LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString(); |
228 | 228 |
229 RTC_DCHECK(process_thread_); | 229 RTC_DCHECK(process_thread_); |
230 RTC_DCHECK(congestion_controller_); | 230 RTC_DCHECK(congestion_controller_); |
231 RTC_DCHECK(call_stats_); | 231 RTC_DCHECK(call_stats_); |
232 | 232 |
| 233 module_process_thread_checker_.DetachFromThread(); |
| 234 |
233 RTC_DCHECK(!config_.decoders.empty()); | 235 RTC_DCHECK(!config_.decoders.empty()); |
234 std::set<int> decoder_payload_types; | 236 std::set<int> decoder_payload_types; |
235 for (const Decoder& decoder : config_.decoders) { | 237 for (const Decoder& decoder : config_.decoders) { |
236 RTC_CHECK(decoder.decoder); | 238 RTC_CHECK(decoder.decoder); |
237 RTC_CHECK(decoder_payload_types.find(decoder.payload_type) == | 239 RTC_CHECK(decoder_payload_types.find(decoder.payload_type) == |
238 decoder_payload_types.end()) | 240 decoder_payload_types.end()) |
239 << "Duplicate payload type (" << decoder.payload_type | 241 << "Duplicate payload type (" << decoder.payload_type |
240 << ") for different decoders."; | 242 << ") for different decoders."; |
241 decoder_payload_types.insert(decoder.payload_type); | 243 decoder_payload_types.insert(decoder.payload_type); |
242 } | 244 } |
243 | 245 |
244 video_receiver_.SetRenderDelay(config.render_delay_ms); | 246 video_receiver_.SetRenderDelay(config.render_delay_ms); |
245 | 247 |
246 if (jitter_buffer_experiment_) { | 248 if (jitter_buffer_experiment_) { |
247 jitter_estimator_.reset(new VCMJitterEstimator(clock_)); | 249 jitter_estimator_.reset(new VCMJitterEstimator(clock_)); |
248 frame_buffer_.reset(new video_coding::FrameBuffer( | 250 frame_buffer_.reset(new video_coding::FrameBuffer( |
249 clock_, jitter_estimator_.get(), timing_.get())); | 251 clock_, jitter_estimator_.get(), timing_.get())); |
250 } | 252 } |
251 | 253 |
252 process_thread_->RegisterModule(&video_receiver_); | 254 process_thread_->RegisterModule(&video_receiver_); |
253 process_thread_->RegisterModule(&rtp_stream_sync_); | 255 process_thread_->RegisterModule(&rtp_stream_sync_); |
254 } | 256 } |
255 | 257 |
256 VideoReceiveStream::~VideoReceiveStream() { | 258 VideoReceiveStream::~VideoReceiveStream() { |
| 259 RTC_DCHECK_RUN_ON(&worker_thread_checker_); |
257 LOG(LS_INFO) << "~VideoReceiveStream: " << config_.ToString(); | 260 LOG(LS_INFO) << "~VideoReceiveStream: " << config_.ToString(); |
258 Stop(); | 261 Stop(); |
259 | 262 |
260 process_thread_->DeRegisterModule(&rtp_stream_sync_); | 263 process_thread_->DeRegisterModule(&rtp_stream_sync_); |
261 process_thread_->DeRegisterModule(&video_receiver_); | 264 process_thread_->DeRegisterModule(&video_receiver_); |
262 | 265 |
263 congestion_controller_->GetRemoteBitrateEstimator(UseSendSideBwe(config_)) | 266 congestion_controller_->GetRemoteBitrateEstimator(UseSendSideBwe(config_)) |
264 ->RemoveStream(rtp_stream_receiver_.GetRemoteSsrc()); | 267 ->RemoveStream(rtp_stream_receiver_.GetRemoteSsrc()); |
265 } | 268 } |
266 | 269 |
267 void VideoReceiveStream::SignalNetworkState(NetworkState state) { | 270 void VideoReceiveStream::SignalNetworkState(NetworkState state) { |
| 271 RTC_DCHECK_RUN_ON(&worker_thread_checker_); |
268 rtp_stream_receiver_.SignalNetworkState(state); | 272 rtp_stream_receiver_.SignalNetworkState(state); |
269 } | 273 } |
270 | 274 |
271 | 275 |
272 bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) { | 276 bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) { |
273 return rtp_stream_receiver_.DeliverRtcp(packet, length); | 277 return rtp_stream_receiver_.DeliverRtcp(packet, length); |
274 } | 278 } |
275 | 279 |
276 bool VideoReceiveStream::DeliverRtp(const uint8_t* packet, | 280 bool VideoReceiveStream::DeliverRtp(const uint8_t* packet, |
277 size_t length, | 281 size_t length, |
278 const PacketTime& packet_time) { | 282 const PacketTime& packet_time) { |
279 return rtp_stream_receiver_.DeliverRtp(packet, length, packet_time); | 283 return rtp_stream_receiver_.DeliverRtp(packet, length, packet_time); |
280 } | 284 } |
281 | 285 |
282 bool VideoReceiveStream::OnRecoveredPacket(const uint8_t* packet, | 286 bool VideoReceiveStream::OnRecoveredPacket(const uint8_t* packet, |
283 size_t length) { | 287 size_t length) { |
| 288 RTC_DCHECK_RUN_ON(&worker_thread_checker_); |
284 return rtp_stream_receiver_.OnRecoveredPacket(packet, length); | 289 return rtp_stream_receiver_.OnRecoveredPacket(packet, length); |
285 } | 290 } |
286 | 291 |
287 void VideoReceiveStream::SetSyncChannel(VoiceEngine* voice_engine, | 292 void VideoReceiveStream::SetSync(Syncable* audio_syncable) { |
288 int audio_channel_id) { | 293 RTC_DCHECK_RUN_ON(&worker_thread_checker_); |
289 if (voice_engine && audio_channel_id != -1) { | 294 rtp_stream_sync_.ConfigureSync(audio_syncable); |
290 VoEVideoSync* voe_sync_interface = VoEVideoSync::GetInterface(voice_engine); | |
291 rtp_stream_sync_.ConfigureSync(audio_channel_id, voe_sync_interface); | |
292 voe_sync_interface->Release(); | |
293 } else { | |
294 rtp_stream_sync_.ConfigureSync(-1, nullptr); | |
295 } | |
296 } | 295 } |
297 | 296 |
298 void VideoReceiveStream::Start() { | 297 void VideoReceiveStream::Start() { |
| 298 RTC_DCHECK_RUN_ON(&worker_thread_checker_); |
299 if (decode_thread_.IsRunning()) | 299 if (decode_thread_.IsRunning()) |
300 return; | 300 return; |
301 | 301 |
302 bool protected_by_fec = | 302 bool protected_by_fec = |
303 protected_by_flexfec_ || rtp_stream_receiver_.IsUlpfecEnabled(); | 303 protected_by_flexfec_ || rtp_stream_receiver_.IsUlpfecEnabled(); |
304 | 304 |
305 if (jitter_buffer_experiment_) { | 305 if (jitter_buffer_experiment_) { |
306 frame_buffer_->Start(); | 306 frame_buffer_->Start(); |
307 call_stats_->RegisterStatsObserver(&rtp_stream_receiver_); | 307 call_stats_->RegisterStatsObserver(&rtp_stream_receiver_); |
308 | 308 |
(...skipping 30 matching lines...) Expand all Loading... |
339 &stats_proxy_, renderer, config_.pre_render_callback)); | 339 &stats_proxy_, renderer, config_.pre_render_callback)); |
340 // Register the channel to receive stats updates. | 340 // Register the channel to receive stats updates. |
341 call_stats_->RegisterStatsObserver(video_stream_decoder_.get()); | 341 call_stats_->RegisterStatsObserver(video_stream_decoder_.get()); |
342 // Start the decode thread | 342 // Start the decode thread |
343 decode_thread_.Start(); | 343 decode_thread_.Start(); |
344 decode_thread_.SetPriority(rtc::kHighestPriority); | 344 decode_thread_.SetPriority(rtc::kHighestPriority); |
345 rtp_stream_receiver_.StartReceive(); | 345 rtp_stream_receiver_.StartReceive(); |
346 } | 346 } |
347 | 347 |
348 void VideoReceiveStream::Stop() { | 348 void VideoReceiveStream::Stop() { |
| 349 RTC_DCHECK_RUN_ON(&worker_thread_checker_); |
349 rtp_stream_receiver_.StopReceive(); | 350 rtp_stream_receiver_.StopReceive(); |
350 // TriggerDecoderShutdown will release any waiting decoder thread and make it | 351 // TriggerDecoderShutdown will release any waiting decoder thread and make it |
351 // stop immediately, instead of waiting for a timeout. Needs to be called | 352 // stop immediately, instead of waiting for a timeout. Needs to be called |
352 // before joining the decoder thread thread. | 353 // before joining the decoder thread thread. |
353 video_receiver_.TriggerDecoderShutdown(); | 354 video_receiver_.TriggerDecoderShutdown(); |
354 | 355 |
355 if (jitter_buffer_experiment_) { | 356 if (jitter_buffer_experiment_) { |
356 frame_buffer_->Stop(); | 357 frame_buffer_->Stop(); |
357 call_stats_->DeregisterStatsObserver(&rtp_stream_receiver_); | 358 call_stats_->DeregisterStatsObserver(&rtp_stream_receiver_); |
358 } | 359 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 // TODO(tommi): OnDecodedFrame grabs a lock, incidentally the same lock | 401 // TODO(tommi): OnDecodedFrame grabs a lock, incidentally the same lock |
401 // that OnSyncOffsetUpdated() and OnRenderedFrame() below grab. | 402 // that OnSyncOffsetUpdated() and OnRenderedFrame() below grab. |
402 stats_proxy_.OnDecodedFrame(); | 403 stats_proxy_.OnDecodedFrame(); |
403 | 404 |
404 int64_t sync_offset_ms; | 405 int64_t sync_offset_ms; |
405 double estimated_freq_khz; | 406 double estimated_freq_khz; |
406 // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks. One inside the | 407 // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks. One inside the |
407 // function itself, another in GetChannel() and a third in | 408 // function itself, another in GetChannel() and a third in |
408 // GetPlayoutTimestamp. Seems excessive. Anyhow, I'm assuming the function | 409 // GetPlayoutTimestamp. Seems excessive. Anyhow, I'm assuming the function |
409 // succeeds most of the time, which leads to grabbing a fourth lock. | 410 // succeeds most of the time, which leads to grabbing a fourth lock. |
410 if (rtp_stream_sync_.GetStreamSyncOffsetInMs(video_frame, &sync_offset_ms, | 411 if (rtp_stream_sync_.GetStreamSyncOffsetInMs(video_frame.timestamp(), |
| 412 video_frame.render_time_ms(), |
| 413 &sync_offset_ms, |
411 &estimated_freq_khz)) { | 414 &estimated_freq_khz)) { |
412 // TODO(tommi): OnSyncOffsetUpdated grabs a lock. | 415 // TODO(tommi): OnSyncOffsetUpdated grabs a lock. |
413 stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz); | 416 stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz); |
414 } | 417 } |
415 | 418 |
416 // config_.renderer must never be null if we're getting this callback. | 419 // config_.renderer must never be null if we're getting this callback. |
417 config_.renderer->OnFrame(video_frame); | 420 config_.renderer->OnFrame(video_frame); |
418 | 421 |
419 // TODO(tommi): OnRenderFrame grabs a lock too. | 422 // TODO(tommi): OnRenderFrame grabs a lock too. |
420 stats_proxy_.OnRenderedFrame(video_frame); | 423 stats_proxy_.OnRenderedFrame(video_frame); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 rtp_stream_receiver_.RequestKeyFrame(); | 457 rtp_stream_receiver_.RequestKeyFrame(); |
455 } | 458 } |
456 | 459 |
457 void VideoReceiveStream::OnCompleteFrame( | 460 void VideoReceiveStream::OnCompleteFrame( |
458 std::unique_ptr<video_coding::FrameObject> frame) { | 461 std::unique_ptr<video_coding::FrameObject> frame) { |
459 int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame)); | 462 int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame)); |
460 if (last_continuous_pid != -1) | 463 if (last_continuous_pid != -1) |
461 rtp_stream_receiver_.FrameContinuous(last_continuous_pid); | 464 rtp_stream_receiver_.FrameContinuous(last_continuous_pid); |
462 } | 465 } |
463 | 466 |
| 467 int VideoReceiveStream::id() const { |
| 468 RTC_DCHECK_RUN_ON(&worker_thread_checker_); |
| 469 return config_.rtp.remote_ssrc; |
| 470 } |
| 471 |
| 472 rtc::Optional<Syncable::Info> VideoReceiveStream::GetInfo() const { |
| 473 RTC_DCHECK_RUN_ON(&module_process_thread_checker_); |
| 474 Syncable::Info info; |
| 475 |
| 476 RtpReceiver* rtp_receiver = rtp_stream_receiver_.GetRtpReceiver(); |
| 477 RTC_DCHECK(rtp_receiver); |
| 478 if (!rtp_receiver->Timestamp(&info.latest_received_capture_timestamp)) |
| 479 return rtc::Optional<Syncable::Info>(); |
| 480 if (!rtp_receiver->LastReceivedTimeMs(&info.latest_receive_time_ms)) |
| 481 return rtc::Optional<Syncable::Info>(); |
| 482 |
| 483 RtpRtcp* rtp_rtcp = rtp_stream_receiver_.rtp_rtcp(); |
| 484 RTC_DCHECK(rtp_rtcp); |
| 485 if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs, |
| 486 &info.capture_time_ntp_frac, |
| 487 nullptr, |
| 488 nullptr, |
| 489 &info.capture_time_source_clock) != 0) { |
| 490 return rtc::Optional<Syncable::Info>(); |
| 491 } |
| 492 |
| 493 info.current_delay_ms = video_receiver_.Delay(); |
| 494 return rtc::Optional<Syncable::Info>(info); |
| 495 } |
| 496 |
| 497 uint32_t VideoReceiveStream::GetPlayoutTimestamp() const { |
| 498 RTC_NOTREACHED(); |
| 499 return 0; |
| 500 } |
| 501 |
| 502 void VideoReceiveStream::SetMinimumPlayoutDelay(int delay_ms) { |
| 503 RTC_DCHECK_RUN_ON(&module_process_thread_checker_); |
| 504 video_receiver_.SetMinimumPlayoutDelay(delay_ms); |
| 505 } |
| 506 |
464 bool VideoReceiveStream::DecodeThreadFunction(void* ptr) { | 507 bool VideoReceiveStream::DecodeThreadFunction(void* ptr) { |
465 static_cast<VideoReceiveStream*>(ptr)->Decode(); | 508 static_cast<VideoReceiveStream*>(ptr)->Decode(); |
466 return true; | 509 return true; |
467 } | 510 } |
468 | 511 |
469 void VideoReceiveStream::Decode() { | 512 void VideoReceiveStream::Decode() { |
470 static const int kMaxDecodeWaitTimeMs = 50; | 513 static const int kMaxDecodeWaitTimeMs = 50; |
471 if (jitter_buffer_experiment_) { | 514 if (jitter_buffer_experiment_) { |
472 static const int kMaxWaitForFrameMs = 3000; | 515 static const int kMaxWaitForFrameMs = 3000; |
473 std::unique_ptr<video_coding::FrameObject> frame; | 516 std::unique_ptr<video_coding::FrameObject> frame; |
474 video_coding::FrameBuffer::ReturnReason res = | 517 video_coding::FrameBuffer::ReturnReason res = |
475 frame_buffer_->NextFrame(kMaxWaitForFrameMs, &frame); | 518 frame_buffer_->NextFrame(kMaxWaitForFrameMs, &frame); |
476 | 519 |
477 if (res == video_coding::FrameBuffer::ReturnReason::kStopped) | 520 if (res == video_coding::FrameBuffer::ReturnReason::kStopped) |
478 return; | 521 return; |
479 | 522 |
480 if (frame) { | 523 if (frame) { |
481 if (video_receiver_.Decode(frame.get()) == VCM_OK) | 524 if (video_receiver_.Decode(frame.get()) == VCM_OK) |
482 rtp_stream_receiver_.FrameDecoded(frame->picture_id); | 525 rtp_stream_receiver_.FrameDecoded(frame->picture_id); |
483 } else { | 526 } else { |
484 LOG(LS_WARNING) << "No decodable frame in " << kMaxWaitForFrameMs | 527 LOG(LS_WARNING) << "No decodable frame in " << kMaxWaitForFrameMs |
485 << " ms, requesting keyframe."; | 528 << " ms, requesting keyframe."; |
486 RequestKeyFrame(); | 529 RequestKeyFrame(); |
487 } | 530 } |
488 } else { | 531 } else { |
489 video_receiver_.Decode(kMaxDecodeWaitTimeMs); | 532 video_receiver_.Decode(kMaxDecodeWaitTimeMs); |
490 } | 533 } |
491 } | 534 } |
492 | |
493 } // namespace internal | 535 } // namespace internal |
494 } // namespace webrtc | 536 } // namespace webrtc |
OLD | NEW |