2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
11 #include "webrtc/common_types.h"
12 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
13 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
14 #include "webrtc/modules/video_coding/main/source/encoded_frame.h"
15 #include "webrtc/modules/video_coding/main/source/jitter_buffer.h"
16 #include "webrtc/modules/video_coding/main/source/packet.h"
17 #include "webrtc/modules/video_coding/main/source/video_coding_impl.h"
18 #include "webrtc/system_wrappers/interface/clock.h"
19 #include "webrtc/system_wrappers/interface/logging.h"
20 #include "webrtc/system_wrappers/interface/trace_event.h"
22 // #define DEBUG_DECODER_BIT_STREAM
27 VideoReceiver::VideoReceiver(Clock* clock, EventFactory* event_factory)
29 process_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
30 _receiveCritSect(CriticalSectionWrapper::CreateCriticalSection()),
31 _receiverInited(false),
33 _dualTiming(clock_, &_timing),
34 _receiver(&_timing, clock_, event_factory, true),
35 _dualReceiver(&_dualTiming, clock_, event_factory, false),
36 _decodedFrameCallback(_timing, clock_),
37 _dualDecodedFrameCallback(_dualTiming, clock_),
38 _frameTypeCallback(NULL),
39 _receiveStatsCallback(NULL),
40 _decoderTimingCallback(NULL),
41 _packetRequestCallback(NULL),
42 render_buffer_callback_(NULL),
45 #ifdef DEBUG_DECODER_BIT_STREAM
46 _bitStreamBeforeDecoder(NULL),
49 _keyRequestMode(kKeyOnError),
50 _scheduleKeyRequest(false),
51 max_nack_list_size_(0),
52 pre_decode_image_callback_(NULL),
54 _receiveStatsTimer(1000, clock_),
55 _retransmissionTimer(10, clock_),
56 _keyRequestTimer(500, clock_) {
58 #ifdef DEBUG_DECODER_BIT_STREAM
59 _bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb");
63 VideoReceiver::~VideoReceiver() {
64 if (_dualDecoder != NULL) {
65 _codecDataBase.ReleaseDecoder(_dualDecoder);
67 delete _receiveCritSect;
68 #ifdef DEBUG_DECODER_BIT_STREAM
69 fclose(_bitStreamBeforeDecoder);
73 int32_t VideoReceiver::Process() {
74 int32_t returnValue = VCM_OK;
76 // Receive-side statistics
77 if (_receiveStatsTimer.TimeUntilProcess() == 0) {
78 _receiveStatsTimer.Processed();
79 CriticalSectionScoped cs(process_crit_sect_.get());
80 if (_receiveStatsCallback != NULL) {
83 _receiver.ReceiveStatistics(&bitRate, &frameRate);
84 _receiveStatsCallback->OnReceiveStatisticsUpdate(bitRate, frameRate);
87 if (_decoderTimingCallback != NULL) {
93 int min_playout_delay_ms;
95 _timing.GetTimings(&decode_ms,
100 &min_playout_delay_ms,
102 _decoderTimingCallback->OnDecoderTiming(decode_ms,
107 min_playout_delay_ms,
111 // Size of render buffer.
112 if (render_buffer_callback_) {
113 int buffer_size_ms = _receiver.RenderBufferSizeMs();
114 render_buffer_callback_->RenderBufferSizeMs(buffer_size_ms);
118 // Key frame requests
119 if (_keyRequestTimer.TimeUntilProcess() == 0) {
120 _keyRequestTimer.Processed();
121 bool request_key_frame = false;
123 CriticalSectionScoped cs(process_crit_sect_.get());
124 request_key_frame = _scheduleKeyRequest && _frameTypeCallback != NULL;
126 if (request_key_frame) {
127 const int32_t ret = RequestKeyFrame();
128 if (ret != VCM_OK && returnValue == VCM_OK) {
134 // Packet retransmission requests
135 // TODO(holmer): Add API for changing Process interval and make sure it's
136 // disabled when NACK is off.
137 if (_retransmissionTimer.TimeUntilProcess() == 0) {
138 _retransmissionTimer.Processed();
139 bool callback_registered = false;
142 CriticalSectionScoped cs(process_crit_sect_.get());
143 length = max_nack_list_size_;
144 callback_registered = _packetRequestCallback != NULL;
146 if (callback_registered && length > 0) {
147 std::vector<uint16_t> nackList(length);
148 const int32_t ret = NackList(&nackList[0], &length);
149 if (ret != VCM_OK && returnValue == VCM_OK) {
152 if (ret == VCM_OK && length > 0) {
153 CriticalSectionScoped cs(process_crit_sect_.get());
154 if (_packetRequestCallback != NULL) {
155 _packetRequestCallback->ResendPackets(&nackList[0], length);
164 int32_t VideoReceiver::TimeUntilNextProcess() {
165 uint32_t timeUntilNextProcess = _receiveStatsTimer.TimeUntilProcess();
166 if ((_receiver.NackMode() != kNoNack) ||
167 (_dualReceiver.State() != kPassive)) {
168 // We need a Process call more often if we are relying on
170 timeUntilNextProcess =
171 VCM_MIN(timeUntilNextProcess, _retransmissionTimer.TimeUntilProcess());
173 timeUntilNextProcess =
174 VCM_MIN(timeUntilNextProcess, _keyRequestTimer.TimeUntilProcess());
176 return timeUntilNextProcess;
179 int32_t VideoReceiver::SetReceiveChannelParameters(uint32_t rtt) {
180 CriticalSectionScoped receiveCs(_receiveCritSect);
181 _receiver.UpdateRtt(rtt);
185 // Enable or disable a video protection method.
186 // Note: This API should be deprecated, as it does not offer a distinction
187 // between the protection method and decoding with or without errors. If such a
188 // behavior is desired, use the following API: SetReceiverRobustnessMode.
189 int32_t VideoReceiver::SetVideoProtection(VCMVideoProtection videoProtection,
191 // By default, do not decode with errors.
192 _receiver.SetDecodeErrorMode(kNoErrors);
193 // The dual decoder should always be error free.
194 _dualReceiver.SetDecodeErrorMode(kNoErrors);
195 switch (videoProtection) {
196 case kProtectionNack:
197 case kProtectionNackReceiver: {
198 CriticalSectionScoped cs(_receiveCritSect);
200 // Enable NACK and always wait for retransmits.
201 _receiver.SetNackMode(kNack, -1, -1);
203 _receiver.SetNackMode(kNoNack, -1, -1);
208 case kProtectionDualDecoder: {
209 CriticalSectionScoped cs(_receiveCritSect);
211 // Enable NACK but don't wait for retransmissions and don't
212 // add any extra delay.
213 _receiver.SetNackMode(kNack, 0, 0);
214 // Enable NACK and always wait for retransmissions and
215 // compensate with extra delay.
216 _dualReceiver.SetNackMode(kNack, -1, -1);
217 _receiver.SetDecodeErrorMode(kWithErrors);
219 _dualReceiver.SetNackMode(kNoNack, -1, -1);
224 case kProtectionKeyOnLoss: {
225 CriticalSectionScoped cs(_receiveCritSect);
227 _keyRequestMode = kKeyOnLoss;
228 _receiver.SetDecodeErrorMode(kWithErrors);
229 } else if (_keyRequestMode == kKeyOnLoss) {
230 _keyRequestMode = kKeyOnError; // default mode
232 return VCM_PARAMETER_ERROR;
237 case kProtectionKeyOnKeyLoss: {
238 CriticalSectionScoped cs(_receiveCritSect);
240 _keyRequestMode = kKeyOnKeyLoss;
241 } else if (_keyRequestMode == kKeyOnKeyLoss) {
242 _keyRequestMode = kKeyOnError; // default mode
244 return VCM_PARAMETER_ERROR;
249 case kProtectionNackFEC: {
250 CriticalSectionScoped cs(_receiveCritSect);
252 // Enable hybrid NACK/FEC. Always wait for retransmissions
253 // and don't add extra delay when RTT is above
255 _receiver.SetNackMode(kNack, media_optimization::kLowRttNackMs, -1);
256 _receiver.SetDecodeErrorMode(kNoErrors);
257 _receiver.SetDecodeErrorMode(kNoErrors);
259 _receiver.SetNackMode(kNoNack, -1, -1);
263 case kProtectionNackSender:
265 case kProtectionPeriodicKeyFrames:
266 // Ignore encoder modes.
272 // Initialize receiver, resets codec database etc
273 int32_t VideoReceiver::InitializeReceiver() {
274 int32_t ret = _receiver.Initialize();
279 ret = _dualReceiver.Initialize();
283 _codecDataBase.ResetReceiver();
287 CriticalSectionScoped receive_cs(_receiveCritSect);
288 _receiverInited = true;
292 CriticalSectionScoped process_cs(process_crit_sect_.get());
294 _decodedFrameCallback.SetUserReceiveCallback(NULL);
295 _frameTypeCallback = NULL;
296 _receiveStatsCallback = NULL;
297 _decoderTimingCallback = NULL;
298 _packetRequestCallback = NULL;
299 _keyRequestMode = kKeyOnError;
300 _scheduleKeyRequest = false;
306 // Register a receive callback. Will be called whenever there is a new frame
307 // ready for rendering.
308 int32_t VideoReceiver::RegisterReceiveCallback(
309 VCMReceiveCallback* receiveCallback) {
310 CriticalSectionScoped cs(_receiveCritSect);
311 _decodedFrameCallback.SetUserReceiveCallback(receiveCallback);
315 int32_t VideoReceiver::RegisterReceiveStatisticsCallback(
316 VCMReceiveStatisticsCallback* receiveStats) {
317 CriticalSectionScoped cs(process_crit_sect_.get());
318 _receiveStatsCallback = receiveStats;
322 int32_t VideoReceiver::RegisterDecoderTimingCallback(
323 VCMDecoderTimingCallback* decoderTiming) {
324 CriticalSectionScoped cs(process_crit_sect_.get());
325 _decoderTimingCallback = decoderTiming;
329 // Register an externally defined decoder/render object.
330 // Can be a decoder only or a decoder coupled with a renderer.
331 int32_t VideoReceiver::RegisterExternalDecoder(VideoDecoder* externalDecoder,
333 bool internalRenderTiming) {
334 CriticalSectionScoped cs(_receiveCritSect);
335 if (externalDecoder == NULL) {
336 // Make sure the VCM updates the decoder next time it decodes.
338 return _codecDataBase.DeregisterExternalDecoder(payloadType) ? 0 : -1;
340 return _codecDataBase.RegisterExternalDecoder(
341 externalDecoder, payloadType, internalRenderTiming)
346 // Register a frame type request callback.
347 int32_t VideoReceiver::RegisterFrameTypeCallback(
348 VCMFrameTypeCallback* frameTypeCallback) {
349 CriticalSectionScoped cs(process_crit_sect_.get());
350 _frameTypeCallback = frameTypeCallback;
354 int32_t VideoReceiver::RegisterPacketRequestCallback(
355 VCMPacketRequestCallback* callback) {
356 CriticalSectionScoped cs(process_crit_sect_.get());
357 _packetRequestCallback = callback;
361 int VideoReceiver::RegisterRenderBufferSizeCallback(
362 VCMRenderBufferSizeCallback* callback) {
363 CriticalSectionScoped cs(process_crit_sect_.get());
364 render_buffer_callback_ = callback;
368 // Decode next frame, blocking.
369 // Should be called as often as possible to get the most out of the decoder.
370 int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) {
371 int64_t nextRenderTimeMs;
373 CriticalSectionScoped cs(_receiveCritSect);
374 if (!_receiverInited) {
375 return VCM_UNINITIALIZED;
377 if (!_codecDataBase.DecoderRegistered()) {
378 return VCM_NO_CODEC_REGISTERED;
382 const bool dualReceiverEnabledNotReceiving = (
383 _dualReceiver.State() != kReceiving && _dualReceiver.NackMode() == kNack);
385 VCMEncodedFrame* frame =
386 _receiver.FrameForDecoding(maxWaitTimeMs,
388 _codecDataBase.SupportsRenderScheduling(),
391 if (dualReceiverEnabledNotReceiving && _dualReceiver.State() == kReceiving) {
392 // Dual receiver is enabled (kNACK enabled), but was not receiving
393 // before the call to FrameForDecoding(). After the call the state
394 // changed to receiving, and therefore we must copy the primary decoder
395 // state to the dual decoder to make it possible for the dual decoder to
396 // start decoding retransmitted frames and recover.
397 CriticalSectionScoped cs(_receiveCritSect);
398 if (_dualDecoder != NULL) {
399 _codecDataBase.ReleaseDecoder(_dualDecoder);
401 _dualDecoder = _codecDataBase.CreateDecoderCopy();
402 if (_dualDecoder != NULL) {
403 _dualDecoder->RegisterDecodeCompleteCallback(&_dualDecodedFrameCallback);
405 _dualReceiver.Reset();
410 return VCM_FRAME_NOT_READY;
412 CriticalSectionScoped cs(_receiveCritSect);
414 // If this frame was too late, we should adjust the delay accordingly
415 _timing.UpdateCurrentDelay(frame->RenderTimeMs(),
416 clock_->TimeInMilliseconds());
418 if (pre_decode_image_callback_) {
419 EncodedImage encoded_image(frame->EncodedImage());
420 pre_decode_image_callback_->Encoded(encoded_image);
423 #ifdef DEBUG_DECODER_BIT_STREAM
424 if (_bitStreamBeforeDecoder != NULL) {
425 // Write bit stream to file for debugging purposes
427 frame->Buffer(), 1, frame->Length(), _bitStreamBeforeDecoder) !=
433 const int32_t ret = Decode(*frame);
434 _receiver.ReleaseFrame(frame);
443 int32_t VideoReceiver::RequestSliceLossIndication(
444 const uint64_t pictureID) const {
445 TRACE_EVENT1("webrtc", "RequestSLI", "picture_id", pictureID);
446 CriticalSectionScoped cs(process_crit_sect_.get());
447 if (_frameTypeCallback != NULL) {
449 _frameTypeCallback->SliceLossIndicationRequest(pictureID);
454 return VCM_MISSING_CALLBACK;
459 int32_t VideoReceiver::RequestKeyFrame() {
460 TRACE_EVENT0("webrtc", "RequestKeyFrame");
461 CriticalSectionScoped process_cs(process_crit_sect_.get());
462 if (_frameTypeCallback != NULL) {
463 const int32_t ret = _frameTypeCallback->RequestKeyFrame();
467 _scheduleKeyRequest = false;
469 return VCM_MISSING_CALLBACK;
474 int32_t VideoReceiver::DecodeDualFrame(uint16_t maxWaitTimeMs) {
475 CriticalSectionScoped cs(_receiveCritSect);
476 if (_dualReceiver.State() != kReceiving ||
477 _dualReceiver.NackMode() != kNack) {
478 // The dual receiver is currently not receiving or
479 // dual decoder mode is disabled.
482 int64_t dummyRenderTime;
483 int32_t decodeCount = 0;
484 // The dual decoder's state is copied from the main decoder, which may
485 // decode with errors. Make sure that the dual decoder does not introduce
487 _dualReceiver.SetDecodeErrorMode(kNoErrors);
488 VCMEncodedFrame* dualFrame =
489 _dualReceiver.FrameForDecoding(maxWaitTimeMs, dummyRenderTime);
490 if (dualFrame != NULL && _dualDecoder != NULL) {
491 // Decode dualFrame and try to catch up
493 _dualDecoder->Decode(*dualFrame, clock_->TimeInMilliseconds());
494 if (ret != WEBRTC_VIDEO_CODEC_OK) {
495 LOG(LS_ERROR) << "Failed to decode frame with dual decoder. Error code: "
497 _dualReceiver.ReleaseFrame(dualFrame);
498 return VCM_CODEC_ERROR;
500 if (_receiver.DualDecoderCaughtUp(dualFrame, _dualReceiver)) {
501 // Copy the complete decoder state of the dual decoder
502 // to the primary decoder.
503 _codecDataBase.CopyDecoder(*_dualDecoder);
504 _codecDataBase.ReleaseDecoder(_dualDecoder);
509 _dualReceiver.ReleaseFrame(dualFrame);
513 // Must be called from inside the receive side critical section.
514 int32_t VideoReceiver::Decode(const VCMEncodedFrame& frame) {
515 TRACE_EVENT_ASYNC_STEP1("webrtc",
521 // Change decoder if payload type has changed
522 const bool renderTimingBefore = _codecDataBase.SupportsRenderScheduling();
524 _codecDataBase.GetDecoder(frame.PayloadType(), &_decodedFrameCallback);
525 if (renderTimingBefore != _codecDataBase.SupportsRenderScheduling()) {
526 // Make sure we reset the decode time estimate since it will
527 // be zero for codecs without render timing.
528 _timing.ResetDecodeTime();
530 if (_decoder == NULL) {
531 return VCM_NO_CODEC_REGISTERED;
534 int32_t ret = _decoder->Decode(frame, clock_->TimeInMilliseconds());
536 // Check for failed decoding, run frame type request callback if needed.
537 bool request_key_frame = false;
539 if (ret == VCM_ERROR_REQUEST_SLI) {
540 return RequestSliceLossIndication(
541 _decodedFrameCallback.LastReceivedPictureID() + 1);
543 request_key_frame = true;
545 } else if (ret == VCM_REQUEST_SLI) {
546 ret = RequestSliceLossIndication(
547 _decodedFrameCallback.LastReceivedPictureID() + 1);
549 if (!frame.Complete() || frame.MissingFrame()) {
550 switch (_keyRequestMode) {
551 case kKeyOnKeyLoss: {
552 if (frame.FrameType() == kVideoFrameKey) {
553 request_key_frame = true;
559 request_key_frame = true;
566 if (request_key_frame) {
567 CriticalSectionScoped cs(process_crit_sect_.get());
568 _scheduleKeyRequest = true;
570 TRACE_EVENT_ASYNC_END0("webrtc", "Video", frame.TimeStamp());
574 // Reset the decoder state
575 int32_t VideoReceiver::ResetDecoder() {
576 bool reset_key_request = false;
578 CriticalSectionScoped cs(_receiveCritSect);
579 if (_decoder != NULL) {
580 _receiver.Initialize();
582 reset_key_request = true;
585 if (_dualReceiver.State() != kPassive) {
586 _dualReceiver.Initialize();
588 if (_dualDecoder != NULL) {
589 _codecDataBase.ReleaseDecoder(_dualDecoder);
593 if (reset_key_request) {
594 CriticalSectionScoped cs(process_crit_sect_.get());
595 _scheduleKeyRequest = false;
600 // Register possible receive codecs, can be called multiple times
601 int32_t VideoReceiver::RegisterReceiveCodec(const VideoCodec* receiveCodec,
602 int32_t numberOfCores,
603 bool requireKeyFrame) {
604 CriticalSectionScoped cs(_receiveCritSect);
605 if (receiveCodec == NULL) {
606 return VCM_PARAMETER_ERROR;
608 if (!_codecDataBase.RegisterReceiveCodec(
609 receiveCodec, numberOfCores, requireKeyFrame)) {
615 // Get current received codec
616 int32_t VideoReceiver::ReceiveCodec(VideoCodec* currentReceiveCodec) const {
617 CriticalSectionScoped cs(_receiveCritSect);
618 if (currentReceiveCodec == NULL) {
619 return VCM_PARAMETER_ERROR;
621 return _codecDataBase.ReceiveCodec(currentReceiveCodec) ? 0 : -1;
624 // Get current received codec
625 VideoCodecType VideoReceiver::ReceiveCodec() const {
626 CriticalSectionScoped cs(_receiveCritSect);
627 return _codecDataBase.ReceiveCodec();
630 // Incoming packet from network parsed and ready for decode, non blocking.
631 int32_t VideoReceiver::IncomingPacket(const uint8_t* incomingPayload,
632 uint32_t payloadLength,
633 const WebRtcRTPHeader& rtpInfo) {
634 if (rtpInfo.frameType == kVideoFrameKey) {
635 TRACE_EVENT1("webrtc",
636 "VCM::PacketKeyFrame",
638 rtpInfo.header.sequenceNumber);
640 if (incomingPayload == NULL) {
641 // The jitter buffer doesn't handle non-zero payload lengths for packets
643 // TODO(holmer): We should fix this in the jitter buffer.
646 const VCMPacket packet(incomingPayload, payloadLength, rtpInfo);
648 if (_dualReceiver.State() != kPassive) {
649 ret = _dualReceiver.InsertPacket(
650 packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height);
651 if (ret == VCM_FLUSH_INDICATOR) {
654 } else if (ret < 0) {
658 ret = _receiver.InsertPacket(
659 packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height);
660 // TODO(holmer): Investigate if this somehow should use the key frame
661 // request scheduling to throttle the requests.
662 if (ret == VCM_FLUSH_INDICATOR) {
665 } else if (ret < 0) {
671 // Minimum playout delay (used for lip-sync). This is the minimum delay required
672 // to sync with audio. Not included in VideoCodingModule::Delay()
674 int32_t VideoReceiver::SetMinimumPlayoutDelay(uint32_t minPlayoutDelayMs) {
675 _timing.set_min_playout_delay(minPlayoutDelayMs);
679 // The estimated delay caused by rendering, defaults to
680 // kDefaultRenderDelayMs = 10 ms
681 int32_t VideoReceiver::SetRenderDelay(uint32_t timeMS) {
682 _timing.set_render_delay(timeMS);
686 // Current video delay
687 int32_t VideoReceiver::Delay() const { return _timing.TargetVideoDelay(); }
690 int32_t VideoReceiver::NackList(uint16_t* nackList, uint16_t* size) {
691 VCMNackStatus nackStatus = kNackOk;
692 uint16_t nack_list_length = 0;
693 // Collect sequence numbers from the default receiver
694 // if in normal nack mode. Otherwise collect them from
695 // the dual receiver if the dual receiver is receiving.
696 if (_receiver.NackMode() != kNoNack) {
697 nackStatus = _receiver.NackList(nackList, *size, &nack_list_length);
699 if (nack_list_length == 0 && _dualReceiver.State() != kPassive) {
700 nackStatus = _dualReceiver.NackList(nackList, *size, &nack_list_length);
702 *size = nack_list_length;
703 if (nackStatus == kNackKeyFrameRequest) {
704 return RequestKeyFrame();
709 int32_t VideoReceiver::ReceivedFrameCount(VCMFrameCount* frameCount) const {
710 _receiver.ReceivedFrameCount(frameCount);
714 uint32_t VideoReceiver::DiscardedPackets() const {
715 return _receiver.DiscardedPackets();
718 int VideoReceiver::SetReceiverRobustnessMode(
719 ReceiverRobustness robustnessMode,
720 VCMDecodeErrorMode decode_error_mode) {
721 CriticalSectionScoped cs(_receiveCritSect);
722 switch (robustnessMode) {
723 case VideoCodingModule::kNone:
724 _receiver.SetNackMode(kNoNack, -1, -1);
725 _dualReceiver.SetNackMode(kNoNack, -1, -1);
726 if (decode_error_mode == kNoErrors) {
727 _keyRequestMode = kKeyOnLoss;
729 _keyRequestMode = kKeyOnError;
732 case VideoCodingModule::kHardNack:
733 // Always wait for retransmissions (except when decoding with errors).
734 _receiver.SetNackMode(kNack, -1, -1);
735 _dualReceiver.SetNackMode(kNoNack, -1, -1);
736 _keyRequestMode = kKeyOnError; // TODO(hlundin): On long NACK list?
738 case VideoCodingModule::kSoftNack:
740 assert(false); // TODO(hlundin): Not completed.
741 return VCM_NOT_IMPLEMENTED;
743 // Enable hybrid NACK/FEC. Always wait for retransmissions and don't add
744 // extra delay when RTT is above kLowRttNackMs.
745 _receiver.SetNackMode(kNack, media_optimization::kLowRttNackMs, -1);
746 _dualReceiver.SetNackMode(kNoNack, -1, -1);
747 _keyRequestMode = kKeyOnError;
750 case VideoCodingModule::kDualDecoder:
751 if (decode_error_mode == kNoErrors) {
752 return VCM_PARAMETER_ERROR;
754 // Enable NACK but don't wait for retransmissions and don't add any extra
756 _receiver.SetNackMode(kNack, 0, 0);
757 // Enable NACK, compensate with extra delay and wait for retransmissions.
758 _dualReceiver.SetNackMode(kNack, -1, -1);
759 _keyRequestMode = kKeyOnError;
761 case VideoCodingModule::kReferenceSelection:
763 assert(false); // TODO(hlundin): Not completed.
764 return VCM_NOT_IMPLEMENTED;
766 if (decode_error_mode == kNoErrors) {
767 return VCM_PARAMETER_ERROR;
769 _receiver.SetNackMode(kNoNack, -1, -1);
770 _dualReceiver.SetNackMode(kNoNack, -1, -1);
774 _receiver.SetDecodeErrorMode(decode_error_mode);
775 // The dual decoder should never decode with errors.
776 _dualReceiver.SetDecodeErrorMode(kNoErrors);
780 void VideoReceiver::SetDecodeErrorMode(VCMDecodeErrorMode decode_error_mode) {
781 CriticalSectionScoped cs(_receiveCritSect);
782 _receiver.SetDecodeErrorMode(decode_error_mode);
785 void VideoReceiver::SetNackSettings(size_t max_nack_list_size,
786 int max_packet_age_to_nack,
787 int max_incomplete_time_ms) {
788 if (max_nack_list_size != 0) {
789 CriticalSectionScoped process_cs(process_crit_sect_.get());
790 max_nack_list_size_ = max_nack_list_size;
792 _receiver.SetNackSettings(
793 max_nack_list_size, max_packet_age_to_nack, max_incomplete_time_ms);
794 _dualReceiver.SetNackSettings(
795 max_nack_list_size, max_packet_age_to_nack, max_incomplete_time_ms);
798 int VideoReceiver::SetMinReceiverDelay(int desired_delay_ms) {
799 return _receiver.SetMinReceiverDelay(desired_delay_ms);
802 void VideoReceiver::RegisterPreDecodeImageCallback(
803 EncodedImageCallback* observer) {
804 CriticalSectionScoped cs(_receiveCritSect);
805 pre_decode_image_callback_ = observer;
809 } // namespace webrtc