1 /*
2 * Copyright (c) 2014 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_format_video_generic.h"
12
13 #include <assert.h>
14 #include <string.h>
15
16 #include "absl/types/optional.h"
17 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
18 #include "rtc_base/checks.h"
19 #include "rtc_base/logging.h"
20
21 namespace webrtc {
22
23 static const size_t kGenericHeaderLength = 1;
24 static const size_t kExtendedHeaderLength = 2;
25
RtpPacketizerGeneric(rtc::ArrayView<const uint8_t> payload,PayloadSizeLimits limits,const RTPVideoHeader & rtp_video_header)26 RtpPacketizerGeneric::RtpPacketizerGeneric(
27 rtc::ArrayView<const uint8_t> payload,
28 PayloadSizeLimits limits,
29 const RTPVideoHeader& rtp_video_header)
30 : remaining_payload_(payload) {
31 BuildHeader(rtp_video_header);
32
33 limits.max_payload_len -= header_size_;
34 payload_sizes_ = SplitAboutEqually(payload.size(), limits);
35 current_packet_ = payload_sizes_.begin();
36 }
37
RtpPacketizerGeneric(rtc::ArrayView<const uint8_t> payload,PayloadSizeLimits limits)38 RtpPacketizerGeneric::RtpPacketizerGeneric(
39 rtc::ArrayView<const uint8_t> payload,
40 PayloadSizeLimits limits)
41 : header_size_(0), remaining_payload_(payload) {
42 payload_sizes_ = SplitAboutEqually(payload.size(), limits);
43 current_packet_ = payload_sizes_.begin();
44 }
45
46 RtpPacketizerGeneric::~RtpPacketizerGeneric() = default;
47
NumPackets() const48 size_t RtpPacketizerGeneric::NumPackets() const {
49 return payload_sizes_.end() - current_packet_;
50 }
51
NextPacket(RtpPacketToSend * packet)52 bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet) {
53 RTC_DCHECK(packet);
54 if (current_packet_ == payload_sizes_.end())
55 return false;
56
57 size_t next_packet_payload_len = *current_packet_;
58
59 uint8_t* out_ptr =
60 packet->AllocatePayload(header_size_ + next_packet_payload_len);
61 RTC_CHECK(out_ptr);
62
63 if (header_size_ > 0) {
64 memcpy(out_ptr, header_, header_size_);
65 // Remove first-packet bit, following packets are intermediate.
66 header_[0] &= ~RtpFormatVideoGeneric::kFirstPacketBit;
67 }
68
69 memcpy(out_ptr + header_size_, remaining_payload_.data(),
70 next_packet_payload_len);
71
72 remaining_payload_ = remaining_payload_.subview(next_packet_payload_len);
73
74 ++current_packet_;
75
76 // Packets left to produce and data left to split should end at the same time.
77 RTC_DCHECK_EQ(current_packet_ == payload_sizes_.end(),
78 remaining_payload_.empty());
79
80 packet->SetMarker(remaining_payload_.empty());
81 return true;
82 }
83
BuildHeader(const RTPVideoHeader & rtp_video_header)84 void RtpPacketizerGeneric::BuildHeader(const RTPVideoHeader& rtp_video_header) {
85 header_size_ = kGenericHeaderLength;
86 header_[0] = RtpFormatVideoGeneric::kFirstPacketBit;
87 if (rtp_video_header.frame_type == VideoFrameType::kVideoFrameKey) {
88 header_[0] |= RtpFormatVideoGeneric::kKeyFrameBit;
89 }
90 if (const auto* generic_header = absl::get_if<RTPVideoHeaderLegacyGeneric>(
91 &rtp_video_header.video_type_header)) {
92 // Store bottom 15 bits of the picture id. Only 15 bits are used for
93 // compatibility with other packetizer implemenetations.
94 uint16_t picture_id = generic_header->picture_id;
95 header_[0] |= RtpFormatVideoGeneric::kExtendedHeaderBit;
96 header_[1] = (picture_id >> 8) & 0x7F;
97 header_[2] = picture_id & 0xFF;
98 header_size_ += kExtendedHeaderLength;
99 }
100 }
101 } // namespace webrtc
102