1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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.
9 */
10
11#include "webrtc/modules/video_coding/main/interface/video_coding.h"
12#include "webrtc/modules/video_coding/main/source/generic_decoder.h"
13#include "webrtc/modules/video_coding/main/source/internal_defines.h"
14#include "webrtc/system_wrappers/interface/clock.h"
15#include "webrtc/system_wrappers/interface/logging.h"
16
17namespace webrtc {
18
19VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming& timing,
20                                                 Clock* clock)
21:
22_critSect(CriticalSectionWrapper::CreateCriticalSection()),
23_clock(clock),
24_receiveCallback(NULL),
25_timing(timing),
26_timestampMap(kDecoderFrameMemoryLength),
27_lastReceivedPictureID(0)
28{
29}
30
31VCMDecodedFrameCallback::~VCMDecodedFrameCallback()
32{
33    delete _critSect;
34}
35
36void VCMDecodedFrameCallback::SetUserReceiveCallback(
37    VCMReceiveCallback* receiveCallback)
38{
39    CriticalSectionScoped cs(_critSect);
40    _receiveCallback = receiveCallback;
41}
42
43VCMReceiveCallback* VCMDecodedFrameCallback::UserReceiveCallback()
44{
45    CriticalSectionScoped cs(_critSect);
46    return _receiveCallback;
47}
48
49int32_t VCMDecodedFrameCallback::Decoded(I420VideoFrame& decodedImage)
50{
51    // TODO(holmer): We should improve this so that we can handle multiple
52    // callbacks from one call to Decode().
53    VCMFrameInformation* frameInfo;
54    VCMReceiveCallback* callback;
55    {
56        CriticalSectionScoped cs(_critSect);
57        frameInfo = static_cast<VCMFrameInformation*>(
58            _timestampMap.Pop(decodedImage.timestamp()));
59        callback = _receiveCallback;
60    }
61
62    if (frameInfo == NULL) {
63      LOG(LS_WARNING) << "Too many frames backed up in the decoder, dropping "
64                         "this one.";
65      return WEBRTC_VIDEO_CODEC_OK;
66    }
67
68    _timing.StopDecodeTimer(
69        decodedImage.timestamp(),
70        frameInfo->decodeStartTimeMs,
71        _clock->TimeInMilliseconds());
72
73    if (callback != NULL)
74    {
75        decodedImage.set_render_time_ms(frameInfo->renderTimeMs);
76        callback->FrameToRender(decodedImage);
77    }
78    return WEBRTC_VIDEO_CODEC_OK;
79}
80
81int32_t
82VCMDecodedFrameCallback::ReceivedDecodedReferenceFrame(
83    const uint64_t pictureId)
84{
85    CriticalSectionScoped cs(_critSect);
86    if (_receiveCallback != NULL)
87    {
88        return _receiveCallback->ReceivedDecodedReferenceFrame(pictureId);
89    }
90    return -1;
91}
92
93int32_t
94VCMDecodedFrameCallback::ReceivedDecodedFrame(const uint64_t pictureId)
95{
96    _lastReceivedPictureID = pictureId;
97    return 0;
98}
99
100uint64_t VCMDecodedFrameCallback::LastReceivedPictureID() const
101{
102    return _lastReceivedPictureID;
103}
104
105int32_t VCMDecodedFrameCallback::Map(uint32_t timestamp, VCMFrameInformation* frameInfo)
106{
107    CriticalSectionScoped cs(_critSect);
108    return _timestampMap.Add(timestamp, frameInfo);
109}
110
111int32_t VCMDecodedFrameCallback::Pop(uint32_t timestamp)
112{
113    CriticalSectionScoped cs(_critSect);
114    if (_timestampMap.Pop(timestamp) == NULL)
115    {
116        return VCM_GENERAL_ERROR;
117    }
118    return VCM_OK;
119}
120
121VCMGenericDecoder::VCMGenericDecoder(VideoDecoder& decoder, bool isExternal)
122:
123_callback(NULL),
124_frameInfos(),
125_nextFrameInfoIdx(0),
126_decoder(decoder),
127_codecType(kVideoCodecUnknown),
128_isExternal(isExternal),
129_keyFrameDecoded(false)
130{
131}
132
133VCMGenericDecoder::~VCMGenericDecoder()
134{
135}
136
137int32_t VCMGenericDecoder::InitDecode(const VideoCodec* settings,
138                                      int32_t numberOfCores)
139{
140    _codecType = settings->codecType;
141
142    return _decoder.InitDecode(settings, numberOfCores);
143}
144
145int32_t VCMGenericDecoder::Decode(const VCMEncodedFrame& frame,
146                                        int64_t nowMs)
147{
148    _frameInfos[_nextFrameInfoIdx].decodeStartTimeMs = nowMs;
149    _frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs();
150    _callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]);
151
152    _nextFrameInfoIdx = (_nextFrameInfoIdx + 1) % kDecoderFrameMemoryLength;
153    int32_t ret = _decoder.Decode(frame.EncodedImage(),
154                                        frame.MissingFrame(),
155                                        frame.FragmentationHeader(),
156                                        frame.CodecSpecific(),
157                                        frame.RenderTimeMs());
158
159    if (ret < WEBRTC_VIDEO_CODEC_OK)
160    {
161        LOG(LS_WARNING) << "Failed to decode frame with timestamp "
162                        << frame.TimeStamp() << ", error code: " << ret;
163        _callback->Pop(frame.TimeStamp());
164        return ret;
165    }
166    else if (ret == WEBRTC_VIDEO_CODEC_NO_OUTPUT ||
167             ret == WEBRTC_VIDEO_CODEC_REQUEST_SLI)
168    {
169        // No output
170        _callback->Pop(frame.TimeStamp());
171    }
172    return ret;
173}
174
175int32_t
176VCMGenericDecoder::Release()
177{
178    return _decoder.Release();
179}
180
181int32_t VCMGenericDecoder::Reset()
182{
183    return _decoder.Reset();
184}
185
186int32_t VCMGenericDecoder::SetCodecConfigParameters(const uint8_t* buffer, int32_t size)
187{
188    return _decoder.SetCodecConfigParameters(buffer, size);
189}
190
191int32_t VCMGenericDecoder::RegisterDecodeCompleteCallback(VCMDecodedFrameCallback* callback)
192{
193    _callback = callback;
194    return _decoder.RegisterDecodeCompleteCallback(callback);
195}
196
197bool VCMGenericDecoder::External() const
198{
199    return _isExternal;
200}
201
202}  // namespace
203