• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "modules/rtp_rtcp/source/rtp_utility.h"
12 
13 #include <assert.h>
14 #include <stddef.h>
15 
16 #include <string>
17 
18 #include "api/array_view.h"
19 #include "api/video/video_content_type.h"
20 #include "api/video/video_rotation.h"
21 #include "api/video/video_timing.h"
22 #include "modules/rtp_rtcp/include/rtp_cvo.h"
23 #include "modules/rtp_rtcp/source/byte_io.h"
24 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
25 #include "modules/video_coding/codecs/interface/common_constants.h"
26 #include "rtc_base/checks.h"
27 #include "rtc_base/logging.h"
28 
29 namespace webrtc {
30 
31 namespace RtpUtility {
32 
33 enum {
34   kRtcpExpectedVersion = 2,
35   kRtcpMinHeaderLength = 4,
36   kRtcpMinParseLength = 8,
37 
38   kRtpExpectedVersion = 2,
39   kRtpMinParseLength = 12
40 };
41 
42 /*
43  * Misc utility routines
44  */
45 
Word32Align(size_t size)46 size_t Word32Align(size_t size) {
47   uint32_t remainder = size % 4;
48   if (remainder != 0)
49     return size + 4 - remainder;
50   return size;
51 }
52 
RtpHeaderParser(const uint8_t * rtpData,const size_t rtpDataLength)53 RtpHeaderParser::RtpHeaderParser(const uint8_t* rtpData,
54                                  const size_t rtpDataLength)
55     : _ptrRTPDataBegin(rtpData),
56       _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {}
57 
~RtpHeaderParser()58 RtpHeaderParser::~RtpHeaderParser() {}
59 
RTCP() const60 bool RtpHeaderParser::RTCP() const {
61   // 72 to 76 is reserved for RTP
62   // 77 to 79 is not reserver but  they are not assigned we will block them
63   // for RTCP 200 SR  == marker bit + 72
64   // for RTCP 204 APP == marker bit + 76
65   /*
66    *       RTCP
67    *
68    * FIR      full INTRA-frame request             192     [RFC2032]   supported
69    * NACK     negative acknowledgement             193     [RFC2032]
70    * IJ       Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toff
71    * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
72    * SR       sender report                        200     [RFC3551]   supported
73    * RR       receiver report                      201     [RFC3551]   supported
74    * SDES     source description                   202     [RFC3551]   supported
75    * BYE      goodbye                              203     [RFC3551]   supported
76    * APP      application-defined                  204     [RFC3551]   ignored
77    * RTPFB    Transport layer FB message           205     [RFC4585]   supported
78    * PSFB     Payload-specific FB message          206     [RFC4585]   supported
79    * XR       extended report                      207     [RFC3611]   supported
80    */
81 
82   /* 205       RFC 5104
83    * FMT 1      NACK       supported
84    * FMT 2      reserved
85    * FMT 3      TMMBR      supported
86    * FMT 4      TMMBN      supported
87    */
88 
89   /* 206      RFC 5104
90    * FMT 1:     Picture Loss Indication (PLI)                      supported
91    * FMT 2:     Slice Lost Indication (SLI)
92    * FMT 3:     Reference Picture Selection Indication (RPSI)
93    * FMT 4:     Full Intra Request (FIR) Command                   supported
94    * FMT 5:     Temporal-Spatial Trade-off Request (TSTR)
95    * FMT 6:     Temporal-Spatial Trade-off Notification (TSTN)
96    * FMT 7:     Video Back Channel Message (VBCM)
97    * FMT 15:    Application layer FB message
98    */
99 
100   const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
101   if (length < kRtcpMinHeaderLength) {
102     return false;
103   }
104 
105   const uint8_t V = _ptrRTPDataBegin[0] >> 6;
106   if (V != kRtcpExpectedVersion) {
107     return false;
108   }
109 
110   const uint8_t payloadType = _ptrRTPDataBegin[1];
111   switch (payloadType) {
112     case 192:
113       return true;
114     case 193:
115       // not supported
116       // pass through and check for a potential RTP packet
117       return false;
118     case 195:
119     case 200:
120     case 201:
121     case 202:
122     case 203:
123     case 204:
124     case 205:
125     case 206:
126     case 207:
127       return true;
128     default:
129       return false;
130   }
131 }
132 
ParseRtcp(RTPHeader * header) const133 bool RtpHeaderParser::ParseRtcp(RTPHeader* header) const {
134   assert(header != NULL);
135 
136   const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
137   if (length < kRtcpMinParseLength) {
138     return false;
139   }
140 
141   const uint8_t V = _ptrRTPDataBegin[0] >> 6;
142   if (V != kRtcpExpectedVersion) {
143     return false;
144   }
145 
146   const uint8_t PT = _ptrRTPDataBegin[1];
147   const size_t len = (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3];
148   const uint8_t* ptr = &_ptrRTPDataBegin[4];
149 
150   uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
151   ptr += 4;
152 
153   header->payloadType = PT;
154   header->ssrc = SSRC;
155   header->headerLength = 4 + (len << 2);
156 
157   return true;
158 }
159 
Parse(RTPHeader * header,const RtpHeaderExtensionMap * ptrExtensionMap,bool header_only) const160 bool RtpHeaderParser::Parse(RTPHeader* header,
161                             const RtpHeaderExtensionMap* ptrExtensionMap,
162                             bool header_only) const {
163   const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
164   if (length < kRtpMinParseLength) {
165     return false;
166   }
167 
168   // Version
169   const uint8_t V = _ptrRTPDataBegin[0] >> 6;
170   // Padding
171   const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
172   // eXtension
173   const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
174   const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f;
175   const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;
176 
177   const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f;
178 
179   const uint16_t sequenceNumber =
180       (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3];
181 
182   const uint8_t* ptr = &_ptrRTPDataBegin[4];
183 
184   uint32_t RTPTimestamp = ByteReader<uint32_t>::ReadBigEndian(ptr);
185   ptr += 4;
186 
187   uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
188   ptr += 4;
189 
190   if (V != kRtpExpectedVersion) {
191     return false;
192   }
193 
194   const size_t CSRCocts = CC * 4;
195 
196   if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
197     return false;
198   }
199 
200   header->markerBit = M;
201   header->payloadType = PT;
202   header->sequenceNumber = sequenceNumber;
203   header->timestamp = RTPTimestamp;
204   header->ssrc = SSRC;
205   header->numCSRCs = CC;
206   if (!P || header_only) {
207     header->paddingLength = 0;
208   }
209 
210   for (uint8_t i = 0; i < CC; ++i) {
211     uint32_t CSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
212     ptr += 4;
213     header->arrOfCSRCs[i] = CSRC;
214   }
215 
216   header->headerLength = 12 + CSRCocts;
217 
218   // If in effect, MAY be omitted for those packets for which the offset
219   // is zero.
220   header->extension.hasTransmissionTimeOffset = false;
221   header->extension.transmissionTimeOffset = 0;
222 
223   // May not be present in packet.
224   header->extension.hasAbsoluteSendTime = false;
225   header->extension.absoluteSendTime = 0;
226 
227   // May not be present in packet.
228   header->extension.hasAudioLevel = false;
229   header->extension.voiceActivity = false;
230   header->extension.audioLevel = 0;
231 
232   // May not be present in packet.
233   header->extension.hasVideoRotation = false;
234   header->extension.videoRotation = kVideoRotation_0;
235 
236   // May not be present in packet.
237   header->extension.playout_delay.min_ms = -1;
238   header->extension.playout_delay.max_ms = -1;
239 
240   // May not be present in packet.
241   header->extension.hasVideoContentType = false;
242   header->extension.videoContentType = VideoContentType::UNSPECIFIED;
243 
244   header->extension.has_video_timing = false;
245   header->extension.video_timing = {0u, 0u, 0u, 0u, 0u, 0u, false};
246 
247   if (X) {
248     /* RTP header extension, RFC 3550.
249      0                   1                   2                   3
250      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
251     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
252     |      defined by profile       |           length              |
253     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
254     |                        header extension                       |
255     |                             ....                              |
256     */
257     const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
258     if (remain < 4) {
259       return false;
260     }
261 
262     header->headerLength += 4;
263 
264     uint16_t definedByProfile = ByteReader<uint16_t>::ReadBigEndian(ptr);
265     ptr += 2;
266 
267     // in 32 bit words
268     size_t XLen = ByteReader<uint16_t>::ReadBigEndian(ptr);
269     ptr += 2;
270     XLen *= 4;  // in bytes
271 
272     if (static_cast<size_t>(remain) < (4 + XLen)) {
273       return false;
274     }
275     static constexpr uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
276     if (definedByProfile == kRtpOneByteHeaderExtensionId) {
277       const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen;
278       ParseOneByteExtensionHeader(header, ptrExtensionMap,
279                                   ptrRTPDataExtensionEnd, ptr);
280     }
281     header->headerLength += XLen;
282   }
283   if (header->headerLength > static_cast<size_t>(length))
284     return false;
285 
286   if (P && !header_only) {
287     // Packet has padding.
288     if (header->headerLength != static_cast<size_t>(length)) {
289       // Packet is not header only. We can parse padding length now.
290       header->paddingLength = *(_ptrRTPDataEnd - 1);
291     } else {
292       RTC_LOG(LS_WARNING) << "Cannot parse padding length.";
293       // Packet is header only. We have no clue of the padding length.
294       return false;
295     }
296   }
297 
298   if (header->headerLength + header->paddingLength >
299       static_cast<size_t>(length))
300     return false;
301   return true;
302 }
303 
ParseOneByteExtensionHeader(RTPHeader * header,const RtpHeaderExtensionMap * ptrExtensionMap,const uint8_t * ptrRTPDataExtensionEnd,const uint8_t * ptr) const304 void RtpHeaderParser::ParseOneByteExtensionHeader(
305     RTPHeader* header,
306     const RtpHeaderExtensionMap* ptrExtensionMap,
307     const uint8_t* ptrRTPDataExtensionEnd,
308     const uint8_t* ptr) const {
309   if (!ptrExtensionMap) {
310     return;
311   }
312 
313   while (ptrRTPDataExtensionEnd - ptr > 0) {
314     //  0
315     //  0 1 2 3 4 5 6 7
316     // +-+-+-+-+-+-+-+-+
317     // |  ID   |  len  |
318     // +-+-+-+-+-+-+-+-+
319 
320     // Note that 'len' is the header extension element length, which is the
321     // number of bytes - 1.
322     const int id = (*ptr & 0xf0) >> 4;
323     const int len = (*ptr & 0x0f);
324     ptr++;
325 
326     if (id == 0) {
327       // Padding byte, skip ignoring len.
328       continue;
329     }
330 
331     if (id == 15) {
332       RTC_LOG(LS_VERBOSE)
333           << "RTP extension header 15 encountered. Terminate parsing.";
334       return;
335     }
336 
337     if (ptrRTPDataExtensionEnd - ptr < (len + 1)) {
338       RTC_LOG(LS_WARNING) << "Incorrect one-byte extension len: " << (len + 1)
339                           << ", bytes left in buffer: "
340                           << (ptrRTPDataExtensionEnd - ptr);
341       return;
342     }
343 
344     RTPExtensionType type = ptrExtensionMap->GetType(id);
345     if (type == RtpHeaderExtensionMap::kInvalidType) {
346       // If we encounter an unknown extension, just skip over it.
347       RTC_LOG(LS_WARNING) << "Failed to find extension id: " << id;
348     } else {
349       switch (type) {
350         case kRtpExtensionTransmissionTimeOffset: {
351           if (len != 2) {
352             RTC_LOG(LS_WARNING)
353                 << "Incorrect transmission time offset len: " << len;
354             return;
355           }
356           //  0                   1                   2                   3
357           //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
358           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359           // |  ID   | len=2 |              transmission offset              |
360           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
361 
362           header->extension.transmissionTimeOffset =
363               ByteReader<int32_t, 3>::ReadBigEndian(ptr);
364           header->extension.hasTransmissionTimeOffset = true;
365           break;
366         }
367         case kRtpExtensionAudioLevel: {
368           if (len != 0) {
369             RTC_LOG(LS_WARNING) << "Incorrect audio level len: " << len;
370             return;
371           }
372           //  0                   1
373           //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
374           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
375           // |  ID   | len=0 |V|   level     |
376           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
377           //
378           header->extension.audioLevel = ptr[0] & 0x7f;
379           header->extension.voiceActivity = (ptr[0] & 0x80) != 0;
380           header->extension.hasAudioLevel = true;
381           break;
382         }
383         case kRtpExtensionAbsoluteSendTime: {
384           if (len != 2) {
385             RTC_LOG(LS_WARNING) << "Incorrect absolute send time len: " << len;
386             return;
387           }
388           //  0                   1                   2                   3
389           //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
390           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391           // |  ID   | len=2 |              absolute send time               |
392           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393 
394           header->extension.absoluteSendTime =
395               ByteReader<uint32_t, 3>::ReadBigEndian(ptr);
396           header->extension.hasAbsoluteSendTime = true;
397           break;
398         }
399         case kRtpExtensionAbsoluteCaptureTime: {
400           AbsoluteCaptureTime extension;
401           if (!AbsoluteCaptureTimeExtension::Parse(
402                   rtc::MakeArrayView(ptr, len + 1), &extension)) {
403             RTC_LOG(LS_WARNING)
404                 << "Incorrect absolute capture time len: " << len;
405             return;
406           }
407           header->extension.absolute_capture_time = extension;
408           break;
409         }
410         case kRtpExtensionVideoRotation: {
411           if (len != 0) {
412             RTC_LOG(LS_WARNING)
413                 << "Incorrect coordination of video coordination len: " << len;
414             return;
415           }
416           //  0                   1
417           //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
418           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
419           // |  ID   | len=0 |0 0 0 0 C F R R|
420           // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
421           header->extension.hasVideoRotation = true;
422           header->extension.videoRotation =
423               ConvertCVOByteToVideoRotation(ptr[0]);
424           break;
425         }
426         case kRtpExtensionTransportSequenceNumber: {
427           if (len != 1) {
428             RTC_LOG(LS_WARNING)
429                 << "Incorrect transport sequence number len: " << len;
430             return;
431           }
432           //   0                   1                   2
433           //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
434           //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435           //  |  ID   | L=1   |transport wide sequence number |
436           //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437 
438           uint16_t sequence_number = ptr[0] << 8;
439           sequence_number += ptr[1];
440           header->extension.transportSequenceNumber = sequence_number;
441           header->extension.hasTransportSequenceNumber = true;
442           break;
443         }
444         case kRtpExtensionTransportSequenceNumber02:
445           RTC_LOG(WARNING) << "TransportSequenceNumberV2 unsupported by rtp "
446                               "header parser.";
447           break;
448         case kRtpExtensionPlayoutDelay: {
449           if (len != 2) {
450             RTC_LOG(LS_WARNING) << "Incorrect playout delay len: " << len;
451             return;
452           }
453           //   0                   1                   2                   3
454           //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
455           //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
456           //  |  ID   | len=2 |   MIN delay           |   MAX delay           |
457           //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458 
459           int min_playout_delay = (ptr[0] << 4) | ((ptr[1] >> 4) & 0xf);
460           int max_playout_delay = ((ptr[1] & 0xf) << 8) | ptr[2];
461           header->extension.playout_delay.min_ms =
462               min_playout_delay * PlayoutDelayLimits::kGranularityMs;
463           header->extension.playout_delay.max_ms =
464               max_playout_delay * PlayoutDelayLimits::kGranularityMs;
465           break;
466         }
467         case kRtpExtensionVideoContentType: {
468           if (len != 0) {
469             RTC_LOG(LS_WARNING) << "Incorrect video content type len: " << len;
470             return;
471           }
472           //    0                   1
473           //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
474           //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
475           //   |  ID   | len=0 | Content type  |
476           //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
477 
478           if (videocontenttypehelpers::IsValidContentType(ptr[0])) {
479             header->extension.hasVideoContentType = true;
480             header->extension.videoContentType =
481                 static_cast<VideoContentType>(ptr[0]);
482           }
483           break;
484         }
485         case kRtpExtensionVideoTiming: {
486           if (len != VideoTimingExtension::kValueSizeBytes - 1) {
487             RTC_LOG(LS_WARNING) << "Incorrect video timing len: " << len;
488             return;
489           }
490           header->extension.has_video_timing = true;
491           VideoTimingExtension::Parse(rtc::MakeArrayView(ptr, len + 1),
492                                       &header->extension.video_timing);
493           break;
494         }
495         case kRtpExtensionRtpStreamId: {
496           std::string name(reinterpret_cast<const char*>(ptr), len + 1);
497           if (IsLegalRsidName(name)) {
498             header->extension.stream_id = name;
499           } else {
500             RTC_LOG(LS_WARNING) << "Incorrect RtpStreamId";
501           }
502           break;
503         }
504         case kRtpExtensionRepairedRtpStreamId: {
505           std::string name(reinterpret_cast<const char*>(ptr), len + 1);
506           if (IsLegalRsidName(name)) {
507             header->extension.repaired_stream_id = name;
508           } else {
509             RTC_LOG(LS_WARNING) << "Incorrect RepairedRtpStreamId";
510           }
511           break;
512         }
513         case kRtpExtensionMid: {
514           std::string name(reinterpret_cast<const char*>(ptr), len + 1);
515           if (IsLegalMidName(name)) {
516             header->extension.mid = name;
517           } else {
518             RTC_LOG(LS_WARNING) << "Incorrect Mid";
519           }
520           break;
521         }
522         case kRtpExtensionGenericFrameDescriptor00:
523         case kRtpExtensionGenericFrameDescriptor02:
524           RTC_LOG(WARNING)
525               << "RtpGenericFrameDescriptor unsupported by rtp header parser.";
526           break;
527         case kRtpExtensionColorSpace:
528           RTC_LOG(WARNING)
529               << "RtpExtensionColorSpace unsupported by rtp header parser.";
530           break;
531         case kRtpExtensionInbandComfortNoise:
532           RTC_LOG(WARNING) << "Inband comfort noise extension unsupported by "
533                               "rtp header parser.";
534           break;
535         case kRtpExtensionNone:
536         case kRtpExtensionNumberOfExtensions: {
537           RTC_NOTREACHED() << "Invalid extension type: " << type;
538           return;
539         }
540       }
541     }
542     ptr += (len + 1);
543   }
544 }
545 
546 }  // namespace RtpUtility
547 }  // namespace webrtc
548