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/source/frame_buffer.h"
12
13 #include <assert.h>
14 #include <string.h>
15
16 #include "webrtc/modules/video_coding/main/source/packet.h"
17 #include "webrtc/system_wrappers/interface/logging.h"
18
19 namespace webrtc {
20
VCMFrameBuffer()21 VCMFrameBuffer::VCMFrameBuffer()
22 :
23 _state(kStateEmpty),
24 _frameCounted(false),
25 _nackCount(0),
26 _latestPacketTimeMs(-1) {
27 }
28
~VCMFrameBuffer()29 VCMFrameBuffer::~VCMFrameBuffer() {
30 }
31
VCMFrameBuffer(const VCMFrameBuffer & rhs)32 VCMFrameBuffer::VCMFrameBuffer(const VCMFrameBuffer& rhs)
33 :
34 VCMEncodedFrame(rhs),
35 _state(rhs._state),
36 _frameCounted(rhs._frameCounted),
37 _sessionInfo(),
38 _nackCount(rhs._nackCount),
39 _latestPacketTimeMs(rhs._latestPacketTimeMs) {
40 _sessionInfo = rhs._sessionInfo;
41 _sessionInfo.UpdateDataPointers(rhs._buffer, _buffer);
42 }
43
44 webrtc::FrameType
FrameType() const45 VCMFrameBuffer::FrameType() const {
46 return _sessionInfo.FrameType();
47 }
48
49 int32_t
GetLowSeqNum() const50 VCMFrameBuffer::GetLowSeqNum() const {
51 return _sessionInfo.LowSequenceNumber();
52 }
53
54 int32_t
GetHighSeqNum() const55 VCMFrameBuffer::GetHighSeqNum() const {
56 return _sessionInfo.HighSequenceNumber();
57 }
58
PictureId() const59 int VCMFrameBuffer::PictureId() const {
60 return _sessionInfo.PictureId();
61 }
62
TemporalId() const63 int VCMFrameBuffer::TemporalId() const {
64 return _sessionInfo.TemporalId();
65 }
66
LayerSync() const67 bool VCMFrameBuffer::LayerSync() const {
68 return _sessionInfo.LayerSync();
69 }
70
Tl0PicId() const71 int VCMFrameBuffer::Tl0PicId() const {
72 return _sessionInfo.Tl0PicId();
73 }
74
NonReference() const75 bool VCMFrameBuffer::NonReference() const {
76 return _sessionInfo.NonReference();
77 }
78
79 bool
IsSessionComplete() const80 VCMFrameBuffer::IsSessionComplete() const {
81 return _sessionInfo.complete();
82 }
83
84 // Insert packet
85 VCMFrameBufferEnum
InsertPacket(const VCMPacket & packet,int64_t timeInMs,VCMDecodeErrorMode decode_error_mode,const FrameData & frame_data)86 VCMFrameBuffer::InsertPacket(const VCMPacket& packet,
87 int64_t timeInMs,
88 VCMDecodeErrorMode decode_error_mode,
89 const FrameData& frame_data) {
90 assert(!(NULL == packet.dataPtr && packet.sizeBytes > 0));
91 if (packet.dataPtr != NULL) {
92 _payloadType = packet.payloadType;
93 }
94
95 if (kStateEmpty == _state) {
96 // First packet (empty and/or media) inserted into this frame.
97 // store some info and set some initial values.
98 _timeStamp = packet.timestamp;
99 // We only take the ntp timestamp of the first packet of a frame.
100 ntp_time_ms_ = packet.ntp_time_ms_;
101 _codec = packet.codec;
102 if (packet.frameType != kFrameEmpty) {
103 // first media packet
104 SetState(kStateIncomplete);
105 }
106 }
107
108 uint32_t requiredSizeBytes = Length() + packet.sizeBytes +
109 (packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
110 if (requiredSizeBytes >= _size) {
111 const uint8_t* prevBuffer = _buffer;
112 const uint32_t increments = requiredSizeBytes /
113 kBufferIncStepSizeBytes +
114 (requiredSizeBytes %
115 kBufferIncStepSizeBytes > 0);
116 const uint32_t newSize = _size +
117 increments * kBufferIncStepSizeBytes;
118 if (newSize > kMaxJBFrameSizeBytes) {
119 LOG(LS_ERROR) << "Failed to insert packet due to frame being too "
120 "big.";
121 return kSizeError;
122 }
123 VerifyAndAllocate(newSize);
124 _sessionInfo.UpdateDataPointers(prevBuffer, _buffer);
125 }
126
127 if (packet.width > 0 && packet.height > 0) {
128 _encodedWidth = packet.width;
129 _encodedHeight = packet.height;
130 }
131
132 CopyCodecSpecific(&packet.codecSpecificHeader);
133
134 int retVal = _sessionInfo.InsertPacket(packet, _buffer,
135 decode_error_mode,
136 frame_data);
137 if (retVal == -1) {
138 return kSizeError;
139 } else if (retVal == -2) {
140 return kDuplicatePacket;
141 } else if (retVal == -3) {
142 return kOutOfBoundsPacket;
143 }
144 // update length
145 _length = Length() + static_cast<uint32_t>(retVal);
146
147 _latestPacketTimeMs = timeInMs;
148
149 if (_sessionInfo.complete()) {
150 SetState(kStateComplete);
151 return kCompleteSession;
152 } else if (_sessionInfo.decodable()) {
153 SetState(kStateDecodable);
154 return kDecodableSession;
155 }
156 return kIncomplete;
157 }
158
159 int64_t
LatestPacketTimeMs() const160 VCMFrameBuffer::LatestPacketTimeMs() const {
161 return _latestPacketTimeMs;
162 }
163
164 void
IncrementNackCount()165 VCMFrameBuffer::IncrementNackCount() {
166 _nackCount++;
167 }
168
169 int16_t
GetNackCount() const170 VCMFrameBuffer::GetNackCount() const {
171 return _nackCount;
172 }
173
174 bool
HaveFirstPacket() const175 VCMFrameBuffer::HaveFirstPacket() const {
176 return _sessionInfo.HaveFirstPacket();
177 }
178
179 bool
HaveLastPacket() const180 VCMFrameBuffer::HaveLastPacket() const {
181 return _sessionInfo.HaveLastPacket();
182 }
183
184 int
NumPackets() const185 VCMFrameBuffer::NumPackets() const {
186 return _sessionInfo.NumPackets();
187 }
188
189 void
Reset()190 VCMFrameBuffer::Reset() {
191 _length = 0;
192 _timeStamp = 0;
193 _sessionInfo.Reset();
194 _frameCounted = false;
195 _payloadType = 0;
196 _nackCount = 0;
197 _latestPacketTimeMs = -1;
198 _state = kStateEmpty;
199 VCMEncodedFrame::Reset();
200 }
201
202 // Set state of frame
203 void
SetState(VCMFrameBufferStateEnum state)204 VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state) {
205 if (_state == state) {
206 return;
207 }
208 switch (state) {
209 case kStateIncomplete:
210 // we can go to this state from state kStateEmpty
211 assert(_state == kStateEmpty);
212
213 // Do nothing, we received a packet
214 break;
215
216 case kStateComplete:
217 assert(_state == kStateEmpty ||
218 _state == kStateIncomplete ||
219 _state == kStateDecodable);
220
221 break;
222
223 case kStateEmpty:
224 // Should only be set to empty through Reset().
225 assert(false);
226 break;
227
228 case kStateDecodable:
229 assert(_state == kStateEmpty ||
230 _state == kStateIncomplete);
231 break;
232 }
233 _state = state;
234 }
235
236 // Set counted status (as counted by JB or not)
SetCountedFrame(bool frameCounted)237 void VCMFrameBuffer::SetCountedFrame(bool frameCounted) {
238 _frameCounted = frameCounted;
239 }
240
GetCountedFrame() const241 bool VCMFrameBuffer::GetCountedFrame() const {
242 return _frameCounted;
243 }
244
245 // Get current state of frame
246 VCMFrameBufferStateEnum
GetState() const247 VCMFrameBuffer::GetState() const {
248 return _state;
249 }
250
251 // Get current state of frame
252 VCMFrameBufferStateEnum
GetState(uint32_t & timeStamp) const253 VCMFrameBuffer::GetState(uint32_t& timeStamp) const {
254 timeStamp = TimeStamp();
255 return GetState();
256 }
257
258 bool
IsRetransmitted() const259 VCMFrameBuffer::IsRetransmitted() const {
260 return _sessionInfo.session_nack();
261 }
262
263 void
PrepareForDecode(bool continuous)264 VCMFrameBuffer::PrepareForDecode(bool continuous) {
265 #ifdef INDEPENDENT_PARTITIONS
266 if (_codec == kVideoCodecVP8) {
267 _length =
268 _sessionInfo.BuildVP8FragmentationHeader(_buffer, _length,
269 &_fragmentation);
270 } else {
271 int bytes_removed = _sessionInfo.MakeDecodable();
272 _length -= bytes_removed;
273 }
274 #else
275 int bytes_removed = _sessionInfo.MakeDecodable();
276 _length -= bytes_removed;
277 #endif
278 // Transfer frame information to EncodedFrame and create any codec
279 // specific information.
280 _frameType = ConvertFrameType(_sessionInfo.FrameType());
281 _completeFrame = _sessionInfo.complete();
282 _missingFrame = !continuous;
283 }
284
285 } // namespace webrtc
286