henrik.lundin@webrtc.org 7d8c72e2db Re-implement dependency injection of TickTime into VCM and tests
This change basicly re-enables the change of r1220, which was
reverted in r1235 due to Clang issues.

The difference from r1220 is that the TickTimeInterface was
renamed to TickTimeClass, and no longer inherits from TickTime.

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1267 4adac7df-926f-26a2-2b94-8c16560cd09d
2011-12-21 15:24:01 +00:00

227 lines
6.6 KiB
C++

/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "video_coding.h"
#include "trace.h"
#include "generic_decoder.h"
#include "internal_defines.h"
#include "tick_time_base.h"
namespace webrtc {
VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming& timing,
TickTimeBase* clock)
:
_critSect(CriticalSectionWrapper::CreateCriticalSection()),
_clock(clock),
_receiveCallback(NULL),
_timing(timing),
_timestampMap(kDecoderFrameMemoryLength)
{
}
VCMDecodedFrameCallback::~VCMDecodedFrameCallback()
{
delete _critSect;
}
void VCMDecodedFrameCallback::SetUserReceiveCallback(
VCMReceiveCallback* receiveCallback)
{
CriticalSectionScoped cs(_critSect);
_receiveCallback = receiveCallback;
}
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);
VCMFrameInformation* frameInfo = static_cast<VCMFrameInformation*>(
_timestampMap.Pop(decodedImage._timeStamp));
if (frameInfo == NULL)
{
// The map should never be empty or full if this callback is called.
return WEBRTC_VIDEO_CODEC_ERROR;
}
_timing.StopDecodeTimer(
decodedImage._timeStamp,
frameInfo->decodeStartTimeMs,
_clock->MillisecondTimestamp());
if (_receiveCallback != NULL)
{
_frame.Swap(decodedImage._buffer,
decodedImage._length,
decodedImage._size);
_frame.SetWidth(decodedImage._width);
_frame.SetHeight(decodedImage._height);
_frame.SetTimeStamp(decodedImage._timeStamp);
_frame.SetRenderTime(frameInfo->renderTimeMs);
// Convert raw image to video frame
WebRtc_Word32 callbackReturn = _receiveCallback->FrameToRender(_frame);
if (callbackReturn < 0)
{
WEBRTC_TRACE(webrtc::kTraceDebug,
webrtc::kTraceVideoCoding,
-1,
"Render callback returned error: %d", callbackReturn);
}
}
return WEBRTC_VIDEO_CODEC_OK;
}
WebRtc_Word32
VCMDecodedFrameCallback::ReceivedDecodedReferenceFrame(
const WebRtc_UWord64 pictureId)
{
CriticalSectionScoped cs(_critSect);
if (_receiveCallback != NULL)
{
return _receiveCallback->ReceivedDecodedReferenceFrame(pictureId);
}
return -1;
}
WebRtc_Word32
VCMDecodedFrameCallback::ReceivedDecodedFrame(const WebRtc_UWord64 pictureId)
{
_lastReceivedPictureID = pictureId;
return 0;
}
WebRtc_UWord64 VCMDecodedFrameCallback::LastReceivedPictureID() const
{
return _lastReceivedPictureID;
}
WebRtc_Word32 VCMDecodedFrameCallback::Map(WebRtc_UWord32 timestamp, VCMFrameInformation* frameInfo)
{
CriticalSectionScoped cs(_critSect);
return _timestampMap.Add(timestamp, frameInfo);
}
WebRtc_Word32 VCMDecodedFrameCallback::Pop(WebRtc_UWord32 timestamp)
{
CriticalSectionScoped cs(_critSect);
if (_timestampMap.Pop(timestamp) == NULL)
{
return VCM_GENERAL_ERROR;
}
return VCM_OK;
}
VCMGenericDecoder::VCMGenericDecoder(VideoDecoder& decoder, WebRtc_Word32 id, bool isExternal)
:
_id(id),
_callback(NULL),
_frameInfos(),
_nextFrameInfoIdx(0),
_decoder(decoder),
_codecType(kVideoCodecUnknown),
_isExternal(isExternal),
_requireKeyFrame(false),
_keyFrameDecoded(false)
{
}
VCMGenericDecoder::~VCMGenericDecoder()
{
}
WebRtc_Word32 VCMGenericDecoder::InitDecode(const VideoCodec* settings,
WebRtc_Word32 numberOfCores,
bool requireKeyFrame)
{
_requireKeyFrame = requireKeyFrame;
_keyFrameDecoded = false;
_codecType = settings->codecType;
return _decoder.InitDecode(settings, numberOfCores);
}
WebRtc_Word32 VCMGenericDecoder::Decode(const VCMEncodedFrame& frame,
int64_t nowMs)
{
if (_requireKeyFrame &&
!_keyFrameDecoded &&
frame.FrameType() != kVideoFrameKey &&
frame.FrameType() != kVideoFrameGolden)
{
// Require key frame is enabled, meaning that one key frame must be decoded
// before we can decode delta frames.
return VCM_CODEC_ERROR;
}
_frameInfos[_nextFrameInfoIdx].decodeStartTimeMs = nowMs;
_frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs();
_callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]);
WEBRTC_TRACE(webrtc::kTraceDebug,
webrtc::kTraceVideoCoding,
VCMId(_id),
"Decoding timestamp %u", frame.TimeStamp());
_nextFrameInfoIdx = (_nextFrameInfoIdx + 1) % kDecoderFrameMemoryLength;
WebRtc_Word32 ret = _decoder.Decode(frame.EncodedImage(),
frame.MissingFrame(),
frame.FragmentationHeader(),
frame.CodecSpecific(),
frame.RenderTimeMs());
if (ret < WEBRTC_VIDEO_CODEC_OK)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), "Decoder error: %d\n", ret);
_callback->Pop(frame.TimeStamp());
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.
_keyFrameDecoded = (frame.FrameType() == kVideoFrameKey || frame.FrameType() == kVideoFrameGolden);
return ret;
}
WebRtc_Word32
VCMGenericDecoder::Release()
{
_keyFrameDecoded = false;
return _decoder.Release();
}
WebRtc_Word32 VCMGenericDecoder::Reset()
{
_keyFrameDecoded = false;
return _decoder.Reset();
}
WebRtc_Word32 VCMGenericDecoder::SetCodecConfigParameters(const WebRtc_UWord8* buffer, WebRtc_Word32 size)
{
return _decoder.SetCodecConfigParameters(buffer, size);
}
WebRtc_Word32 VCMGenericDecoder::RegisterDecodeCompleteCallback(VCMDecodedFrameCallback* callback)
{
_callback = callback;
return _decoder.RegisterDecodeCompleteCallback(callback);
}
bool VCMGenericDecoder::External() const
{
return _isExternal;
}
} // namespace