blob: 012a8acbee33072e68336d9b4d6e973cad800089 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
Henrik Kjellander2557b862015-11-18 22:00:21 +010011#include "webrtc/modules/video_coding/frame_buffer.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <string.h>
15
guoweis@webrtc.org54d072e2015-03-17 21:54:50 +000016#include "webrtc/base/checks.h"
pbos854e84c2015-11-16 16:39:06 -080017#include "webrtc/base/logging.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010018#include "webrtc/modules/video_coding/packet.h"
agalusza@google.comd818dcb2013-07-29 21:48:11 +000019
niklase@google.com470e71d2011-07-07 08:21:25 +000020namespace webrtc {
21
stefan@webrtc.orgc3d89102011-09-08 06:50:28 +000022VCMFrameBuffer::VCMFrameBuffer()
23 :
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +000024 _state(kStateEmpty),
niklase@google.com470e71d2011-07-07 08:21:25 +000025 _nackCount(0),
stefan@webrtc.orgc3d89102011-09-08 06:50:28 +000026 _latestPacketTimeMs(-1) {
niklase@google.com470e71d2011-07-07 08:21:25 +000027}
28
stefan@webrtc.orgc3d89102011-09-08 06:50:28 +000029VCMFrameBuffer::~VCMFrameBuffer() {
niklase@google.com470e71d2011-07-07 08:21:25 +000030}
31
agalusza@google.comd818dcb2013-07-29 21:48:11 +000032VCMFrameBuffer::VCMFrameBuffer(const VCMFrameBuffer& rhs)
niklase@google.com470e71d2011-07-07 08:21:25 +000033:
34VCMEncodedFrame(rhs),
35_state(rhs._state),
niklase@google.com470e71d2011-07-07 08:21:25 +000036_sessionInfo(),
37_nackCount(rhs._nackCount),
agalusza@google.comd818dcb2013-07-29 21:48:11 +000038_latestPacketTimeMs(rhs._latestPacketTimeMs) {
niklase@google.com470e71d2011-07-07 08:21:25 +000039 _sessionInfo = rhs._sessionInfo;
stefan@webrtc.orgb07aa402012-01-10 11:45:05 +000040 _sessionInfo.UpdateDataPointers(rhs._buffer, _buffer);
niklase@google.com470e71d2011-07-07 08:21:25 +000041}
42
43webrtc::FrameType
agalusza@google.comd818dcb2013-07-29 21:48:11 +000044VCMFrameBuffer::FrameType() const {
niklase@google.com470e71d2011-07-07 08:21:25 +000045 return _sessionInfo.FrameType();
46}
47
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000048int32_t
agalusza@google.comd818dcb2013-07-29 21:48:11 +000049VCMFrameBuffer::GetLowSeqNum() const {
stefan@webrtc.org076fa6e2011-12-13 07:54:56 +000050 return _sessionInfo.LowSequenceNumber();
niklase@google.com470e71d2011-07-07 08:21:25 +000051}
52
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000053int32_t
agalusza@google.comd818dcb2013-07-29 21:48:11 +000054VCMFrameBuffer::GetHighSeqNum() const {
stefan@webrtc.org076fa6e2011-12-13 07:54:56 +000055 return _sessionInfo.HighSequenceNumber();
niklase@google.com470e71d2011-07-07 08:21:25 +000056}
57
stefan@webrtc.orgffd28f92011-10-19 15:55:39 +000058int VCMFrameBuffer::PictureId() const {
59 return _sessionInfo.PictureId();
60}
61
mikhal@webrtc.orgf5ee1dc2011-12-08 19:04:47 +000062int VCMFrameBuffer::TemporalId() const {
63 return _sessionInfo.TemporalId();
64}
65
henrik.lundin@webrtc.orgeda86dc2011-12-13 14:11:06 +000066bool VCMFrameBuffer::LayerSync() const {
67 return _sessionInfo.LayerSync();
68}
69
mikhal@webrtc.orgf5ee1dc2011-12-08 19:04:47 +000070int VCMFrameBuffer::Tl0PicId() const {
71 return _sessionInfo.Tl0PicId();
72}
73
mikhal@webrtc.orgea714402011-12-12 02:29:34 +000074bool VCMFrameBuffer::NonReference() const {
75 return _sessionInfo.NonReference();
76}
77
asapersson9a4cd872015-10-23 00:27:14 -070078void 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
niklase@google.com470e71d2011-07-07 08:21:25 +000087bool
agalusza@google.comd818dcb2013-07-29 21:48:11 +000088VCMFrameBuffer::IsSessionComplete() const {
stefan@webrtc.org076fa6e2011-12-13 07:54:56 +000089 return _sessionInfo.complete();
niklase@google.com470e71d2011-07-07 08:21:25 +000090}
91
92// Insert packet
93VCMFrameBufferEnum
agalusza@google.coma7e360e2013-08-01 03:15:08 +000094VCMFrameBuffer::InsertPacket(const VCMPacket& packet,
95 int64_t timeInMs,
96 VCMDecodeErrorMode decode_error_mode,
agalusza@google.comd818dcb2013-07-29 21:48:11 +000097 const FrameData& frame_data) {
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000098 assert(!(NULL == packet.dataPtr && packet.sizeBytes > 0));
agalusza@google.comd818dcb2013-07-29 21:48:11 +000099 if (packet.dataPtr != NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 _payloadType = packet.payloadType;
101 }
102
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000103 if (kStateEmpty == _state) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000104 // First packet (empty and/or media) inserted into this frame.
105 // store some info and set some initial values.
106 _timeStamp = packet.timestamp;
wu@webrtc.org6c75c982014-04-15 17:46:33 +0000107 // We only take the ntp timestamp of the first packet of a frame.
108 ntp_time_ms_ = packet.ntp_time_ms_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000109 _codec = packet.codec;
pbos22993e12015-10-19 02:39:06 -0700110 if (packet.frameType != kEmptyFrame) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000111 // first media packet
112 SetState(kStateIncomplete);
113 }
114 }
115
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000116 uint32_t requiredSizeBytes = Length() + packet.sizeBytes +
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 (packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000118 if (requiredSizeBytes >= _size) {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000119 const uint8_t* prevBuffer = _buffer;
120 const uint32_t increments = requiredSizeBytes /
niklase@google.com470e71d2011-07-07 08:21:25 +0000121 kBufferIncStepSizeBytes +
122 (requiredSizeBytes %
123 kBufferIncStepSizeBytes > 0);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000124 const uint32_t newSize = _size +
niklase@google.com470e71d2011-07-07 08:21:25 +0000125 increments * kBufferIncStepSizeBytes;
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000126 if (newSize > kMaxJBFrameSizeBytes) {
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000127 LOG(LS_ERROR) << "Failed to insert packet due to frame being too "
128 "big.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000129 return kSizeError;
130 }
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000131 VerifyAndAllocate(newSize);
stefan@webrtc.orgb07aa402012-01-10 11:45:05 +0000132 _sessionInfo.UpdateDataPointers(prevBuffer, _buffer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 }
henrik.lundin@webrtc.org473bac82011-08-17 09:47:33 +0000134
stefan@webrtc.org3417eb42013-05-21 15:25:53 +0000135 if (packet.width > 0 && packet.height > 0) {
136 _encodedWidth = packet.width;
137 _encodedHeight = packet.height;
138 }
139
asapersson@webrtc.org37c05592015-01-28 13:58:27 +0000140 // Don't copy payload specific data for empty packets (e.g padding packets).
141 if (packet.sizeBytes > 0)
142 CopyCodecSpecific(&packet.codecSpecificHeader);
henrik.lundin@webrtc.org473bac82011-08-17 09:47:33 +0000143
stefan@webrtc.org076fa6e2011-12-13 07:54:56 +0000144 int retVal = _sessionInfo.InsertPacket(packet, _buffer,
agalusza@google.coma7e360e2013-08-01 03:15:08 +0000145 decode_error_mode,
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000146 frame_data);
147 if (retVal == -1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 return kSizeError;
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000149 } else if (retVal == -2) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 return kDuplicatePacket;
mikhal@webrtc.orgf31a47a2013-08-26 17:10:11 +0000151 } else if (retVal == -3) {
152 return kOutOfBoundsPacket;
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 }
154 // update length
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000155 _length = Length() + static_cast<uint32_t>(retVal);
niklase@google.com470e71d2011-07-07 08:21:25 +0000156
157 _latestPacketTimeMs = timeInMs;
158
guoweis@webrtc.org54d072e2015-03-17 21:54:50 +0000159 // 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) {
henrikg91d6ede2015-09-17 00:24:34 -0700166 RTC_DCHECK(!_rotation_set);
guoweis@webrtc.org54d072e2015-03-17 21:54:50 +0000167 _rotation = packet.codecSpecificHeader.rotation;
168 _rotation_set = true;
169 }
170
stefan@webrtc.org076fa6e2011-12-13 07:54:56 +0000171 if (_sessionInfo.complete()) {
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000172 SetState(kStateComplete);
mikhal@webrtc.org6b9a7f82011-11-22 22:48:20 +0000173 return kCompleteSession;
stefan@webrtc.org076fa6e2011-12-13 07:54:56 +0000174 } else if (_sessionInfo.decodable()) {
mikhal@webrtc.org6b9a7f82011-11-22 22:48:20 +0000175 SetState(kStateDecodable);
176 return kDecodableSession;
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 }
178 return kIncomplete;
179}
180
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000181int64_t
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000182VCMFrameBuffer::LatestPacketTimeMs() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 return _latestPacketTimeMs;
184}
185
mikhal@google.com0ef03772011-07-19 23:24:37 +0000186void
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000187VCMFrameBuffer::IncrementNackCount() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 _nackCount++;
189}
190
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000191int16_t
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000192VCMFrameBuffer::GetNackCount() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 return _nackCount;
194}
195
mikhal@google.com0ef03772011-07-19 23:24:37 +0000196bool
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000197VCMFrameBuffer::HaveFirstPacket() const {
stefan@webrtc.org885cd132013-04-16 09:38:26 +0000198 return _sessionInfo.HaveFirstPacket();
199}
200
201bool
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000202VCMFrameBuffer::HaveLastPacket() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 return _sessionInfo.HaveLastPacket();
204}
205
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000206int
207VCMFrameBuffer::NumPackets() const {
208 return _sessionInfo.NumPackets();
209}
210
mikhal@google.com0ef03772011-07-19 23:24:37 +0000211void
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000212VCMFrameBuffer::Reset() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 _length = 0;
214 _timeStamp = 0;
215 _sessionInfo.Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000216 _payloadType = 0;
217 _nackCount = 0;
218 _latestPacketTimeMs = -1;
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000219 _state = kStateEmpty;
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 VCMEncodedFrame::Reset();
221}
222
niklase@google.com470e71d2011-07-07 08:21:25 +0000223// Set state of frame
224void
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000225VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state) {
226 if (_state == state) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 return;
228 }
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000229 switch (state) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000230 case kStateIncomplete:
231 // we can go to this state from state kStateEmpty
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000232 assert(_state == kStateEmpty);
niklase@google.com470e71d2011-07-07 08:21:25 +0000233
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:
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000245 // Should only be set to empty through Reset().
246 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 break;
248
249 case kStateDecodable:
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 assert(_state == kStateEmpty ||
251 _state == kStateIncomplete);
252 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 }
254 _state = state;
255}
256
niklase@google.com470e71d2011-07-07 08:21:25 +0000257// Get current state of frame
258VCMFrameBufferStateEnum
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000259VCMFrameBuffer::GetState() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 return _state;
261}
262
263// Get current state of frame
264VCMFrameBufferStateEnum
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000265VCMFrameBuffer::GetState(uint32_t& timeStamp) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 timeStamp = TimeStamp();
267 return GetState();
268}
269
270bool
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000271VCMFrameBuffer::IsRetransmitted() const {
stefan@webrtc.org076fa6e2011-12-13 07:54:56 +0000272 return _sessionInfo.session_nack();
niklase@google.com470e71d2011-07-07 08:21:25 +0000273}
274
275void
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000276VCMFrameBuffer::PrepareForDecode(bool continuous) {
stefan@webrtc.orgc3d89102011-09-08 06:50:28 +0000277#ifdef INDEPENDENT_PARTITIONS
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000278 if (_codec == kVideoCodecVP8) {
stefan@webrtc.orgc3d89102011-09-08 06:50:28 +0000279 _length =
280 _sessionInfo.BuildVP8FragmentationHeader(_buffer, _length,
281 &_fragmentation);
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000282 } else {
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000283 size_t bytes_removed = _sessionInfo.MakeDecodable();
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000284 _length -= bytes_removed;
stefan@webrtc.orgc3d89102011-09-08 06:50:28 +0000285 }
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000286#else
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000287 size_t bytes_removed = _sessionInfo.MakeDecodable();
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000288 _length -= bytes_removed;
stefan@webrtc.orgc3d89102011-09-08 06:50:28 +0000289#endif
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000290 // Transfer frame information to EncodedFrame and create any codec
291 // specific information.
pbos22993e12015-10-19 02:39:06 -0700292 _frameType = _sessionInfo.FrameType();
stefan@webrtc.org4cf1a8a2013-06-27 15:20:14 +0000293 _completeFrame = _sessionInfo.complete();
294 _missingFrame = !continuous;
niklase@google.com470e71d2011-07-07 08:21:25 +0000295}
296
agalusza@google.comd818dcb2013-07-29 21:48:11 +0000297} // namespace webrtc