1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/cast/net/rtp_sender/rtp_packetizer/rtp_packetizer.h"
6
7 #include "base/logging.h"
8 #include "media/cast/cast_defines.h"
9 #include "media/cast/net/pacing/paced_sender.h"
10 #include "net/base/big_endian.h"
11
12 namespace media {
13 namespace cast {
14
15 static const uint16 kCommonRtpHeaderLength = 12;
16 static const uint16 kCastRtpHeaderLength = 7;
17 static const uint8 kCastKeyFrameBitMask = 0x80;
18 static const uint8 kCastReferenceFrameIdBitMask = 0x40;
19
RtpPacketizer(PacedPacketSender * transport,PacketStorage * packet_storage,RtpPacketizerConfig rtp_packetizer_config)20 RtpPacketizer::RtpPacketizer(PacedPacketSender* transport,
21 PacketStorage* packet_storage,
22 RtpPacketizerConfig rtp_packetizer_config)
23 : config_(rtp_packetizer_config),
24 transport_(transport),
25 packet_storage_(packet_storage),
26 sequence_number_(config_.sequence_number),
27 rtp_timestamp_(config_.rtp_timestamp),
28 packet_id_(0),
29 send_packets_count_(0),
30 send_octet_count_(0) {
31 DCHECK(transport) << "Invalid argument";
32 }
33
~RtpPacketizer()34 RtpPacketizer::~RtpPacketizer() {}
35
IncomingEncodedVideoFrame(const EncodedVideoFrame * video_frame,const base::TimeTicks & capture_time)36 void RtpPacketizer::IncomingEncodedVideoFrame(
37 const EncodedVideoFrame* video_frame,
38 const base::TimeTicks& capture_time) {
39 DCHECK(!config_.audio) << "Invalid state";
40 if (config_.audio) return;
41
42 // Timestamp is in 90 KHz for video.
43 rtp_timestamp_ = GetVideoRtpTimestamp(capture_time);
44 time_last_sent_rtp_timestamp_ = capture_time;
45
46 Cast(video_frame->key_frame,
47 video_frame->frame_id,
48 video_frame->last_referenced_frame_id,
49 rtp_timestamp_,
50 video_frame->data);
51 }
52
IncomingEncodedAudioFrame(const EncodedAudioFrame * audio_frame,const base::TimeTicks & recorded_time)53 void RtpPacketizer::IncomingEncodedAudioFrame(
54 const EncodedAudioFrame* audio_frame,
55 const base::TimeTicks& recorded_time) {
56 DCHECK(config_.audio) << "Invalid state";
57 if (!config_.audio) return;
58
59 rtp_timestamp_ += audio_frame->samples; // Timestamp is in samples for audio.
60 time_last_sent_rtp_timestamp_ = recorded_time;
61 Cast(true, audio_frame->frame_id, 0, rtp_timestamp_, audio_frame->data);
62 }
63
NextSequenceNumber()64 uint16 RtpPacketizer::NextSequenceNumber() {
65 ++sequence_number_;
66 return sequence_number_ - 1;
67 }
68
LastSentTimestamp(base::TimeTicks * time_sent,uint32 * rtp_timestamp) const69 bool RtpPacketizer::LastSentTimestamp(base::TimeTicks* time_sent,
70 uint32* rtp_timestamp) const {
71 if (time_last_sent_rtp_timestamp_.is_null()) return false;
72
73 *time_sent = time_last_sent_rtp_timestamp_;
74 *rtp_timestamp = rtp_timestamp_;
75 return true;
76 }
77
78 // TODO(mikhal): Switch to pass data with a const_ref.
Cast(bool is_key,uint32 frame_id,uint32 reference_frame_id,uint32 timestamp,const std::string & data)79 void RtpPacketizer::Cast(bool is_key,
80 uint32 frame_id,
81 uint32 reference_frame_id,
82 uint32 timestamp,
83 const std::string& data) {
84 uint16 rtp_header_length = kCommonRtpHeaderLength + kCastRtpHeaderLength;
85 uint16 max_length = config_.max_payload_length - rtp_header_length - 1;
86
87 // Split the payload evenly (round number up).
88 size_t num_packets = (data.size() + max_length) / max_length;
89 size_t payload_length = (data.size() + num_packets) / num_packets;
90 DCHECK_LE(payload_length, max_length) << "Invalid argument";
91
92 PacketList packets;
93
94 size_t remaining_size = data.size();
95 std::string::const_iterator data_iter = data.begin();
96 while (remaining_size > 0) {
97 Packet packet;
98
99 if (remaining_size < payload_length) {
100 payload_length = remaining_size;
101 }
102 remaining_size -= payload_length;
103 BuildCommonRTPheader(&packet, remaining_size == 0, timestamp);
104
105 // Build Cast header.
106 packet.push_back(
107 (is_key ? kCastKeyFrameBitMask : 0) | kCastReferenceFrameIdBitMask);
108 packet.push_back(frame_id);
109 size_t start_size = packet.size();
110 packet.resize(start_size + 4);
111 net::BigEndianWriter big_endian_writer(&(packet[start_size]), 4);
112 big_endian_writer.WriteU16(packet_id_);
113 big_endian_writer.WriteU16(static_cast<uint16>(num_packets - 1));
114 packet.push_back(static_cast<uint8>(reference_frame_id));
115
116 // Copy payload data.
117 packet.insert(packet.end(), data_iter, data_iter + payload_length);
118
119 // Store packet.
120 packet_storage_->StorePacket(frame_id, packet_id_, &packet);
121 ++packet_id_;
122 data_iter += payload_length;
123
124 // Update stats.
125 ++send_packets_count_;
126 send_octet_count_ += payload_length;
127 packets.push_back(packet);
128 }
129 DCHECK(packet_id_ == num_packets) << "Invalid state";
130
131 // Send to network.
132 transport_->SendPackets(packets);
133
134 // Prepare for next frame.
135 packet_id_ = 0;
136 }
137
BuildCommonRTPheader(Packet * packet,bool marker_bit,uint32 time_stamp)138 void RtpPacketizer::BuildCommonRTPheader(
139 Packet* packet, bool marker_bit, uint32 time_stamp) {
140 packet->push_back(0x80);
141 packet->push_back(static_cast<uint8>(config_.payload_type) |
142 (marker_bit ? kRtpMarkerBitMask : 0));
143 size_t start_size = packet->size();
144 packet->resize(start_size + 10);
145 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 10);
146 big_endian_writer.WriteU16(sequence_number_);
147 big_endian_writer.WriteU32(time_stamp);
148 big_endian_writer.WriteU32(config_.ssrc);
149 ++sequence_number_;
150 }
151
152 } // namespace cast
153 } // namespace media
154