OLD | NEW |
| (Empty) |
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/base/checks.h" | |
17 #include "webrtc/base/logging.h" | |
18 #include "webrtc/modules/video_coding/main/source/packet.h" | |
19 | |
20 namespace webrtc { | |
21 | |
22 VCMFrameBuffer::VCMFrameBuffer() | |
23 : | |
24 _state(kStateEmpty), | |
25 _nackCount(0), | |
26 _latestPacketTimeMs(-1) { | |
27 } | |
28 | |
29 VCMFrameBuffer::~VCMFrameBuffer() { | |
30 } | |
31 | |
32 VCMFrameBuffer::VCMFrameBuffer(const VCMFrameBuffer& rhs) | |
33 : | |
34 VCMEncodedFrame(rhs), | |
35 _state(rhs._state), | |
36 _sessionInfo(), | |
37 _nackCount(rhs._nackCount), | |
38 _latestPacketTimeMs(rhs._latestPacketTimeMs) { | |
39 _sessionInfo = rhs._sessionInfo; | |
40 _sessionInfo.UpdateDataPointers(rhs._buffer, _buffer); | |
41 } | |
42 | |
43 webrtc::FrameType | |
44 VCMFrameBuffer::FrameType() const { | |
45 return _sessionInfo.FrameType(); | |
46 } | |
47 | |
48 int32_t | |
49 VCMFrameBuffer::GetLowSeqNum() const { | |
50 return _sessionInfo.LowSequenceNumber(); | |
51 } | |
52 | |
53 int32_t | |
54 VCMFrameBuffer::GetHighSeqNum() const { | |
55 return _sessionInfo.HighSequenceNumber(); | |
56 } | |
57 | |
58 int VCMFrameBuffer::PictureId() const { | |
59 return _sessionInfo.PictureId(); | |
60 } | |
61 | |
62 int VCMFrameBuffer::TemporalId() const { | |
63 return _sessionInfo.TemporalId(); | |
64 } | |
65 | |
66 bool VCMFrameBuffer::LayerSync() const { | |
67 return _sessionInfo.LayerSync(); | |
68 } | |
69 | |
70 int VCMFrameBuffer::Tl0PicId() const { | |
71 return _sessionInfo.Tl0PicId(); | |
72 } | |
73 | |
74 bool VCMFrameBuffer::NonReference() const { | |
75 return _sessionInfo.NonReference(); | |
76 } | |
77 | |
78 void VCMFrameBuffer::SetGofInfo(const GofInfoVP9& gof_info, size_t idx) { | |
79 _sessionInfo.SetGofInfo(gof_info, idx); | |
80 // TODO(asapersson): Consider adding hdr->VP9.ref_picture_id for testing. | |
81 _codecSpecificInfo.codecSpecific.VP9.temporal_idx = | |
82 gof_info.temporal_idx[idx]; | |
83 _codecSpecificInfo.codecSpecific.VP9.temporal_up_switch = | |
84 gof_info.temporal_up_switch[idx]; | |
85 } | |
86 | |
87 bool | |
88 VCMFrameBuffer::IsSessionComplete() const { | |
89 return _sessionInfo.complete(); | |
90 } | |
91 | |
92 // Insert packet | |
93 VCMFrameBufferEnum | |
94 VCMFrameBuffer::InsertPacket(const VCMPacket& packet, | |
95 int64_t timeInMs, | |
96 VCMDecodeErrorMode decode_error_mode, | |
97 const FrameData& frame_data) { | |
98 assert(!(NULL == packet.dataPtr && packet.sizeBytes > 0)); | |
99 if (packet.dataPtr != NULL) { | |
100 _payloadType = packet.payloadType; | |
101 } | |
102 | |
103 if (kStateEmpty == _state) { | |
104 // First packet (empty and/or media) inserted into this frame. | |
105 // store some info and set some initial values. | |
106 _timeStamp = packet.timestamp; | |
107 // We only take the ntp timestamp of the first packet of a frame. | |
108 ntp_time_ms_ = packet.ntp_time_ms_; | |
109 _codec = packet.codec; | |
110 if (packet.frameType != kEmptyFrame) { | |
111 // first media packet | |
112 SetState(kStateIncomplete); | |
113 } | |
114 } | |
115 | |
116 uint32_t requiredSizeBytes = Length() + packet.sizeBytes + | |
117 (packet.insertStartCode ? kH264StartCodeLengthBytes : 0); | |
118 if (requiredSizeBytes >= _size) { | |
119 const uint8_t* prevBuffer = _buffer; | |
120 const uint32_t increments = requiredSizeBytes / | |
121 kBufferIncStepSizeBytes + | |
122 (requiredSizeBytes % | |
123 kBufferIncStepSizeBytes > 0); | |
124 const uint32_t newSize = _size + | |
125 increments * kBufferIncStepSizeBytes; | |
126 if (newSize > kMaxJBFrameSizeBytes) { | |
127 LOG(LS_ERROR) << "Failed to insert packet due to frame being too " | |
128 "big."; | |
129 return kSizeError; | |
130 } | |
131 VerifyAndAllocate(newSize); | |
132 _sessionInfo.UpdateDataPointers(prevBuffer, _buffer); | |
133 } | |
134 | |
135 if (packet.width > 0 && packet.height > 0) { | |
136 _encodedWidth = packet.width; | |
137 _encodedHeight = packet.height; | |
138 } | |
139 | |
140 // Don't copy payload specific data for empty packets (e.g padding packets). | |
141 if (packet.sizeBytes > 0) | |
142 CopyCodecSpecific(&packet.codecSpecificHeader); | |
143 | |
144 int retVal = _sessionInfo.InsertPacket(packet, _buffer, | |
145 decode_error_mode, | |
146 frame_data); | |
147 if (retVal == -1) { | |
148 return kSizeError; | |
149 } else if (retVal == -2) { | |
150 return kDuplicatePacket; | |
151 } else if (retVal == -3) { | |
152 return kOutOfBoundsPacket; | |
153 } | |
154 // update length | |
155 _length = Length() + static_cast<uint32_t>(retVal); | |
156 | |
157 _latestPacketTimeMs = timeInMs; | |
158 | |
159 // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ | |
160 // ts_126114v120700p.pdf Section 7.4.5. | |
161 // The MTSI client shall add the payload bytes as defined in this clause | |
162 // onto the last RTP packet in each group of packets which make up a key | |
163 // frame (I-frame or IDR frame in H.264 (AVC), or an IRAP picture in H.265 | |
164 // (HEVC)). | |
165 if (packet.markerBit) { | |
166 RTC_DCHECK(!_rotation_set); | |
167 _rotation = packet.codecSpecificHeader.rotation; | |
168 _rotation_set = true; | |
169 } | |
170 | |
171 if (_sessionInfo.complete()) { | |
172 SetState(kStateComplete); | |
173 return kCompleteSession; | |
174 } else if (_sessionInfo.decodable()) { | |
175 SetState(kStateDecodable); | |
176 return kDecodableSession; | |
177 } | |
178 return kIncomplete; | |
179 } | |
180 | |
181 int64_t | |
182 VCMFrameBuffer::LatestPacketTimeMs() const { | |
183 return _latestPacketTimeMs; | |
184 } | |
185 | |
186 void | |
187 VCMFrameBuffer::IncrementNackCount() { | |
188 _nackCount++; | |
189 } | |
190 | |
191 int16_t | |
192 VCMFrameBuffer::GetNackCount() const { | |
193 return _nackCount; | |
194 } | |
195 | |
196 bool | |
197 VCMFrameBuffer::HaveFirstPacket() const { | |
198 return _sessionInfo.HaveFirstPacket(); | |
199 } | |
200 | |
201 bool | |
202 VCMFrameBuffer::HaveLastPacket() const { | |
203 return _sessionInfo.HaveLastPacket(); | |
204 } | |
205 | |
206 int | |
207 VCMFrameBuffer::NumPackets() const { | |
208 return _sessionInfo.NumPackets(); | |
209 } | |
210 | |
211 void | |
212 VCMFrameBuffer::Reset() { | |
213 _length = 0; | |
214 _timeStamp = 0; | |
215 _sessionInfo.Reset(); | |
216 _payloadType = 0; | |
217 _nackCount = 0; | |
218 _latestPacketTimeMs = -1; | |
219 _state = kStateEmpty; | |
220 VCMEncodedFrame::Reset(); | |
221 } | |
222 | |
223 // Set state of frame | |
224 void | |
225 VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state) { | |
226 if (_state == state) { | |
227 return; | |
228 } | |
229 switch (state) { | |
230 case kStateIncomplete: | |
231 // we can go to this state from state kStateEmpty | |
232 assert(_state == kStateEmpty); | |
233 | |
234 // Do nothing, we received a packet | |
235 break; | |
236 | |
237 case kStateComplete: | |
238 assert(_state == kStateEmpty || | |
239 _state == kStateIncomplete || | |
240 _state == kStateDecodable); | |
241 | |
242 break; | |
243 | |
244 case kStateEmpty: | |
245 // Should only be set to empty through Reset(). | |
246 assert(false); | |
247 break; | |
248 | |
249 case kStateDecodable: | |
250 assert(_state == kStateEmpty || | |
251 _state == kStateIncomplete); | |
252 break; | |
253 } | |
254 _state = state; | |
255 } | |
256 | |
257 // Get current state of frame | |
258 VCMFrameBufferStateEnum | |
259 VCMFrameBuffer::GetState() const { | |
260 return _state; | |
261 } | |
262 | |
263 // Get current state of frame | |
264 VCMFrameBufferStateEnum | |
265 VCMFrameBuffer::GetState(uint32_t& timeStamp) const { | |
266 timeStamp = TimeStamp(); | |
267 return GetState(); | |
268 } | |
269 | |
270 bool | |
271 VCMFrameBuffer::IsRetransmitted() const { | |
272 return _sessionInfo.session_nack(); | |
273 } | |
274 | |
275 void | |
276 VCMFrameBuffer::PrepareForDecode(bool continuous) { | |
277 #ifdef INDEPENDENT_PARTITIONS | |
278 if (_codec == kVideoCodecVP8) { | |
279 _length = | |
280 _sessionInfo.BuildVP8FragmentationHeader(_buffer, _length, | |
281 &_fragmentation); | |
282 } else { | |
283 size_t bytes_removed = _sessionInfo.MakeDecodable(); | |
284 _length -= bytes_removed; | |
285 } | |
286 #else | |
287 size_t bytes_removed = _sessionInfo.MakeDecodable(); | |
288 _length -= bytes_removed; | |
289 #endif | |
290 // Transfer frame information to EncodedFrame and create any codec | |
291 // specific information. | |
292 _frameType = _sessionInfo.FrameType(); | |
293 _completeFrame = _sessionInfo.complete(); | |
294 _missingFrame = !continuous; | |
295 } | |
296 | |
297 } // namespace webrtc | |
OLD | NEW |