Add API to get the number of packets discarded by the video jitter buffer due to being too late.

BUG=
TEST=

Review URL: http://webrtc-codereview.appspot.com/200001

git-svn-id: http://webrtc.googlecode.com/svn/trunk@723 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2011-10-11 07:53:43 +00:00
parent 06887aebae
commit 791eec7424
13 changed files with 506 additions and 205 deletions

View File

@ -490,6 +490,12 @@ public:
// Return value : VCM_OK, on success. // Return value : VCM_OK, on success.
// <0, on error. // <0, on error.
virtual WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const = 0; virtual WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const = 0;
// Returns the number of packets discarded by the jitter buffer due to being
// too late. This can include duplicated packets which arrived after the
// frame was sent to the decoder. Therefore packets which were prematurely
// NACKed will be counted.
virtual WebRtc_UWord32 DiscardedPackets() const = 0;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -81,6 +81,7 @@ VCMJitterBuffer::VCMJitterBuffer(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId,
_dropCount(0), _dropCount(0),
_numConsecutiveOldFrames(0), _numConsecutiveOldFrames(0),
_numConsecutiveOldPackets(0), _numConsecutiveOldPackets(0),
_discardedPackets(0),
_jitterEstimate(vcmId, receiverId), _jitterEstimate(vcmId, receiverId),
_rttMs(0), _rttMs(0),
_nackMode(kNoNack), _nackMode(kNoNack),
@ -134,6 +135,7 @@ VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
_dropCount = rhs._dropCount; _dropCount = rhs._dropCount;
_numConsecutiveOldFrames = rhs._numConsecutiveOldFrames; _numConsecutiveOldFrames = rhs._numConsecutiveOldFrames;
_numConsecutiveOldPackets = rhs._numConsecutiveOldPackets; _numConsecutiveOldPackets = rhs._numConsecutiveOldPackets;
_discardedPackets = rhs._discardedPackets;
_jitterEstimate = rhs._jitterEstimate; _jitterEstimate = rhs._jitterEstimate;
_delayEstimate = rhs._delayEstimate; _delayEstimate = rhs._delayEstimate;
_waitingForCompletion = rhs._waitingForCompletion; _waitingForCompletion = rhs._waitingForCompletion;
@ -210,6 +212,7 @@ VCMJitterBuffer::Start()
_numConsecutiveOldFrames = 0; _numConsecutiveOldFrames = 0;
_numConsecutiveOldPackets = 0; _numConsecutiveOldPackets = 0;
_discardedPackets = 0;
_frameEvent.Reset(); // start in a non-signaled state _frameEvent.Reset(); // start in a non-signaled state
_packetEvent.Reset(); // start in a non-signaled state _packetEvent.Reset(); // start in a non-signaled state
@ -438,6 +441,11 @@ VCMJitterBuffer::GetFrameStatistics(WebRtc_UWord32& receivedDeltaFrames,
return 0; return 0;
} }
WebRtc_UWord32 VCMJitterBuffer::DiscardedPackets() const {
CriticalSectionScoped cs(_critSect);
return _discardedPackets;
}
// Gets frame to use for this timestamp. If no match, get empty frame. // Gets frame to use for this timestamp. If no match, get empty frame.
WebRtc_Word32 WebRtc_Word32
VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame) VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame)
@ -448,11 +456,12 @@ VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame)
} }
_critSect.Enter(); _critSect.Enter();
// Make sure that old empty packets are inserted.
if (LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp), if (LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
packet.timestamp) == _lastDecodedTimeStamp packet.timestamp) == _lastDecodedTimeStamp
&& packet.sizeBytes > 0) && packet.sizeBytes > 0)
// Make sure that old Empty packets are inserted.
{ {
_discardedPackets++; // Only counts discarded media packets
// Trying to get an old frame. // Trying to get an old frame.
_numConsecutiveOldPackets++; _numConsecutiveOldPackets++;
if (_numConsecutiveOldPackets > kMaxConsecutiveOldPackets) if (_numConsecutiveOldPackets > kMaxConsecutiveOldPackets)

View File

@ -68,6 +68,9 @@ public:
WebRtc_Word32 GetFrameStatistics(WebRtc_UWord32& receivedDeltaFrames, WebRtc_Word32 GetFrameStatistics(WebRtc_UWord32& receivedDeltaFrames,
WebRtc_UWord32& receivedKeyFrames) const; WebRtc_UWord32& receivedKeyFrames) const;
// Get number of packets discarded by the jitter buffer
WebRtc_UWord32 DiscardedPackets() const;
// Statistics, Calculate frame and bit rates // Statistics, Calculate frame and bit rates
WebRtc_Word32 GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate); WebRtc_Word32 GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate);
@ -223,6 +226,9 @@ private:
WebRtc_UWord32 _numConsecutiveOldFrames; WebRtc_UWord32 _numConsecutiveOldFrames;
// Number of packets in a row that have been too old // Number of packets in a row that have been too old
WebRtc_UWord32 _numConsecutiveOldPackets; WebRtc_UWord32 _numConsecutiveOldPackets;
// Number of packets discarded by the jitter buffer
WebRtc_UWord32 _discardedPackets;
// Filters for estimating jitter // Filters for estimating jitter
VCMJitterEstimator _jitterEstimate; VCMJitterEstimator _jitterEstimate;
// Calculates network delays used for jitter calculations // Calculates network delays used for jitter calculations

View File

@ -344,6 +344,10 @@ VCMReceiver::ReceivedFrameCount(VCMFrameCount& frameCount) const
frameCount.numKeyFrames); frameCount.numKeyFrames);
} }
WebRtc_UWord32 VCMReceiver::DiscardedPackets() const {
return _jitterBuffer.DiscardedPackets();
}
void void
VCMReceiver::SetNackMode(VCMNackMode nackMode) VCMReceiver::SetNackMode(VCMNackMode nackMode)
{ {

View File

@ -57,6 +57,7 @@ public:
void ReleaseFrame(VCMEncodedFrame* frame); void ReleaseFrame(VCMEncodedFrame* frame);
WebRtc_Word32 ReceiveStatistics(WebRtc_UWord32& bitRate, WebRtc_UWord32& frameRate); WebRtc_Word32 ReceiveStatistics(WebRtc_UWord32& bitRate, WebRtc_UWord32& frameRate);
WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const; WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const;
WebRtc_UWord32 DiscardedPackets() const;
// NACK // NACK
void SetNackMode(VCMNackMode nackMode); void SetNackMode(VCMNackMode nackMode);

View File

@ -31,7 +31,8 @@ VCMProcessTimer::Period() const
WebRtc_UWord32 WebRtc_UWord32
VCMProcessTimer::TimeUntilProcess() const VCMProcessTimer::TimeUntilProcess() const
{ {
return static_cast<WebRtc_UWord32>(VCM_MAX(static_cast<WebRtc_Word64>(_periodMs) - return static_cast<WebRtc_UWord32>(
VCM_MAX(static_cast<WebRtc_Word64>(_periodMs) -
(VCMTickTime::MillisecondTimestamp() - _latestMs), 0)); (VCMTickTime::MillisecondTimestamp() - _latestMs), 0));
} }
@ -105,7 +106,9 @@ VideoCodingModuleImpl::~VideoCodingModuleImpl()
VideoCodingModule* VideoCodingModule*
VideoCodingModule::Create(const WebRtc_Word32 id) VideoCodingModule::Create(const WebRtc_Word32 id)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(id),
"VideoCodingModule::Create()"); "VideoCodingModule::Create()");
return new VideoCodingModuleImpl(id); return new VideoCodingModuleImpl(id);
} }
@ -115,7 +118,8 @@ VideoCodingModule::Destroy(VideoCodingModule* module)
{ {
if (module != NULL) if (module != NULL)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
static_cast<VideoCodingModuleImpl*>(module)->Id(), static_cast<VideoCodingModuleImpl*>(module)->Id(),
"VideoCodingModule::Destroy()"); "VideoCodingModule::Destroy()");
delete static_cast<VideoCodingModuleImpl*>(module); delete static_cast<VideoCodingModuleImpl*>(module);
@ -135,7 +139,8 @@ VideoCodingModuleImpl::Process()
{ {
WebRtc_UWord32 bitRate; WebRtc_UWord32 bitRate;
WebRtc_UWord32 frameRate; WebRtc_UWord32 frameRate;
const WebRtc_Word32 ret = _receiver.ReceiveStatistics(bitRate, frameRate); const WebRtc_Word32 ret = _receiver.ReceiveStatistics(bitRate,
frameRate);
if (ret == 0) if (ret == 0)
{ {
_receiveStatsCallback->ReceiveStatistics(bitRate, frameRate); _receiveStatsCallback->ReceiveStatistics(bitRate, frameRate);
@ -157,8 +162,10 @@ VideoCodingModuleImpl::Process()
WebRtc_UWord32 frameRate; WebRtc_UWord32 frameRate;
{ {
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
bitRate = static_cast<WebRtc_UWord32>(_mediaOpt.SentBitRate() + 0.5f); bitRate = static_cast<WebRtc_UWord32>(
frameRate = static_cast<WebRtc_UWord32>(_mediaOpt.SentFrameRate() + 0.5f); _mediaOpt.SentBitRate() + 0.5f);
frameRate = static_cast<WebRtc_UWord32>(
_mediaOpt.SentFrameRate() + 0.5f);
} }
_sendStatsCallback->SendStatistics(bitRate, frameRate); _sendStatsCallback->SendStatistics(bitRate, frameRate);
} }
@ -207,10 +214,15 @@ VideoCodingModuleImpl::Version(WebRtc_Word8* version,
WebRtc_UWord32& remainingBufferInBytes, WebRtc_UWord32& remainingBufferInBytes,
WebRtc_UWord32& position) const WebRtc_UWord32& position) const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Version()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Version()");
if (version == NULL) if (version == NULL)
{ {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceWarning,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Invalid buffer pointer in argument to Version()"); "Invalid buffer pointer in argument to Version()");
return VCM_PARAMETER_ERROR; return VCM_PARAMETER_ERROR;
} }
@ -225,7 +237,9 @@ VideoCodingModuleImpl::Version(WebRtc_Word8* version,
position += ourLength; position += ourLength;
// Safe to truncate here. // Safe to truncate here.
WebRtc_Word32 ret = _codecDataBase.Version(version, remainingBufferInBytes, position); WebRtc_Word32 ret = _codecDataBase.Version(version,
remainingBufferInBytes,
position);
if (ret < 0) if (ret < 0)
{ {
return ret; return ret;
@ -242,7 +256,10 @@ VideoCodingModuleImpl::Version(WebRtc_Word8* version,
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::Id() const VideoCodingModuleImpl::Id() const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Id()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Id()");
CriticalSectionScoped receiveCs(_receiveCritSect); CriticalSectionScoped receiveCs(_receiveCritSect);
{ {
CriticalSectionScoped sendCs(_sendCritSect); CriticalSectionScoped sendCs(_sendCritSect);
@ -254,7 +271,10 @@ VideoCodingModuleImpl::Id() const
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::ChangeUniqueId(const WebRtc_Word32 id) VideoCodingModuleImpl::ChangeUniqueId(const WebRtc_Word32 id)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ChangeUniqueId()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"ChangeUniqueId()");
CriticalSectionScoped receiveCs(_receiveCritSect); CriticalSectionScoped receiveCs(_receiveCritSect);
{ {
CriticalSectionScoped sendCs(_sendCritSect); CriticalSectionScoped sendCs(_sendCritSect);
@ -263,15 +283,19 @@ VideoCodingModuleImpl::ChangeUniqueId(const WebRtc_Word32 id)
} }
} }
// Returns the number of milliseconds until the module wants a worker thread to call Process // Returns the number of milliseconds until the module wants a worker thread to
// call Process
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::TimeUntilNextProcess() VideoCodingModuleImpl::TimeUntilNextProcess()
{ {
WebRtc_UWord32 timeUntilNextProcess = VCM_MIN(_receiveStatsTimer.TimeUntilProcess(), WebRtc_UWord32 timeUntilNextProcess = VCM_MIN(
_receiveStatsTimer.TimeUntilProcess(),
_sendStatsTimer.TimeUntilProcess()); _sendStatsTimer.TimeUntilProcess());
if ((_receiver.NackMode() != kNoNack) || (_dualReceiver.State() != kPassive)) if ((_receiver.NackMode() != kNoNack) ||
(_dualReceiver.State() != kPassive))
{ {
// We need a Process call more often if we are relying on retransmissions // We need a Process call more often if we are relying on
// retransmissions
timeUntilNextProcess = VCM_MIN(timeUntilNextProcess, timeUntilNextProcess = VCM_MIN(timeUntilNextProcess,
_retransmissionTimer.TimeUntilProcess()); _retransmissionTimer.TimeUntilProcess());
} }
@ -285,7 +309,10 @@ VideoCodingModuleImpl::TimeUntilNextProcess()
WebRtc_UWord8 WebRtc_UWord8
VideoCodingModule::NumberOfCodecs() VideoCodingModule::NumberOfCodecs()
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, -1, "NumberOfCodecs()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
-1,
"NumberOfCodecs()");
return VCMCodecDataBase::NumberOfCodecs(); return VCMCodecDataBase::NumberOfCodecs();
} }
@ -293,7 +320,10 @@ VideoCodingModule::NumberOfCodecs()
WebRtc_Word32 WebRtc_Word32
VideoCodingModule::Codec(WebRtc_UWord8 listId, VideoCodec* codec) VideoCodingModule::Codec(WebRtc_UWord8 listId, VideoCodec* codec)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, -1, "Codec()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
-1,
"Codec()");
if (codec == NULL) if (codec == NULL)
{ {
return VCM_PARAMETER_ERROR; return VCM_PARAMETER_ERROR;
@ -305,7 +335,10 @@ VideoCodingModule::Codec(WebRtc_UWord8 listId, VideoCodec* codec)
WebRtc_Word32 WebRtc_Word32
VideoCodingModule::Codec(VideoCodecType codecType, VideoCodec* codec) VideoCodingModule::Codec(VideoCodecType codecType, VideoCodec* codec)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, -1, "Codec()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
-1,
"Codec()");
if (codec == NULL) if (codec == NULL)
{ {
return VCM_PARAMETER_ERROR; return VCM_PARAMETER_ERROR;
@ -321,7 +354,10 @@ VideoCodingModule::Codec(VideoCodecType codecType, VideoCodec* codec)
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::InitializeSender() VideoCodingModuleImpl::InitializeSender()
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "InitializeSender()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"InitializeSender()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
_codecDataBase.ResetSender(); _codecDataBase.ResetSender();
_encoder = NULL; _encoder = NULL;
@ -336,7 +372,10 @@ VideoCodingModuleImpl::InitializeSender()
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::ResetEncoder() VideoCodingModuleImpl::ResetEncoder()
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ResetEncoder()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"ResetEncoder()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
if (_encoder != NULL) if (_encoder != NULL)
{ {
@ -351,7 +390,10 @@ VideoCodingModuleImpl::RegisterSendCodec(const VideoCodec* sendCodec,
WebRtc_UWord32 numberOfCores, WebRtc_UWord32 numberOfCores,
WebRtc_UWord32 maxPayloadSize) WebRtc_UWord32 maxPayloadSize)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "RegisterSendCodec()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterSendCodec()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
if (sendCodec == NULL) if (sendCodec == NULL)
{ {
@ -368,7 +410,9 @@ VideoCodingModuleImpl::RegisterSendCodec(const VideoCodec* sendCodec,
_encoder = _codecDataBase.SetEncoder(sendCodec, &_encodedFrameCallback); _encoder = _codecDataBase.SetEncoder(sendCodec, &_encodedFrameCallback);
if (_encoder == NULL) if (_encoder == NULL)
{ {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceError,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Failed to initialize encoder"); "Failed to initialize encoder");
return VCM_CODEC_ERROR; return VCM_CODEC_ERROR;
} }
@ -388,7 +432,10 @@ VideoCodingModuleImpl::RegisterSendCodec(const VideoCodec* sendCodec,
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::SendCodec(VideoCodec* currentSendCodec) const VideoCodingModuleImpl::SendCodec(VideoCodec* currentSendCodec) const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "SendCodec()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SendCodec()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
if (currentSendCodec == NULL) if (currentSendCodec == NULL)
@ -402,7 +449,10 @@ VideoCodingModuleImpl::SendCodec(VideoCodec* currentSendCodec) const
VideoCodecType VideoCodecType
VideoCodingModuleImpl::SendCodec() const VideoCodingModuleImpl::SendCodec() const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "SendCodec()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SendCodec()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
return _codecDataBase.SendCodec(); return _codecDataBase.SendCodec();
@ -415,14 +465,17 @@ VideoCodingModuleImpl::RegisterExternalEncoder(VideoEncoder* externalEncoder,
WebRtc_UWord8 payloadType, WebRtc_UWord8 payloadType,
bool internalSource /*= false*/) bool internalSource /*= false*/)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterExternalEncoder()"); "RegisterExternalEncoder()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
if (externalEncoder == NULL) if (externalEncoder == NULL)
{ {
bool wasSendCodec = false; bool wasSendCodec = false;
const WebRtc_Word32 ret = _codecDataBase.DeRegisterExternalEncoder(payloadType, const WebRtc_Word32 ret = _codecDataBase.DeRegisterExternalEncoder(
payloadType,
wasSendCodec); wasSendCodec);
if (wasSendCodec) if (wasSendCodec)
{ {
@ -438,9 +491,12 @@ VideoCodingModuleImpl::RegisterExternalEncoder(VideoEncoder* externalEncoder,
// Get codec config parameters // Get codec config parameters
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::CodecConfigParameters(WebRtc_UWord8* buffer, WebRtc_Word32 size) VideoCodingModuleImpl::CodecConfigParameters(WebRtc_UWord8* buffer,
WebRtc_Word32 size)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"CodecConfigParameters()"); "CodecConfigParameters()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
if (_encoder != NULL) if (_encoder != NULL)
@ -454,7 +510,10 @@ VideoCodingModuleImpl::CodecConfigParameters(WebRtc_UWord8* buffer, WebRtc_Word3
WebRtc_UWord32 WebRtc_UWord32
VideoCodingModuleImpl::Bitrate() const VideoCodingModuleImpl::Bitrate() const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Bitrate()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Bitrate()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
// return the bit rate which the encoder is set to // return the bit rate which the encoder is set to
if (_encoder != NULL) if (_encoder != NULL)
@ -468,7 +527,10 @@ VideoCodingModuleImpl::Bitrate() const
WebRtc_UWord32 WebRtc_UWord32
VideoCodingModuleImpl::FrameRate() const VideoCodingModuleImpl::FrameRate() const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "FrameRate()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"FrameRate()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
// input frame rate, not compensated // input frame rate, not compensated
if (_encoder != NULL) if (_encoder != NULL)
@ -484,7 +546,9 @@ VideoCodingModuleImpl::SetChannelParameters(WebRtc_UWord32 availableBandWidth,
WebRtc_UWord8 lossRate, WebRtc_UWord8 lossRate,
WebRtc_UWord32 RTT) WebRtc_UWord32 RTT)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SetChannelParameters()"); "SetChannelParameters()");
WebRtc_Word32 ret = 0; WebRtc_Word32 ret = 0;
{ {
@ -499,7 +563,8 @@ VideoCodingModuleImpl::SetChannelParameters(WebRtc_UWord32 availableBandWidth,
{ {
return ret; return ret;
} }
ret = (WebRtc_Word32)_encoder->SetRates(targetRate, _mediaOpt.InputFrameRate()); ret = (WebRtc_Word32)_encoder->SetRates(targetRate,
_mediaOpt.InputFrameRate());
if (ret < 0) if (ret < 0)
{ {
return ret; return ret;
@ -516,18 +581,24 @@ VideoCodingModuleImpl::SetChannelParameters(WebRtc_UWord32 availableBandWidth,
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::SetReceiveChannelParameters(WebRtc_UWord32 RTT) VideoCodingModuleImpl::SetReceiveChannelParameters(WebRtc_UWord32 RTT)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SetReceiveChannelParameters()"); "SetReceiveChannelParameters()");
CriticalSectionScoped receiveCs(_receiveCritSect); CriticalSectionScoped receiveCs(_receiveCritSect);
_receiver.UpdateRtt(RTT); _receiver.UpdateRtt(RTT);
return 0; return 0;
} }
// Register a transport callback which will be called to deliver the encoded buffers // Register a transport callback which will be called to deliver the encoded
// buffers
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterTransportCallback(VCMPacketizationCallback* transport) VideoCodingModuleImpl::RegisterTransportCallback(
VCMPacketizationCallback* transport)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterTransportCallback()"); "RegisterTransportCallback()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
_encodedFrameCallback.SetMediaOpt(&_mediaOpt); _encodedFrameCallback.SetMediaOpt(&_mediaOpt);
@ -535,35 +606,42 @@ VideoCodingModuleImpl::RegisterTransportCallback(VCMPacketizationCallback* trans
return VCM_OK; return VCM_OK;
} }
// Register video output information callback which will be called to deliver information // Register video output information callback which will be called to deliver
// about the video stream produced by the encoder, for instance the average frame rate and // information about the video stream produced by the encoder, for instance the
// bit rate. // average frame rate and bit rate.
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterSendStatisticsCallback(VCMSendStatisticsCallback* sendStats) VideoCodingModuleImpl::RegisterSendStatisticsCallback(
VCMSendStatisticsCallback* sendStats)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterSendStatisticsCallback()"); "RegisterSendStatisticsCallback()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
_sendStatsCallback = sendStats; _sendStatsCallback = sendStats;
return VCM_OK; return VCM_OK;
} }
// Register a video quality settings callback which will be called when frame rate/dimensions // Register a video quality settings callback which will be called when frame
// need to be updated for video quality optimization // rate/dimensions need to be updated for video quality optimization
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterVideoQMCallback(VCMQMSettingsCallback* videoQMSettings) VideoCodingModuleImpl::RegisterVideoQMCallback(
VCMQMSettingsCallback* videoQMSettings)
{ {
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
return _mediaOpt.RegisterVideoQMCallback(videoQMSettings); return _mediaOpt.RegisterVideoQMCallback(videoQMSettings);
} }
// Register a video protection callback which will be called to deliver the requested FEC rate // Register a video protection callback which will be called to deliver the
// and NACK status (on/off). // requested FEC rate and NACK status (on/off).
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterProtectionCallback(VCMProtectionCallback* protection) VideoCodingModuleImpl::RegisterProtectionCallback(
VCMProtectionCallback* protection)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterProtectionCallback()"); "RegisterProtectionCallback()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
_mediaOpt.RegisterProtectionCallback(protection); _mediaOpt.RegisterProtectionCallback(protection);
@ -572,9 +650,12 @@ VideoCodingModuleImpl::RegisterProtectionCallback(VCMProtectionCallback* protect
// Enable or disable a video protection method. // Enable or disable a video protection method.
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::SetVideoProtection(VCMVideoProtection videoProtection, bool enable) VideoCodingModuleImpl::SetVideoProtection(VCMVideoProtection videoProtection,
bool enable)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SetVideoProtection()"); "SetVideoProtection()");
switch (videoProtection) switch (videoProtection)
@ -708,7 +789,10 @@ VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
const VideoContentMetrics* _contentMetrics, const VideoContentMetrics* _contentMetrics,
const CodecSpecificInfo* codecSpecificInfo) const CodecSpecificInfo* codecSpecificInfo)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "AddVideoFrame()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"AddVideoFrame()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
if (_encoder == NULL) if (_encoder == NULL)
@ -725,7 +809,9 @@ VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
if (_mediaOpt.DropFrame()) if (_mediaOpt.DropFrame())
{ {
WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceStream,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Drop frame due to bitrate"); "Drop frame due to bitrate");
} }
else else
@ -738,12 +824,15 @@ VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
requestedFrameType); requestedFrameType);
if (_encoderInputFile != NULL) if (_encoderInputFile != NULL)
{ {
fwrite(videoFrame.Buffer(), 1, videoFrame.Length(), _encoderInputFile); fwrite(videoFrame.Buffer(), 1, videoFrame.Length(),
_encoderInputFile);
} }
if (ret < 0) if (ret < 0)
{ {
_nextFrameType = requestedFrameType; _nextFrameType = requestedFrameType;
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding,VCMId(_id), WEBRTC_TRACE(webrtc::kTraceError,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Encode error: %d", ret); "Encode error: %d", ret);
return ret; return ret;
} }
@ -757,13 +846,16 @@ VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::FrameTypeRequest(FrameType frameType) VideoCodingModuleImpl::FrameTypeRequest(FrameType frameType)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "FrameTypeRequest()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"FrameTypeRequest()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
_nextFrameType = frameType; _nextFrameType = frameType;
if (_encoder != NULL && _encoder->InternalSource()) if (_encoder != NULL && _encoder->InternalSource())
{ {
// Try to request the frame if we have an external encoder with internal source // Try to request the frame if we have an external encoder with
// since AddVideoFrame never will be called. // internal source since AddVideoFrame never will be called.
if (_encoder->RequestFrame(_nextFrameType) == WEBRTC_VIDEO_CODEC_OK) if (_encoder->RequestFrame(_nextFrameType) == WEBRTC_VIDEO_CODEC_OK)
{ {
_nextFrameType = kVideoFrameDelta; _nextFrameType = kVideoFrameDelta;
@ -784,7 +876,10 @@ VideoCodingModuleImpl::EnableFrameDropper(bool enable)
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::SentFrameCount(VCMFrameCount &frameCount) const VideoCodingModuleImpl::SentFrameCount(VCMFrameCount &frameCount) const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "SentFrameCount()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SentFrameCount()");
CriticalSectionScoped cs(_sendCritSect); CriticalSectionScoped cs(_sendCritSect);
return _mediaOpt.SentFrameCount(frameCount); return _mediaOpt.SentFrameCount(frameCount);
} }
@ -793,7 +888,9 @@ VideoCodingModuleImpl::SentFrameCount(VCMFrameCount &frameCount) const
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::InitializeReceiver() VideoCodingModuleImpl::InitializeReceiver()
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"InitializeReceiver()"); "InitializeReceiver()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
WebRtc_Word32 ret = _receiver.Initialize(); WebRtc_Word32 ret = _receiver.Initialize();
@ -823,12 +920,15 @@ VideoCodingModuleImpl::InitializeReceiver()
return VCM_OK; return VCM_OK;
} }
// Register a receive callback. Will be called whenever there is a new frame ready // Register a receive callback. Will be called whenever there is a new frame
// for rendering. // ready for rendering.
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterReceiveCallback(VCMReceiveCallback* receiveCallback) VideoCodingModuleImpl::RegisterReceiveCallback(
VCMReceiveCallback* receiveCallback)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterReceiveCallback()"); "RegisterReceiveCallback()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
_decodedFrameCallback.SetUserReceiveCallback(receiveCallback); _decodedFrameCallback.SetUserReceiveCallback(receiveCallback);
@ -839,7 +939,9 @@ WebRtc_Word32
VideoCodingModuleImpl::RegisterReceiveStatisticsCallback( VideoCodingModuleImpl::RegisterReceiveStatisticsCallback(
VCMReceiveStatisticsCallback* receiveStats) VCMReceiveStatisticsCallback* receiveStats)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterReceiveStatisticsCallback()"); "RegisterReceiveStatisticsCallback()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
_receiveStatsCallback = receiveStats; _receiveStatsCallback = receiveStats;
@ -874,9 +976,12 @@ VideoCodingModuleImpl::RegisterExternalDecoder(VideoDecoder* externalDecoder,
// Register a frame type request callback. // Register a frame type request callback.
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterFrameTypeCallback(VCMFrameTypeCallback* frameTypeCallback) VideoCodingModuleImpl::RegisterFrameTypeCallback(
VCMFrameTypeCallback* frameTypeCallback)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterFrameTypeCallback()"); "RegisterFrameTypeCallback()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
_frameTypeCallback = frameTypeCallback; _frameTypeCallback = frameTypeCallback;
@ -884,9 +989,12 @@ VideoCodingModuleImpl::RegisterFrameTypeCallback(VCMFrameTypeCallback* frameType
} }
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterFrameStorageCallback(VCMFrameStorageCallback* frameStorageCallback) VideoCodingModuleImpl::RegisterFrameStorageCallback(
VCMFrameStorageCallback* frameStorageCallback)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterFrameStorageCallback()"); "RegisterFrameStorageCallback()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
_frameStorageCallback = frameStorageCallback; _frameStorageCallback = frameStorageCallback;
@ -894,9 +1002,12 @@ VideoCodingModuleImpl::RegisterFrameStorageCallback(VCMFrameStorageCallback* fra
} }
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RegisterPacketRequestCallback(VCMPacketRequestCallback* callback) VideoCodingModuleImpl::RegisterPacketRequestCallback(
VCMPacketRequestCallback* callback)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterPacketRequestCallback()"); "RegisterPacketRequestCallback()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
_packetRequestCallback = callback; _packetRequestCallback = callback;
@ -908,9 +1019,11 @@ VideoCodingModuleImpl::RegisterPacketRequestCallback(VCMPacketRequestCallback* c
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::Decode(WebRtc_UWord16 maxWaitTimeMs) VideoCodingModuleImpl::Decode(WebRtc_UWord16 maxWaitTimeMs)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Decode()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Decode()");
WebRtc_Word64 nextRenderTimeMs; WebRtc_Word64 nextRenderTimeMs;
{ {
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
if (!_receiverInited) if (!_receiverInited)
@ -923,20 +1036,23 @@ VideoCodingModuleImpl::Decode(WebRtc_UWord16 maxWaitTimeMs)
} }
} }
const bool dualReceiverEnabledNotReceiving = _dualReceiver.State() != kReceiving && const bool dualReceiverEnabledNotReceiving =
_dualReceiver.NackMode() == kNackInfinite; (_dualReceiver.State() != kReceiving &&
_dualReceiver.NackMode() == kNackInfinite);
VCMEncodedFrame* frame = _receiver.FrameForDecoding(maxWaitTimeMs, VCMEncodedFrame* frame = _receiver.FrameForDecoding(
maxWaitTimeMs,
nextRenderTimeMs, nextRenderTimeMs,
_codecDataBase.RenderTiming(), _codecDataBase.RenderTiming(),
&_dualReceiver); &_dualReceiver);
if (dualReceiverEnabledNotReceiving && _dualReceiver.State() == kReceiving) if (dualReceiverEnabledNotReceiving && _dualReceiver.State() == kReceiving)
{ {
// Dual receiver is enabled (kNACK enabled), but was not receiving before the call to // Dual receiver is enabled (kNACK enabled), but was not receiving
// FrameForDecoding(). After the call the state changed to receiving, and therefore // before the call to FrameForDecoding(). After the call the state
// we must copy the primary decoder state to the dual decoder to make it possible // changed to receiving, and therefore we must copy the primary decoder
// for the dual decoder to start decoding retransmitted frames and recover. // state to the dual decoder to make it possible for the dual decoder to
// start decoding retransmitted frames and recover.
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
if (_dualDecoder != NULL) if (_dualDecoder != NULL)
{ {
@ -945,7 +1061,8 @@ VideoCodingModuleImpl::Decode(WebRtc_UWord16 maxWaitTimeMs)
_dualDecoder = _codecDataBase.CreateDecoderCopy(); _dualDecoder = _codecDataBase.CreateDecoderCopy();
if (_dualDecoder != NULL) if (_dualDecoder != NULL)
{ {
_dualDecoder->RegisterDecodeCompleteCallback(&_dualDecodedFrameCallback); _dualDecoder->RegisterDecodeCompleteCallback(
&_dualDecodedFrameCallback);
} }
} }
@ -954,12 +1071,14 @@ VideoCodingModuleImpl::Decode(WebRtc_UWord16 maxWaitTimeMs)
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
// If this frame was too late, we should adjust the delay accordingly // If this frame was too late, we should adjust the delay accordingly
_timing.UpdateCurrentDelay(frame->RenderTimeMs(), VCMTickTime::MillisecondTimestamp()); _timing.UpdateCurrentDelay(frame->RenderTimeMs(),
VCMTickTime::MillisecondTimestamp());
if (_bitStreamBeforeDecoder != NULL) if (_bitStreamBeforeDecoder != NULL)
{ {
// Write bit stream to file for debugging purposes // Write bit stream to file for debugging purposes
fwrite(frame->Buffer(), 1, frame->Length(), _bitStreamBeforeDecoder); fwrite(frame->Buffer(), 1, frame->Length(),
_bitStreamBeforeDecoder);
} }
if (_frameStorageCallback != NULL) if (_frameStorageCallback != NULL)
{ {
@ -982,22 +1101,30 @@ VideoCodingModuleImpl::Decode(WebRtc_UWord16 maxWaitTimeMs)
} }
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::RequestSliceLossIndication(const WebRtc_UWord64 pictureID) const VideoCodingModuleImpl::RequestSliceLossIndication(
const WebRtc_UWord64 pictureID) const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterSliceLossIndication()"); "RegisterSliceLossIndication()");
if (_frameTypeCallback != NULL) if (_frameTypeCallback != NULL)
{ {
const WebRtc_Word32 ret = _frameTypeCallback->SliceLossIndicationRequest(pictureID); const WebRtc_Word32 ret =
_frameTypeCallback->SliceLossIndicationRequest(pictureID);
if (ret < 0) if (ret < 0)
{ {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceError,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Failed to request key frame"); "Failed to request key frame");
return ret; return ret;
} }
} else } else
{ {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceWarning,
webrtc::kTraceVideoCoding,
VCMId(_id),
"No frame type request callback registered"); "No frame type request callback registered");
return VCM_MISSING_CALLBACK; return VCM_MISSING_CALLBACK;
} }
@ -1009,10 +1136,13 @@ VideoCodingModuleImpl::RequestKeyFrame()
{ {
if (_frameTypeCallback != NULL) if (_frameTypeCallback != NULL)
{ {
const WebRtc_Word32 ret = _frameTypeCallback->FrameTypeRequest(kVideoFrameKey); const WebRtc_Word32 ret = _frameTypeCallback->FrameTypeRequest(
kVideoFrameKey);
if (ret < 0) if (ret < 0)
{ {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceError,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Failed to request key frame"); "Failed to request key frame");
return ret; return ret;
} }
@ -1020,7 +1150,9 @@ VideoCodingModuleImpl::RequestKeyFrame()
} }
else else
{ {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceWarning,
webrtc::kTraceVideoCoding,
VCMId(_id),
"No frame type request callback registered"); "No frame type request callback registered");
return VCM_MISSING_CALLBACK; return VCM_MISSING_CALLBACK;
} }
@ -1030,26 +1162,37 @@ VideoCodingModuleImpl::RequestKeyFrame()
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::DecodeDualFrame(WebRtc_UWord16 maxWaitTimeMs) VideoCodingModuleImpl::DecodeDualFrame(WebRtc_UWord16 maxWaitTimeMs)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "DecodeDualFrame()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"DecodeDualFrame()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
if (_dualReceiver.State() != kReceiving || _dualReceiver.NackMode() != kNackInfinite) if (_dualReceiver.State() != kReceiving ||
_dualReceiver.NackMode() != kNackInfinite)
{ {
// The dual receiver is currently not receiving or dual decoder mode is disabled. // The dual receiver is currently not receiving or
// dual decoder mode is disabled.
return VCM_OK; return VCM_OK;
} }
WebRtc_Word64 dummyRenderTime; WebRtc_Word64 dummyRenderTime;
WebRtc_Word32 decodeCount = 0; WebRtc_Word32 decodeCount = 0;
VCMEncodedFrame* dualFrame = _dualReceiver.FrameForDecoding(maxWaitTimeMs, VCMEncodedFrame* dualFrame = _dualReceiver.FrameForDecoding(
maxWaitTimeMs,
dummyRenderTime); dummyRenderTime);
if (dualFrame != NULL && _dualDecoder != NULL) if (dualFrame != NULL && _dualDecoder != NULL)
{ {
WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceStream,
"Decoding frame %u with dual decoder", dualFrame->TimeStamp()); webrtc::kTraceVideoCoding,
VCMId(_id),
"Decoding frame %u with dual decoder",
dualFrame->TimeStamp());
// Decode dualFrame and try to catch up // Decode dualFrame and try to catch up
WebRtc_Word32 ret = _dualDecoder->Decode(*dualFrame); WebRtc_Word32 ret = _dualDecoder->Decode(*dualFrame);
if (ret != WEBRTC_VIDEO_CODEC_OK) if (ret != WEBRTC_VIDEO_CODEC_OK)
{ {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceWarning,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Failed to decode frame with dual decoder"); "Failed to decode frame with dual decoder");
_dualReceiver.ReleaseFrame(dualFrame); _dualReceiver.ReleaseFrame(dualFrame);
return VCM_CODEC_ERROR; return VCM_CODEC_ERROR;
@ -1058,7 +1201,9 @@ VideoCodingModuleImpl::DecodeDualFrame(WebRtc_UWord16 maxWaitTimeMs)
{ {
// Copy the complete decoder state of the dual decoder // Copy the complete decoder state of the dual decoder
// to the primary decoder. // to the primary decoder.
WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceStream,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Dual decoder caught up"); "Dual decoder caught up");
_codecDataBase.CopyDecoder(*_dualDecoder); _codecDataBase.CopyDecoder(*_dualDecoder);
_codecDataBase.ReleaseDecoder(_dualDecoder); _codecDataBase.ReleaseDecoder(_dualDecoder);
@ -1077,7 +1222,8 @@ VideoCodingModuleImpl::Decode(const VCMEncodedFrame& frame)
{ {
// Change decoder if payload type has changed // Change decoder if payload type has changed
const bool renderTimingBefore = _codecDataBase.RenderTiming(); const bool renderTimingBefore = _codecDataBase.RenderTiming();
_decoder = _codecDataBase.SetDecoder(frame.PayloadType(), _decodedFrameCallback); _decoder = _codecDataBase.SetDecoder(frame.PayloadType(),
_decodedFrameCallback);
if (renderTimingBefore != _codecDataBase.RenderTiming()) if (renderTimingBefore != _codecDataBase.RenderTiming())
{ {
// Make sure we reset the decode time estimate since it will // Make sure we reset the decode time estimate since it will
@ -1101,14 +1247,18 @@ VideoCodingModuleImpl::Decode(const VCMEncodedFrame& frame)
} }
else else
{ {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceError,
"Failed to decode frame %u, requesting key frame", frame.TimeStamp()); webrtc::kTraceVideoCoding,
VCMId(_id),
"Failed to decode frame %u, requesting key frame",
frame.TimeStamp());
ret = RequestKeyFrame(); ret = RequestKeyFrame();
} }
} }
else if (ret == VCM_REQUEST_SLI) else if (ret == VCM_REQUEST_SLI)
{ {
ret = RequestSliceLossIndication(_decodedFrameCallback.LastReceivedPictureID() + 1); ret = RequestSliceLossIndication(
_decodedFrameCallback.LastReceivedPictureID() + 1);
} }
if (!frame.Complete() || frame.MissingFrame()) if (!frame.Complete() || frame.MissingFrame())
{ {
@ -1136,9 +1286,13 @@ VideoCodingModuleImpl::Decode(const VCMEncodedFrame& frame)
} }
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::DecodeFromStorage(const EncodedVideoData& frameFromStorage) VideoCodingModuleImpl::DecodeFromStorage(
const EncodedVideoData& frameFromStorage)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "DecodeFromStorage()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"DecodeFromStorage()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
WebRtc_Word32 ret = _frameFromFile.ExtractFromStorage(frameFromStorage); WebRtc_Word32 ret = _frameFromFile.ExtractFromStorage(frameFromStorage);
if (ret < 0) if (ret < 0)
@ -1152,7 +1306,10 @@ VideoCodingModuleImpl::DecodeFromStorage(const EncodedVideoData& frameFromStorag
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::ResetDecoder() VideoCodingModuleImpl::ResetDecoder()
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ResetDecoder()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"ResetDecoder()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
if (_decoder != NULL) if (_decoder != NULL)
{ {
@ -1179,21 +1336,27 @@ VideoCodingModuleImpl::RegisterReceiveCodec(const VideoCodec* receiveCodec,
WebRtc_Word32 numberOfCores, WebRtc_Word32 numberOfCores,
bool requireKeyFrame) bool requireKeyFrame)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"RegisterReceiveCodec()"); "RegisterReceiveCodec()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
if (receiveCodec == NULL) if (receiveCodec == NULL)
{ {
return VCM_PARAMETER_ERROR; return VCM_PARAMETER_ERROR;
} }
return _codecDataBase.RegisterReceiveCodec(receiveCodec, numberOfCores, requireKeyFrame); return _codecDataBase.RegisterReceiveCodec(receiveCodec, numberOfCores,
requireKeyFrame);
} }
// Get current received codec // Get current received codec
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::ReceiveCodec(VideoCodec* currentReceiveCodec) const VideoCodingModuleImpl::ReceiveCodec(VideoCodec* currentReceiveCodec) const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ReceiveCodec()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"ReceiveCodec()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
if (currentReceiveCodec == NULL) if (currentReceiveCodec == NULL)
{ {
@ -1206,7 +1369,10 @@ VideoCodingModuleImpl::ReceiveCodec(VideoCodec* currentReceiveCodec) const
VideoCodecType VideoCodecType
VideoCodingModuleImpl::ReceiveCodec() const VideoCodingModuleImpl::ReceiveCodec() const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ReceiveCodec()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"ReceiveCodec()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
return _codecDataBase.ReceiveCodec(); return _codecDataBase.ReceiveCodec();
} }
@ -1217,7 +1383,10 @@ VideoCodingModuleImpl::IncomingPacket(const WebRtc_UWord8* incomingPayload,
WebRtc_UWord32 payloadLength, WebRtc_UWord32 payloadLength,
const WebRtcRTPHeader& rtpInfo) const WebRtcRTPHeader& rtpInfo)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "IncomingPacket()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"IncomingPacket()");
const VCMPacket packet(incomingPayload, payloadLength, rtpInfo); const VCMPacket packet(incomingPayload, payloadLength, rtpInfo);
WebRtc_Word32 ret; WebRtc_Word32 ret;
if (_dualReceiver.State() != kPassive) if (_dualReceiver.State() != kPassive)
@ -1230,7 +1399,8 @@ VideoCodingModuleImpl::IncomingPacket(const WebRtc_UWord8* incomingPayload,
return ret; return ret;
} }
} }
ret = _receiver.InsertPacket(packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height); ret = _receiver.InsertPacket(packet, rtpInfo.type.Video.width,
rtpInfo.type.Video.height);
if (ret < 0) if (ret < 0)
{ {
return ret; return ret;
@ -1244,14 +1414,20 @@ VideoCodingModuleImpl::SetCodecConfigParameters(WebRtc_UWord8 payloadType,
const WebRtc_UWord8* buffer, const WebRtc_UWord8* buffer,
WebRtc_Word32 length) WebRtc_Word32 length)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SetCodecConfigParameters()"); "SetCodecConfigParameters()");
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
WebRtc_Word32 ret = _codecDataBase.SetCodecConfigParameters(payloadType, buffer, length); WebRtc_Word32 ret = _codecDataBase.SetCodecConfigParameters(payloadType,
buffer,
length);
if (ret < 0) if (ret < 0)
{ {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceError,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SetCodecConfigParameters() failed, %d", ret); "SetCodecConfigParameters() failed, %d", ret);
return ret; return ret;
} }
@ -1264,7 +1440,9 @@ VideoCodingModuleImpl::SetCodecConfigParameters(WebRtc_UWord8 payloadType,
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::SetMinimumPlayoutDelay(WebRtc_UWord32 minPlayoutDelayMs) VideoCodingModuleImpl::SetMinimumPlayoutDelay(WebRtc_UWord32 minPlayoutDelayMs)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SetMininumPlayoutDelay(%u)", minPlayoutDelayMs); "SetMininumPlayoutDelay(%u)", minPlayoutDelayMs);
_timing.SetMinimumTotalDelay(minPlayoutDelayMs); _timing.SetMinimumTotalDelay(minPlayoutDelayMs);
return VCM_OK; return VCM_OK;
@ -1275,7 +1453,9 @@ VideoCodingModuleImpl::SetMinimumPlayoutDelay(WebRtc_UWord32 minPlayoutDelayMs)
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::SetRenderDelay(WebRtc_UWord32 timeMS) VideoCodingModuleImpl::SetRenderDelay(WebRtc_UWord32 timeMS)
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"SetRenderDelay(%u)", timeMS); "SetRenderDelay(%u)", timeMS);
_timing.SetRenderDelay(timeMS); _timing.SetRenderDelay(timeMS);
return VCM_OK; return VCM_OK;
@ -1285,7 +1465,10 @@ VideoCodingModuleImpl::SetRenderDelay(WebRtc_UWord32 timeMS)
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::Delay() const VideoCodingModuleImpl::Delay() const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Delay()"); WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Delay()");
return _timing.TargetVideoDelay(); return _timing.TargetVideoDelay();
} }
@ -1314,14 +1497,18 @@ VideoCodingModuleImpl::NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size)
{ {
case kNackNeedMoreMemory: case kNackNeedMoreMemory:
{ {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceError,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Out of memory"); "Out of memory");
return VCM_MEMORY; return VCM_MEMORY;
} }
case kNackKeyFrameRequest: case kNackKeyFrameRequest:
{ {
CriticalSectionScoped cs(_receiveCritSect); CriticalSectionScoped cs(_receiveCritSect);
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceWarning,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Failed to get NACK list, requesting key frame"); "Failed to get NACK list, requesting key frame");
return RequestKeyFrame(); return RequestKeyFrame();
} }
@ -1334,9 +1521,19 @@ VideoCodingModuleImpl::NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size)
WebRtc_Word32 WebRtc_Word32
VideoCodingModuleImpl::ReceivedFrameCount(VCMFrameCount& frameCount) const VideoCodingModuleImpl::ReceivedFrameCount(VCMFrameCount& frameCount) const
{ {
WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"ReceivedFrameCount()"); "ReceivedFrameCount()");
return _receiver.ReceivedFrameCount(frameCount); return _receiver.ReceivedFrameCount(frameCount);
} }
WebRtc_UWord32 VideoCodingModuleImpl::DiscardedPackets() const {
WEBRTC_TRACE(webrtc::kTraceModuleCall,
webrtc::kTraceVideoCoding,
VCMId(_id),
"DiscardedPackets()");
return _receiver.DiscardedPackets();
} }
} // namespace webrtc

View File

@ -44,8 +44,10 @@ private:
enum VCMKeyRequestMode enum VCMKeyRequestMode
{ {
kKeyOnError, // Normal mode, request key frames on decoder error kKeyOnError, // Normal mode, request key frames on decoder error
kKeyOnKeyLoss, // Request key frames on decoder error and on packet loss in key frames kKeyOnKeyLoss, // Request key frames on decoder error and on packet loss
kKeyOnLoss, // Request key frames on decoder error and on packet loss in any frame // in key frames.
kKeyOnLoss, // Request key frames on decoder error and on packet loss
// in any frame
}; };
class VideoCodingModuleImpl : public VideoCodingModule class VideoCodingModuleImpl : public VideoCodingModule
@ -65,7 +67,8 @@ public:
// Change the unique identifier of this object // Change the unique identifier of this object
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id); virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
// Returns the number of milliseconds until the module want a worker thread to call Process // Returns the number of milliseconds until the module want a worker thread
// to call Process
virtual WebRtc_Word32 TimeUntilNextProcess(); virtual WebRtc_Word32 TimeUntilNextProcess();
virtual WebRtc_Word32 Process(); virtual WebRtc_Word32 Process();
@ -97,7 +100,8 @@ public:
bool internalSource = false); bool internalSource = false);
// Get codec config parameters // Get codec config parameters
virtual WebRtc_Word32 CodecConfigParameters(WebRtc_UWord8* buffer, WebRtc_Word32 size); virtual WebRtc_Word32 CodecConfigParameters(WebRtc_UWord8* buffer,
WebRtc_Word32 size);
// Get encode bitrate // Get encode bitrate
virtual WebRtc_UWord32 Bitrate() const; virtual WebRtc_UWord32 Bitrate() const;
@ -106,30 +110,38 @@ public:
virtual WebRtc_UWord32 FrameRate() const; virtual WebRtc_UWord32 FrameRate() const;
// Set channel parameters // Set channel parameters
virtual WebRtc_Word32 SetChannelParameters(WebRtc_UWord32 availableBandWidth, virtual WebRtc_Word32 SetChannelParameters(
WebRtc_UWord32 availableBandWidth,
WebRtc_UWord8 lossRate, WebRtc_UWord8 lossRate,
WebRtc_UWord32 RTT); WebRtc_UWord32 RTT);
// Set recieve channel parameters // Set recieve channel parameters
virtual WebRtc_Word32 SetReceiveChannelParameters(WebRtc_UWord32 RTT); virtual WebRtc_Word32 SetReceiveChannelParameters(WebRtc_UWord32 RTT);
// Register a transport callback which will be called to deliver the encoded buffers // Register a transport callback which will be called to deliver the
virtual WebRtc_Word32 RegisterTransportCallback(VCMPacketizationCallback* transport); // encoded buffers
virtual WebRtc_Word32 RegisterTransportCallback(
VCMPacketizationCallback* transport);
// Register a send statistics callback which will be called to deliver information // Register a send statistics callback which will be called to deliver
// about the video stream produced by the encoder, // information about the video stream produced by the encoder,
// for instance the average frame rate and bit rate. // for instance the average frame rate and bit rate.
virtual WebRtc_Word32 RegisterSendStatisticsCallback(VCMSendStatisticsCallback* sendStats); virtual WebRtc_Word32 RegisterSendStatisticsCallback(
VCMSendStatisticsCallback* sendStats);
// Register a video quality settings callback which will be called when // Register a video quality settings callback which will be called when
// frame rate/dimensions need to be updated for video quality optimization // frame rate/dimensions need to be updated for video quality optimization
virtual WebRtc_Word32 RegisterVideoQMCallback(VCMQMSettingsCallback* videoQMSettings); virtual WebRtc_Word32 RegisterVideoQMCallback(
VCMQMSettingsCallback* videoQMSettings);
// Register a video protection callback which will be called to deliver // Register a video protection callback which will be called to deliver
// the requested FEC rate and NACK status (on/off). // the requested FEC rate and NACK status (on/off).
virtual WebRtc_Word32 RegisterProtectionCallback(VCMProtectionCallback* protection); virtual WebRtc_Word32 RegisterProtectionCallback(
VCMProtectionCallback* protection);
// Enable or disable a video protection method. // Enable or disable a video protection method.
virtual WebRtc_Word32 SetVideoProtection(VCMVideoProtection videoProtection, bool enable); virtual WebRtc_Word32 SetVideoProtection(VCMVideoProtection videoProtection,
bool enable);
// Add one raw video frame to the encoder, blocking. // Add one raw video frame to the encoder, blocking.
virtual WebRtc_Word32 AddVideoFrame( virtual WebRtc_Word32 AddVideoFrame(
@ -164,31 +176,35 @@ public:
WebRtc_UWord8 payloadType, WebRtc_UWord8 payloadType,
bool internalRenderTiming); bool internalRenderTiming);
// Register a receive callback. Will be called whenever there are a new frame ready // Register a receive callback. Will be called whenever there are a new
// for rendering. // frame ready for rendering.
virtual WebRtc_Word32 RegisterReceiveCallback(VCMReceiveCallback* receiveCallback); virtual WebRtc_Word32 RegisterReceiveCallback(
VCMReceiveCallback* receiveCallback);
// Register a receive statistics callback which will be called to deliver information // Register a receive statistics callback which will be called to deliver
// about the video stream received by the receiving side of the VCM, for instance // information about the video stream received by the receiving side of the
// the average frame rate and bit rate. // VCM, for instance the average frame rate and bit rate.
virtual WebRtc_Word32 RegisterReceiveStatisticsCallback( virtual WebRtc_Word32 RegisterReceiveStatisticsCallback(
VCMReceiveStatisticsCallback* receiveStats); VCMReceiveStatisticsCallback* receiveStats);
// Register a frame type request callback. // Register a frame type request callback.
virtual WebRtc_Word32 RegisterFrameTypeCallback(VCMFrameTypeCallback* frameTypeCallback); virtual WebRtc_Word32 RegisterFrameTypeCallback(
VCMFrameTypeCallback* frameTypeCallback);
// Register a frame storage callback. // Register a frame storage callback.
virtual WebRtc_Word32 RegisterFrameStorageCallback( virtual WebRtc_Word32 RegisterFrameStorageCallback(
VCMFrameStorageCallback* frameStorageCallback); VCMFrameStorageCallback* frameStorageCallback);
// Nack callback // Nack callback
virtual WebRtc_Word32 RegisterPacketRequestCallback(VCMPacketRequestCallback* callback); virtual WebRtc_Word32 RegisterPacketRequestCallback(
VCMPacketRequestCallback* callback);
// Decode next frame, blocks for a maximum of maxWaitTimeMs milliseconds. // Decode next frame, blocks for a maximum of maxWaitTimeMs milliseconds.
// Should be called as often as possible to get the most out of the decoder. // Should be called as often as possible to get the most out of the decoder.
virtual WebRtc_Word32 Decode(WebRtc_UWord16 maxWaitTimeMs = 200); virtual WebRtc_Word32 Decode(WebRtc_UWord16 maxWaitTimeMs = 200);
// Decode next dual frame, blocks for a maximum of maxWaitTimeMs milliseconds. // Decode next dual frame, blocks for a maximum of maxWaitTimeMs
// milliseconds.
virtual WebRtc_Word32 DecodeDualFrame(WebRtc_UWord16 maxWaitTimeMs = 200); virtual WebRtc_Word32 DecodeDualFrame(WebRtc_UWord16 maxWaitTimeMs = 200);
// Reset the decoder state // Reset the decoder state
@ -207,17 +223,19 @@ public:
// A part of an encoded frame to be decoded. // A part of an encoded frame to be decoded.
// Used in conjunction with VCMFrameStorageCallback. // Used in conjunction with VCMFrameStorageCallback.
virtual WebRtc_Word32 DecodeFromStorage(const EncodedVideoData& frameFromStorage); virtual WebRtc_Word32 DecodeFromStorage(
const EncodedVideoData& frameFromStorage);
// Set codec config parameters // Set codec config parameters
virtual WebRtc_Word32 SetCodecConfigParameters(WebRtc_UWord8 payloadType, virtual WebRtc_Word32 SetCodecConfigParameters(WebRtc_UWord8 payloadType,
const WebRtc_UWord8* buffer, const WebRtc_UWord8* buffer,
WebRtc_Word32 length); WebRtc_Word32 length);
// Minimum playout delay (Used for lip-sync). This is the minimum delay required // Minimum playout delay (Used for lip-sync). This is the minimum delay
// to sync with audio. Not included in VideoCodingModule::Delay() // required to sync with audio. Not included in VideoCodingModule::Delay()
// Defaults to 0 ms. // Defaults to 0 ms.
virtual WebRtc_Word32 SetMinimumPlayoutDelay(WebRtc_UWord32 minPlayoutDelayMs); virtual WebRtc_Word32 SetMinimumPlayoutDelay(
WebRtc_UWord32 minPlayoutDelayMs);
// The estimated delay caused by rendering // The estimated delay caused by rendering
virtual WebRtc_Word32 SetRenderDelay(WebRtc_UWord32 timeMS); virtual WebRtc_Word32 SetRenderDelay(WebRtc_UWord32 timeMS);
@ -228,15 +246,19 @@ public:
// Received frame counters // Received frame counters
virtual WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const; virtual WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const;
// Returns the number of packets discarded by the jitter buffer.
virtual WebRtc_UWord32 DiscardedPackets() const;
protected: protected:
WebRtc_Word32 Decode(const webrtc::VCMEncodedFrame& frame); WebRtc_Word32 Decode(const webrtc::VCMEncodedFrame& frame);
WebRtc_Word32 RequestKeyFrame(); WebRtc_Word32 RequestKeyFrame();
WebRtc_Word32 RequestSliceLossIndication(const WebRtc_UWord64 pictureID) const; WebRtc_Word32 RequestSliceLossIndication(
const WebRtc_UWord64 pictureID) const;
WebRtc_Word32 NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size); WebRtc_Word32 NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size);
private: private:
WebRtc_Word32 _id; WebRtc_Word32 _id;
CriticalSectionWrapper& _receiveCritSect; // Critical section for receive side CriticalSectionWrapper& _receiveCritSect;
bool _receiverInited; bool _receiverInited;
VCMTiming _timing; VCMTiming _timing;
VCMTiming _dualTiming; VCMTiming _dualTiming;
@ -255,7 +277,7 @@ private:
VCMKeyRequestMode _keyRequestMode; VCMKeyRequestMode _keyRequestMode;
bool _scheduleKeyRequest; bool _scheduleKeyRequest;
CriticalSectionWrapper& _sendCritSect; // Critical section for send side CriticalSectionWrapper& _sendCritSect;
VCMGenericEncoder* _encoder; VCMGenericEncoder* _encoder;
VCMEncodedFrameCallback _encodedFrameCallback; VCMEncodedFrameCallback _encodedFrameCallback;
FrameType _nextFrameType; FrameType _nextFrameType;

View File

@ -800,11 +800,6 @@ int JitterBufferTest(CmdArgs& args)
packet.insertStartCode = false; packet.insertStartCode = false;
//printf("DONE H.264 insert start code test 2 packets\n"); //printf("DONE H.264 insert start code test 2 packets\n");
// Temporarily do this to make the rest of the test work:
timeStamp += 33*90;
seqNum += 4;
// //
// TEST statistics // TEST statistics
// //
@ -823,8 +818,35 @@ int JitterBufferTest(CmdArgs& args)
TEST(frameRate > 30); TEST(frameRate > 30);
TEST(bitRate > 10000000); TEST(bitRate > 10000000);
// Insert 3 old packets and verify that we have 3 discarded packets
packet.timestamp = timeStamp - 1000;
frameIn = jb.GetFrame(packet);
TEST(frameIn == NULL);
packet.timestamp = timeStamp - 500;
frameIn = jb.GetFrame(packet);
TEST(frameIn == NULL);
packet.timestamp = timeStamp - 100;
frameIn = jb.GetFrame(packet);
TEST(frameIn == NULL);
TEST(jb.DiscardedPackets() == 3);
jb.Flush();
// This statistic shouldn't be reset by a flush.
TEST(jb.DiscardedPackets() == 3);
//printf("DONE Statistics\n"); //printf("DONE Statistics\n");
// Temporarily do this to make the rest of the test work:
timeStamp += 33*90;
seqNum += 4;
// //
// TEST delta frame 100 packets with seqNum wrap // TEST delta frame 100 packets with seqNum wrap
// //
@ -833,7 +855,6 @@ int JitterBufferTest(CmdArgs& args)
// --------------------------------------- // ---------------------------------------
// //
// test flush
jb.Flush(); jb.Flush();
// insert first packet // insert first packet

View File

@ -140,6 +140,10 @@ public:
unsigned int& keyFrames, unsigned int& keyFrames,
unsigned int& deltaFrames) const = 0; unsigned int& deltaFrames) const = 0;
// Gets the number of packets discarded by the jitter buffer because they
// arrived too late.
virtual unsigned int GetDiscardedPackets(const int videoChannel) const = 0;
// Enables key frame request callback in ViEDecoderObserver. // Enables key frame request callback in ViEDecoderObserver.
virtual int SetKeyFrameRequestCallbackStatus(const int videoChannel, virtual int SetKeyFrameRequestCallbackStatus(const int videoChannel,
const bool enable) = 0; const bool enable) = 0;

View File

@ -515,6 +515,14 @@ WebRtc_Word32 ViEChannel::ReceiveCodecStatistics(WebRtc_UWord32& numKeyFrames,
return 0; return 0;
} }
WebRtc_UWord32 ViEChannel::DiscardedPackets() const {
WEBRTC_TRACE(webrtc::kTraceInfo,
webrtc::kTraceVideo,
ViEId(_engineId, _channelId),
"%s", __FUNCTION__);
return _vcm.DiscardedPackets();
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// WaitForKeyFrame // WaitForKeyFrame
// //

View File

@ -95,6 +95,8 @@ public:
WebRtc_Word32 ReceiveCodecStatistics(WebRtc_UWord32& numKeyFrames, WebRtc_Word32 ReceiveCodecStatistics(WebRtc_UWord32& numKeyFrames,
WebRtc_UWord32& numDeltaFrames); WebRtc_UWord32& numDeltaFrames);
WebRtc_UWord32 DiscardedPackets() const;
WebRtc_Word32 WaitForKeyFrame(bool wait); WebRtc_Word32 WaitForKeyFrame(bool wait);
WebRtc_Word32 SetSignalPacketLossStatus(bool enable, bool onlyKeyFrames); WebRtc_Word32 SetSignalPacketLossStatus(bool enable, bool onlyKeyFrames);

View File

@ -566,6 +566,25 @@ int ViECodecImpl::GetReceiveCodecStastistics(const int videoChannel,
} }
unsigned int ViECodecImpl::GetDiscardedPackets(const int videoChannel) const {
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel),
"%s(videoChannel: %d, codecType: %d)", __FUNCTION__,
videoChannel);
ViEChannelManagerScoped cs(_channelManager);
ViEChannel* vieChannel = cs.Channel(videoChannel);
if (vieChannel == NULL)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(_instanceId, videoChannel), "%s: No channel %d",
__FUNCTION__, videoChannel);
SetLastError(kViECodecInvalidChannelId);
return -1;
}
return vieChannel->DiscardedPackets();
}
// Callbacks // Callbacks
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// SetKeyFrameRequestCallbackStatus // SetKeyFrameRequestCallbackStatus

View File

@ -72,6 +72,8 @@ public:
unsigned int& keyFrames, unsigned int& keyFrames,
unsigned int& deltaFrames) const; unsigned int& deltaFrames) const;
virtual unsigned int GetDiscardedPackets(const int videoChannel) const;
// Callbacks // Callbacks
virtual int SetKeyFrameRequestCallbackStatus(const int videoChannel, virtual int SetKeyFrameRequestCallbackStatus(const int videoChannel,
const bool enable); const bool enable);