Fixes two bugs when decoding with packet losses.

Disable _missingFrame bit since we can't set it correctly with FEC.

No longer return more than one decoded frame per Decode() call.
This is a work-around for a bug where the frame info map was popped more often than items were added to the map.

BUG=
TEST=

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@722 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2011-10-10 14:17:46 +00:00
parent ed081a99a9
commit 06887aebae
5 changed files with 40 additions and 20 deletions

View File

@ -16,6 +16,7 @@
// Define return values // Define return values
#define WEBRTC_VIDEO_CODEC_REQUEST_SLI 2 #define WEBRTC_VIDEO_CODEC_REQUEST_SLI 2
#define WEBRTC_VIDEO_CODEC_NO_OUTPUT 1
#define WEBRTC_VIDEO_CODEC_OK 0 #define WEBRTC_VIDEO_CODEC_OK 0
#define WEBRTC_VIDEO_CODEC_ERROR -1 #define WEBRTC_VIDEO_CODEC_ERROR -1
#define WEBRTC_VIDEO_CODEC_LEVEL_EXCEEDED -2 #define WEBRTC_VIDEO_CODEC_LEVEL_EXCEEDED -2

View File

@ -835,9 +835,6 @@ VP8Decoder::Decode(const EncodedImage& inputImage,
return WEBRTC_VIDEO_CODEC_ERROR; return WEBRTC_VIDEO_CODEC_ERROR;
} }
img = vpx_codec_get_frame(_decoder, &iter); img = vpx_codec_get_frame(_decoder, &iter);
ret = ReturnFrame(img, inputImage._timeStamp);
if (ret != 0)
return ret;
iter = NULL; iter = NULL;
} }
@ -966,7 +963,7 @@ VP8Decoder::ReturnFrame(const vpx_image_t* img, WebRtc_UWord32 timeStamp)
if (img == NULL) if (img == NULL)
{ {
// Decoder OK and NULL image => No show frame // Decoder OK and NULL image => No show frame
return WEBRTC_VIDEO_CODEC_OK; return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
} }
// Allocate memory for decoded image // Allocate memory for decoded image

View File

@ -343,7 +343,10 @@ VCMFrameBuffer::RestructureFrameInformation()
PrepareForDecode(); PrepareForDecode();
_frameType = ConvertFrameType(_sessionInfo.FrameType()); _frameType = ConvertFrameType(_sessionInfo.FrameType());
_completeFrame = _sessionInfo.IsSessionComplete(); _completeFrame = _sessionInfo.IsSessionComplete();
_missingFrame = _sessionInfo.PreviousFrameLoss(); // TODO(holmer): This bit is disabled for now since we can't tell whether
// we have had a full frame loss or if we've just lost an FEC/empty packet.
// _missingFrame = _sessionInfo.PreviousFrameLoss();
_missingFrame = false;
} }
WebRtc_Word32 WebRtc_Word32

View File

@ -30,7 +30,8 @@ VCMDecodedFrameCallback::~VCMDecodedFrameCallback()
delete &_critSect; delete &_critSect;
} }
void VCMDecodedFrameCallback::SetUserReceiveCallback(VCMReceiveCallback* receiveCallback) void VCMDecodedFrameCallback::SetUserReceiveCallback(
VCMReceiveCallback* receiveCallback)
{ {
CriticalSectionScoped cs(_critSect); CriticalSectionScoped cs(_critSect);
_receiveCallback = receiveCallback; _receiveCallback = receiveCallback;
@ -38,18 +39,27 @@ void VCMDecodedFrameCallback::SetUserReceiveCallback(VCMReceiveCallback* receive
WebRtc_Word32 VCMDecodedFrameCallback::Decoded(RawImage& decodedImage) WebRtc_Word32 VCMDecodedFrameCallback::Decoded(RawImage& decodedImage)
{ {
// TODO(holmer): We should improve this so that we can handle multiple
// callbacks from one call to Decode().
CriticalSectionScoped cs(_critSect); CriticalSectionScoped cs(_critSect);
VCMFrameInformation* frameInfo = static_cast<VCMFrameInformation*>(_timestampMap.Pop(decodedImage._timeStamp)); VCMFrameInformation* frameInfo = static_cast<VCMFrameInformation*>(
_timestampMap.Pop(decodedImage._timeStamp));
if (frameInfo == NULL) if (frameInfo == NULL)
{ {
// The map should never be empty or full if this callback is called.
return WEBRTC_VIDEO_CODEC_ERROR; return WEBRTC_VIDEO_CODEC_ERROR;
} }
WebRtc_Word32 ret = _timing.StopDecodeTimer(decodedImage._timeStamp, frameInfo->decodeStartTimeMs, VCMTickTime::MillisecondTimestamp()); _timing.StopDecodeTimer(
decodedImage._timeStamp,
frameInfo->decodeStartTimeMs,
VCMTickTime::MillisecondTimestamp());
if (_receiveCallback != NULL) if (_receiveCallback != NULL)
{ {
_frame.Swap(decodedImage._buffer, decodedImage._length, decodedImage._size); _frame.Swap(decodedImage._buffer,
decodedImage._length,
decodedImage._size);
_frame.SetWidth(decodedImage._width); _frame.SetWidth(decodedImage._width);
_frame.SetHeight(decodedImage._height); _frame.SetHeight(decodedImage._height);
_frame.SetTimeStamp(decodedImage._timeStamp); _frame.SetTimeStamp(decodedImage._timeStamp);
@ -58,18 +68,18 @@ WebRtc_Word32 VCMDecodedFrameCallback::Decoded(RawImage& decodedImage)
WebRtc_Word32 callbackReturn = _receiveCallback->FrameToRender(_frame); WebRtc_Word32 callbackReturn = _receiveCallback->FrameToRender(_frame);
if (callbackReturn < 0) if (callbackReturn < 0)
{ {
return callbackReturn; WEBRTC_TRACE(webrtc::kTraceDebug,
webrtc::kTraceVideoCoding,
-1,
"Render callback returned error: %d", callbackReturn);
} }
} }
if (ret < 0)
{
return ret;
}
return WEBRTC_VIDEO_CODEC_OK; return WEBRTC_VIDEO_CODEC_OK;
} }
WebRtc_Word32 WebRtc_Word32
VCMDecodedFrameCallback::ReceivedDecodedReferenceFrame(const WebRtc_UWord64 pictureId) VCMDecodedFrameCallback::ReceivedDecodedReferenceFrame(
const WebRtc_UWord64 pictureId)
{ {
CriticalSectionScoped cs(_critSect); CriticalSectionScoped cs(_critSect);
if (_receiveCallback != NULL) if (_receiveCallback != NULL)
@ -125,7 +135,9 @@ VCMGenericDecoder::~VCMGenericDecoder()
{ {
} }
WebRtc_Word32 VCMGenericDecoder::InitDecode(const VideoCodec* settings, WebRtc_Word32 numberOfCores, bool requireKeyFrame) WebRtc_Word32 VCMGenericDecoder::InitDecode(const VideoCodec* settings,
WebRtc_Word32 numberOfCores,
bool requireKeyFrame)
{ {
_requireKeyFrame = requireKeyFrame; _requireKeyFrame = requireKeyFrame;
_keyFrameDecoded = false; _keyFrameDecoded = false;
@ -149,9 +161,10 @@ WebRtc_Word32 VCMGenericDecoder::Decode(const VCMEncodedFrame& frame)
_frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs(); _frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs();
_callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]); _callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]);
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_id), WEBRTC_TRACE(webrtc::kTraceDebug,
"Decoding timestamp %u", webrtc::kTraceVideoCoding,
frame.TimeStamp()); VCMId(_id),
"Decoding timestamp %u", frame.TimeStamp());
_nextFrameInfoIdx = (_nextFrameInfoIdx + 1) % kDecoderFrameMemoryLength; _nextFrameInfoIdx = (_nextFrameInfoIdx + 1) % kDecoderFrameMemoryLength;
@ -167,6 +180,12 @@ WebRtc_Word32 VCMGenericDecoder::Decode(const VCMEncodedFrame& frame)
_callback->Pop(frame.TimeStamp()); _callback->Pop(frame.TimeStamp());
return ret; return ret;
} }
else if (ret == WEBRTC_VIDEO_CODEC_NO_OUTPUT ||
ret == WEBRTC_VIDEO_CODEC_REQUEST_SLI)
{
// No output
_callback->Pop(frame.TimeStamp());
}
// Update the key frame decoded variable so that we know whether or not we've decoded a key frame since reset. // Update the key frame decoded variable so that we know whether or not we've decoded a key frame since reset.
_keyFrameDecoded = (frame.FrameType() == kVideoFrameKey || frame.FrameType() == kVideoFrameGolden); _keyFrameDecoded = (frame.FrameType() == kVideoFrameKey || frame.FrameType() == kVideoFrameGolden);
return ret; return ret;

View File

@ -199,7 +199,7 @@ VCMTiming::StopDecodeTimer(WebRtc_UWord32 timeStamp,
{ {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId), WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
"Codec timer error: %d", timeDiffMs); "Codec timer error: %d", timeDiffMs);
return timeDiffMs; assert(false);
} }
if (_master) if (_master)