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 <string>
12
13 #include "modules/include/module_common_types.h"
14 #include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
15 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
16 #include "rtc_base/logging.h"
17
18 namespace webrtc {
19
20 static const size_t kGenericHeaderLength = 1;
21
RtpPacketizerGeneric(FrameType frame_type,size_t max_payload_len,size_t last_packet_reduction_len)22 RtpPacketizerGeneric::RtpPacketizerGeneric(FrameType frame_type,
23 size_t max_payload_len,
24 size_t last_packet_reduction_len)
25 : payload_data_(NULL),
26 payload_size_(0),
27 max_payload_len_(max_payload_len - kGenericHeaderLength),
28 last_packet_reduction_len_(last_packet_reduction_len),
29 frame_type_(frame_type),
30 num_packets_left_(0),
31 num_larger_packets_(0) {}
32
~RtpPacketizerGeneric()33 RtpPacketizerGeneric::~RtpPacketizerGeneric() {
34 }
35
SetPayloadData(const uint8_t * payload_data,size_t payload_size,const RTPFragmentationHeader * fragmentation)36 size_t RtpPacketizerGeneric::SetPayloadData(
37 const uint8_t* payload_data,
38 size_t payload_size,
39 const RTPFragmentationHeader* fragmentation) {
40 payload_data_ = payload_data;
41 payload_size_ = payload_size;
42
43 // Fragment packets such that they are almost the same size, even accounting
44 // for larger header in the last packet.
45 // Since we are given how much extra space is occupied by the longer header
46 // in the last packet, we can pretend that RTP headers are the same, but
47 // there's last_packet_reduction_len_ virtual payload, to be put at the end of
48 // the last packet.
49 //
50 size_t total_bytes = payload_size_ + last_packet_reduction_len_;
51
52 // Minimum needed number of packets to fit payload and virtual payload in the
53 // last packet.
54 num_packets_left_ = (total_bytes + max_payload_len_ - 1) / max_payload_len_;
55 // Given number of packets, calculate average size rounded down.
56 payload_len_per_packet_ = total_bytes / num_packets_left_;
57 // If we can't divide everything perfectly evenly, we put 1 extra byte in some
58 // last packets: 14 bytes in 4 packets would be split as 3+3+4+4.
59 num_larger_packets_ = total_bytes % num_packets_left_;
60 RTC_DCHECK_LE(payload_len_per_packet_, max_payload_len_);
61
62 generic_header_ = RtpFormatVideoGeneric::kFirstPacketBit;
63 if (frame_type_ == kVideoFrameKey) {
64 generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit;
65 }
66 return num_packets_left_;
67 }
68
NextPacket(RtpPacketToSend * packet)69 bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet) {
70 RTC_DCHECK(packet);
71 if (num_packets_left_ == 0)
72 return false;
73 // Last larger_packets_ packets are 1 byte larger than previous packets.
74 // Increase per packet payload once needed.
75 if (num_packets_left_ == num_larger_packets_)
76 ++payload_len_per_packet_;
77 size_t next_packet_payload_len = payload_len_per_packet_;
78 if (payload_size_ <= next_packet_payload_len) {
79 // Whole payload fits into this packet.
80 next_packet_payload_len = payload_size_;
81 if (num_packets_left_ == 2) {
82 // This is the penultimate packet. Leave at least 1 payload byte for the
83 // last packet.
84 --next_packet_payload_len;
85 RTC_DCHECK_GT(next_packet_payload_len, 0);
86 }
87 }
88 RTC_DCHECK_LE(next_packet_payload_len, max_payload_len_);
89
90 uint8_t* out_ptr =
91 packet->AllocatePayload(kGenericHeaderLength + next_packet_payload_len);
92 // Put generic header in packet.
93 out_ptr[0] = generic_header_;
94 // Remove first-packet bit, following packets are intermediate.
95 generic_header_ &= ~RtpFormatVideoGeneric::kFirstPacketBit;
96
97 // Put payload in packet.
98 memcpy(out_ptr + kGenericHeaderLength, payload_data_,
99 next_packet_payload_len);
100 payload_data_ += next_packet_payload_len;
101 payload_size_ -= next_packet_payload_len;
102 --num_packets_left_;
103 // Packets left to produce and data left to split should end at the same time.
104 RTC_DCHECK_EQ(num_packets_left_ == 0, payload_size_ == 0);
105
106 packet->SetMarker(payload_size_ == 0);
107
108 return true;
109 }
110
ToString()111 std::string RtpPacketizerGeneric::ToString() {
112 return "RtpPacketizerGeneric";
113 }
114
Parse(ParsedPayload * parsed_payload,const uint8_t * payload_data,size_t payload_data_length)115 bool RtpDepacketizerGeneric::Parse(ParsedPayload* parsed_payload,
116 const uint8_t* payload_data,
117 size_t payload_data_length) {
118 assert(parsed_payload != NULL);
119 if (payload_data_length == 0) {
120 RTC_LOG(LS_ERROR) << "Empty payload.";
121 return false;
122 }
123
124 uint8_t generic_header = *payload_data++;
125 --payload_data_length;
126
127 parsed_payload->frame_type =
128 ((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0)
129 ? kVideoFrameKey
130 : kVideoFrameDelta;
131 parsed_payload->type.Video.is_first_packet_in_frame =
132 (generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0;
133 parsed_payload->type.Video.codec = kRtpVideoGeneric;
134 parsed_payload->type.Video.width = 0;
135 parsed_payload->type.Video.height = 0;
136
137 parsed_payload->payload = payload_data;
138 parsed_payload->payload_length = payload_data_length;
139 return true;
140 }
141 } // namespace webrtc
142