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