diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-16 01:53:07 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-16 01:53:07 +0000 |
commit | 6357e609331c79bda865ac4ec9301a3f0f59d9c7 (patch) | |
tree | 9008d83ee315f5ed9422e6b3cbe10e715707f5a7 /remoting | |
parent | b1081e5dde10ee027a3fc9dfa3781380fb9b49c1 (diff) | |
download | chromium_src-6357e609331c79bda865ac4ec9301a3f0f59d9c7.zip chromium_src-6357e609331c79bda865ac4ec9301a3f0f59d9c7.tar.gz chromium_src-6357e609331c79bda865ac4ec9301a3f0f59d9c7.tar.bz2 |
Packetizer/Depacketizer for RTP.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/4925001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66213 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/protocol/rtp_reader.cc | 18 | ||||
-rw-r--r-- | remoting/protocol/rtp_reader.h | 7 | ||||
-rw-r--r-- | remoting/protocol/rtp_utils.cc | 187 | ||||
-rw-r--r-- | remoting/protocol/rtp_utils.h | 35 | ||||
-rw-r--r-- | remoting/protocol/rtp_video_reader.cc | 129 | ||||
-rw-r--r-- | remoting/protocol/rtp_video_reader.h | 13 | ||||
-rw-r--r-- | remoting/protocol/rtp_video_writer.cc | 56 | ||||
-rw-r--r-- | remoting/protocol/rtp_writer.cc | 55 | ||||
-rw-r--r-- | remoting/protocol/rtp_writer.h | 7 |
9 files changed, 437 insertions, 70 deletions
diff --git a/remoting/protocol/rtp_reader.cc b/remoting/protocol/rtp_reader.cc index b989c44..7e21250 100644 --- a/remoting/protocol/rtp_reader.cc +++ b/remoting/protocol/rtp_reader.cc @@ -24,15 +24,25 @@ void RtpReader::Init(net::Socket* socket, } void RtpReader::OnDataReceived(net::IOBuffer* buffer, int data_size) { - RtpPacket packet; + RtpPacket* packet = new RtpPacket(); int header_size = UnpackRtpHeader(reinterpret_cast<uint8*>(buffer->data()), - data_size, packet.mutable_header()); + data_size, packet->mutable_header()); if (header_size < 0) { LOG(WARNING) << "Received invalid RTP packet."; return; } - packet.mutable_payload()->Append(buffer, buffer->data() + header_size, - data_size - header_size); + + int descriptor_size = UnpackVp8Descriptor( + reinterpret_cast<uint8*>(buffer->data()) + header_size, + data_size - header_size, packet->mutable_vp8_descriptor()); + if (descriptor_size < 0) { + LOG(WARNING) << "Received RTP packet with an invalid VP8 descriptor."; + return; + } + + packet->mutable_payload()->Append( + buffer, buffer->data() + header_size + descriptor_size, + data_size - header_size - descriptor_size); on_message_callback_->Run(packet); } diff --git a/remoting/protocol/rtp_reader.h b/remoting/protocol/rtp_reader.h index e7b42de..1501a3b 100644 --- a/remoting/protocol/rtp_reader.h +++ b/remoting/protocol/rtp_reader.h @@ -20,12 +20,17 @@ class RtpPacket { const RtpHeader& header() const { return header_; } RtpHeader* mutable_header() { return &header_; } + + const Vp8Descriptor& vp8_descriptor() const { return vp8_descriptor_; } + Vp8Descriptor* mutable_vp8_descriptor() { return &vp8_descriptor_; } + const CompoundBuffer& payload() const { return payload_; } CompoundBuffer* mutable_payload() { return &payload_; } private: RtpHeader header_; CompoundBuffer payload_; + Vp8Descriptor vp8_descriptor_; }; class RtpReader : public SocketReaderBase { @@ -35,7 +40,7 @@ class RtpReader : public SocketReaderBase { // The OnMessageCallback is called whenever a new message is received. // Ownership of the message is passed the callback. - typedef Callback1<const RtpPacket&>::Type OnMessageCallback; + typedef Callback1<const RtpPacket*>::Type OnMessageCallback; // Initialize the reader and start reading. Must be called on the thread // |socket| belongs to. The callback will be called when a new message is diff --git a/remoting/protocol/rtp_utils.cc b/remoting/protocol/rtp_utils.cc index 1337795..4075c7b 100644 --- a/remoting/protocol/rtp_utils.cc +++ b/remoting/protocol/rtp_utils.cc @@ -19,25 +19,49 @@ namespace { const int kRtpBaseHeaderSize = 12; const uint8 kRtpVersionNumber = 2; const int kRtpMaxSources = 16; +const int kBytesPerCSRC = 4; } // namespace -int GetRtpHeaderSize(int sources) { - DCHECK_GE(sources, 0); - DCHECK_LT(sources, kRtpMaxSources); - return kRtpBaseHeaderSize + sources * 4; +static inline uint8 ExtractBits(uint8 byte, int bits_count, int shift) { + return (byte >> shift) & ((1 << bits_count) - 1); +} + +// RTP Header format: +// +// 0 1 2 3 +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P|X| CC |M| PT | sequence number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | synchronization source (SSRC) identifier | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | contributing source (CSRC) identifiers | +// | .... | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// On the diagram above order of bytes and order of bits within each +// byte are big-endian. So bits 0 and 7 are the most and the least +// significant bits in the first byte, bit 8 is the most significant +// bit in the second byte, etc. + +int GetRtpHeaderSize(const RtpHeader& header) { + DCHECK_GE(header.sources, 0); + DCHECK_LT(header.sources, kRtpMaxSources); + return kRtpBaseHeaderSize + header.sources * kBytesPerCSRC; } -void PackRtpHeader(uint8* buffer, int buffer_size, - const RtpHeader& header) { +void PackRtpHeader(const RtpHeader& header, uint8* buffer, int buffer_size) { DCHECK_LT(header.sources, kRtpMaxSources); DCHECK_LT(header.payload_type, 1 << 7); - CHECK_GT(buffer_size, GetRtpHeaderSize(header.sources)); + CHECK_GE(buffer_size, GetRtpHeaderSize(header)); - buffer[0] = (kRtpVersionNumber << 6) + - ((uint8)header.padding << 5) + - ((uint8)header.extension << 4) + + buffer[0] = (kRtpVersionNumber << 6) | + ((uint8)header.padding << 5) | + ((uint8)header.extension << 4) | header.sources; - buffer[1] = ((uint8)header.marker << 7) + + buffer[1] = ((uint8)header.marker << 7) | header.payload_type; SetBE16(buffer + 2, header.sequence_number); SetBE32(buffer + 4, header.timestamp); @@ -48,10 +72,6 @@ void PackRtpHeader(uint8* buffer, int buffer_size, } } -static inline uint8 ExtractBits(uint8 byte, int bits_count, int shift) { - return (byte >> shift) & ((1 << bits_count) - 1); -} - int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header) { if (buffer_size < kRtpBaseHeaderSize) { return -1; @@ -75,14 +95,147 @@ int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header) { DCHECK_LT(header->sources, 16); - if (buffer_size < GetRtpHeaderSize(header->sources)) { + if (buffer_size < GetRtpHeaderSize(*header)) { return -1; } for (int i = 0; i < header->sources; i++) { header->source_id[i] = GetBE32(buffer + i * 4 + 12); } - return GetRtpHeaderSize(header->sources); + return GetRtpHeaderSize(*header); +} + +// VP8 Payload Descriptor format: +// +// 0 1 2 3 +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | RSV |I|N|FI |B| PictureID (integer #bytes) | +// +-+-+-+-+-+-+-+-+ | +// : : +// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | : (VP8 data or VP8 payload header; byte aligned)| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// On the diagram above order of bytes and order of bits within each +// byte are big-endian. So bits 0 and 7 are the most and the least +// significant bits in the first byte, bit 8 is the most significant +// bit in the second byte, etc. +// +// RSV: 3 bits +// Bits reserved for future use. MUST be equal to zero and MUST be +// ignored by the receiver. +// +// I: 1 bit +// PictureID present. When set to one, a PictureID is provided after +// the first byte of the payload descriptor. When set to zero, the +// PictureID is omitted, and the one-byte payload descriptor is +// immediately followed by the VP8 payload. +// +// N: 1 bit +// Non-reference frame. When set to one, the frame can be discarded +// without affecting any other future or past frames. +// +// FI: 2 bits +// Fragmentation information field. This field contains information +// about the fragmentation of VP8 payloads carried in the RTP +// packet. The four different values are listed below. +// +// FI Fragmentation status +// 00 The RTP packet contains no fragmented VP8 partitions. The +// payload is one or several complete partitions. +// 01 The RTP packet contains the first part of a fragmented +// partition. The fragment must be placed in its own RTP packet. +// 10 The RTP packet contains a fragment that is neither the first nor +// the last part of a fragmented partition. The fragment must be +// placed in its own RTP packet. +// 11 The RTP packet contains the last part of a fragmented +// partition. The fragment must be placed in its own RTP packet. +// +// B: 1 bit +// Beginning VP8 frame. When set to 1 this signals that a new VP8 +// frame starts in this RTP packet. +// +// PictureID: Multiple of 8 bits +// This is a running index of the frames. The field is present only if +// the I bit is equal to one. The most significant bit of each byte is +// an extension flag. The 7 following bits carry (parts of) the +// PictureID. If the extension flag is one, the PictureID continues in +// the next byte. If the extension flag is zero, the 7 remaining bits +// are the last (and least significant) bits in the PictureID. The +// sender may choose any number of bytes for the PictureID. The +// PictureID SHALL start on a random number, and SHALL wrap after +// reaching the maximum ID as chosen by the application + +int GetVp8DescriptorSize(const Vp8Descriptor& descriptor) { + if (descriptor.picture_id == kuint32max) + return 1; + int result = 2; + // We need 1 byte per each 7 bits in picture_id. + uint32 picture_id = descriptor.picture_id >> 7; + while (picture_id > 0) { + picture_id >>= 7; + ++result; + } + return result; +} + +void PackVp8Descriptor(const Vp8Descriptor& descriptor, uint8* buffer, + int buffer_size) { + CHECK_GT(buffer_size, 0); + + buffer[0] = + ((uint8)(descriptor.picture_id != kuint32max) << 4) | + ((uint8)descriptor.non_reference_frame << 3) | + (descriptor.fragmentation_info << 1) | + ((uint8)descriptor.frame_beginning); + + uint32 picture_id = descriptor.picture_id; + if (picture_id == kuint32max) + return; + + int pos = 1; + while (picture_id > 0) { + CHECK_LT(pos, buffer_size); + buffer[pos] = picture_id & 0x7F; + picture_id >>= 7; + + // Set the extension bit if neccessary. + if (picture_id > 0) + buffer[pos] |= 0x80; + ++pos; + } +} + +int UnpackVp8Descriptor(const uint8* buffer, int buffer_size, + Vp8Descriptor* descriptor) { + if (buffer_size <= 0) + return -1; + + bool picture_id_present = ExtractBits(buffer[0], 1, 4) != 0; + descriptor->non_reference_frame = ExtractBits(buffer[0], 1, 3) != 0; + descriptor->fragmentation_info = ExtractBits(buffer[0], 2, 1); + descriptor->frame_beginning = ExtractBits(buffer[0], 1, 0) != 0; + + // Return here if we don't need to decode PictureID. + if (!picture_id_present) { + descriptor->picture_id = kuint32max; + return 1; + } + + // Decode PictureID. + bool extension = true; + int pos = 1; + descriptor->picture_id = 0; + while (extension) { + if (pos >= buffer_size) + return -1; + + descriptor->picture_id |= buffer[pos] & 0x7F; + extension = (buffer[pos] & 0x80) != 0; + pos += 1; + } + return pos; } } // namespace protocol diff --git a/remoting/protocol/rtp_utils.h b/remoting/protocol/rtp_utils.h index f1275a9..9049a22 100644 --- a/remoting/protocol/rtp_utils.h +++ b/remoting/protocol/rtp_utils.h @@ -24,17 +24,42 @@ struct RtpHeader { uint32 source_id[15]; }; +// Vp8Descriptor struct used to store values of the VP8 RTP descriptor +// fields. Meaning of each field is documented in the RTP Payload +// Format for VP8 spec: http://www.webmproject.org/code/specs/rtp/ . +struct Vp8Descriptor { + enum FragmentationInfo { + NOT_FRAGMENTED = 0, + FIRST_FRAGMENT = 1, + MIDDLE_FRAGMENT = 2, + LAST_FRAGMENT = 3, + }; + + bool non_reference_frame; + uint8 fragmentation_info; + bool frame_beginning; + + // PictureID is considered to be absent if |picture_id| is set to kuint32max. + uint32 picture_id; +}; + // Returns size of RTP header for the specified number of sources. -int GetRtpHeaderSize(int sources); +int GetRtpHeaderSize(const RtpHeader& header); // Packs RTP header into the buffer. -void PackRtpHeader(uint8* buffer, int buffer_size, - const RtpHeader& header); +void PackRtpHeader(const RtpHeader& header, uint8* buffer, int buffer_size); // Unpacks RTP header and stores unpacked values in |header|. If the header // is not valid returns -1, otherwise returns size of the header. -int UnpackRtpHeader(const uint8* buffer, int buffer_size, - RtpHeader* header); +int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header); + +int GetVp8DescriptorSize(const Vp8Descriptor& descriptor); + +void PackVp8Descriptor(const Vp8Descriptor& descriptor, uint8* buffer, + int buffer_size); + +int UnpackVp8Descriptor(const uint8* buffer, int buffer_size, + Vp8Descriptor* descriptor); } // namespace protocol } // namespace remoting diff --git a/remoting/protocol/rtp_video_reader.cc b/remoting/protocol/rtp_video_reader.cc index 8a17339..3a73f10 100644 --- a/remoting/protocol/rtp_video_reader.cc +++ b/remoting/protocol/rtp_video_reader.cc @@ -11,8 +11,17 @@ namespace remoting { namespace protocol { -RtpVideoReader::RtpVideoReader() { } -RtpVideoReader::~RtpVideoReader() { } +namespace { +const int kMaxPacketsInQueue = 1024; +} // namespace + +RtpVideoReader::RtpVideoReader() + : last_sequence_number_(0) { +} + +RtpVideoReader::~RtpVideoReader() { + ResetQueue(); +} void RtpVideoReader::Init(protocol::Session* session, VideoStub* video_stub) { rtp_reader_.Init(session->video_rtp_channel(), @@ -24,16 +33,120 @@ void RtpVideoReader::Close() { rtp_reader_.Close(); } -void RtpVideoReader::OnRtpPacket(const RtpPacket& rtp_packet) { +void RtpVideoReader::ResetQueue() { + for (PacketsQueue::iterator it = packets_queue_.begin(); + it != packets_queue_.end(); ++it) { + delete *it; + } + packets_queue_.clear(); +} + +void RtpVideoReader::OnRtpPacket(const RtpPacket* rtp_packet) { + uint32 sequence_number = rtp_packet->header().sequence_number; + int32 relative_number = sequence_number - last_sequence_number_; + int packet_index; + if (relative_number > 0) { + if (relative_number > kMaxPacketsInQueue) { + // Sequence number jumped too much for some reason. Reset the queue. + ResetQueue(); + packets_queue_.resize(1); + } else { + packets_queue_.resize(packets_queue_.size() + relative_number); + // Cleanup old packets, so that we don't have more than + // |kMaxPacketsInQueue| packets. + while (static_cast<int>(packets_queue_.size()) > kMaxPacketsInQueue) { + delete packets_queue_.front(); + packets_queue_.pop_front(); + } + } + last_sequence_number_ = sequence_number; + packet_index = packets_queue_.size() - 1; + } else { + packet_index = packets_queue_.size() - 1 + relative_number; + if (packet_index < 0) { + // The packet is too old. Just drop it. + delete rtp_packet; + return; + } + } + + CHECK_LT(packet_index, static_cast<int>(packets_queue_.size())); + if (packets_queue_[packet_index]) { + LOG(WARNING) << "Received duplicate packet with sequence number " + << sequence_number; + delete packets_queue_[packet_index]; + } + packets_queue_[packet_index] = rtp_packet; + + CheckFullPacket(packets_queue_.begin() + packet_index); +} + +void RtpVideoReader::CheckFullPacket(PacketsQueue::iterator pos) { + if ((*pos)->vp8_descriptor().fragmentation_info == + Vp8Descriptor::NOT_FRAGMENTED) { + // The packet is not fragmented. + RebuildVideoPacket(pos, pos); + return; + } + + PacketsQueue::iterator first = pos; + while (first > packets_queue_.begin() && (*first) && + (*first)->vp8_descriptor().fragmentation_info != + Vp8Descriptor::FIRST_FRAGMENT) { + first--; + } + if (!(*first) || (*first)->vp8_descriptor().fragmentation_info != + Vp8Descriptor::FIRST_FRAGMENT) { + // We don't have first fragment. + return; + } + + PacketsQueue::iterator last = pos; + while (last < (packets_queue_.end() - 1) && (*last) && + (*last)->vp8_descriptor().fragmentation_info != + Vp8Descriptor::LAST_FRAGMENT) { + last++; + } + if (!(*last) || (*last)->vp8_descriptor().fragmentation_info != + Vp8Descriptor::LAST_FRAGMENT) { + // We don't have last fragment. + return; + } + + // We've found first and last fragments, and we have all fragments in the + // middle, so we can rebuild fill packet. + RebuildVideoPacket(first, last); +} + +void RtpVideoReader::RebuildVideoPacket(PacketsQueue::iterator first, + PacketsQueue::iterator last) { VideoPacket* packet = new VideoPacket(); - packet->mutable_data()->resize(rtp_packet.payload().total_bytes()); - rtp_packet.payload().CopyTo( - const_cast<char*>(packet->mutable_data()->data()), - packet->data().size()); + // Set flags. + if ((*first)->vp8_descriptor().frame_beginning) + packet->set_flags(packet->flags() | VideoPacket::FIRST_PACKET); + + if ((*last)->header().marker) + packet->set_flags(packet->flags() | VideoPacket::LAST_PACKET); + + // Rebuild packet content from the fragments. + // TODO(sergeyu): Use CompoundBuffer inside of VideoPacket, so that we don't + // need to memcopy any data. + CompoundBuffer content; + for (PacketsQueue::iterator it = first; it <= last; ++it) { + content.Append((*it)->payload()); + + // Delete packet because we don't need it anymore. + delete *it; + *it = NULL; + } + + packet->mutable_data()->resize(content.total_bytes()); + content.CopyTo(const_cast<char*>(packet->mutable_data()->data()), + packet->data().size()); + // Set format. packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8); - packet->set_flags(rtp_packet.header().marker ? VideoPacket::LAST_PACKET : 0); video_stub_->ProcessVideoPacket(packet, new DeleteTask<VideoPacket>(packet)); } diff --git a/remoting/protocol/rtp_video_reader.h b/remoting/protocol/rtp_video_reader.h index ccfb53e..9a0ae89 100644 --- a/remoting/protocol/rtp_video_reader.h +++ b/remoting/protocol/rtp_video_reader.h @@ -23,10 +23,21 @@ class RtpVideoReader : public VideoReader { virtual void Close(); private: - void OnRtpPacket(const RtpPacket& rtp_packet); + friend class RtpVideoReaderTest; + + typedef std::deque<const RtpPacket*> PacketsQueue; + + void OnRtpPacket(const RtpPacket* rtp_packet); + void CheckFullPacket(PacketsQueue::iterator pos); + void RebuildVideoPacket(PacketsQueue::iterator from, + PacketsQueue::iterator to); + void ResetQueue(); RtpReader rtp_reader_; + PacketsQueue packets_queue_; + uint32 last_sequence_number_; + // The stub that processes all received packets. VideoStub* video_stub_; diff --git a/remoting/protocol/rtp_video_writer.cc b/remoting/protocol/rtp_video_writer.cc index 1aefbe8..146752c 100644 --- a/remoting/protocol/rtp_video_writer.cc +++ b/remoting/protocol/rtp_video_writer.cc @@ -13,6 +13,10 @@ namespace remoting { namespace protocol { +namespace { +const int kMtu = 1200; +} // namespace + RtpVideoWriter::RtpVideoWriter() { } RtpVideoWriter::~RtpVideoWriter() { } @@ -22,17 +26,65 @@ void RtpVideoWriter::Init(protocol::Session* session) { } void RtpVideoWriter::SendPacket(const VideoPacket& packet) { + CHECK(packet.format().encoding() == VideoPacketFormat::ENCODING_VP8) + << "Only VP8 is supported in RTP."; + CompoundBuffer payload; + // TODO(sergeyu): This copy would not be necessary CompoundBuffer was used + // inside of VideoPacket. payload.AppendCopyOf(packet.data().data(), packet.data().size()); - rtp_writer_.SendPacket(payload, packet.timestamp()); + Vp8Descriptor vp8_desriptor; + // TODO(sergeyu): Add a flag in VideoPacket that indicates whether this is a + // key frame or not. + vp8_desriptor.non_reference_frame = false; + vp8_desriptor.picture_id = kuint32max; + + int position = 0; + while (position < payload.total_bytes()) { + int size = std::min(kMtu, payload.total_bytes() - position); + + // Frame beginning flag is set only for the first packet in the first + // partition. + vp8_desriptor.frame_beginning = + (packet.flags() & VideoPacket::FIRST_PACKET) != 0 && position == 0; + + // Marker bit is set only for the last packet in the last partition. + bool marker = (position + size) == payload.total_bytes() && + (packet.flags() & VideoPacket::LAST_PACKET) != 0; + + // Set fragmentation flag appropriately. + if (position == 0) { + if (size == payload.total_bytes()) { + vp8_desriptor.fragmentation_info = Vp8Descriptor::NOT_FRAGMENTED; + } else { + vp8_desriptor.fragmentation_info = Vp8Descriptor::FIRST_FRAGMENT; + } + } else { + if (position + size == payload.total_bytes()) { + vp8_desriptor.fragmentation_info = Vp8Descriptor::LAST_FRAGMENT; + } else { + vp8_desriptor.fragmentation_info = Vp8Descriptor::MIDDLE_FRAGMENT; + } + } + + // Create CompoundBuffer for the chunk. + CompoundBuffer chunk; + chunk.CopyFrom(payload, position, position + size); + + // And send it. + rtp_writer_.SendPacket(packet.timestamp(), marker, vp8_desriptor, chunk); + + position += size; + } + + DCHECK_EQ(position, payload.total_bytes()); } int RtpVideoWriter::GetPendingPackets() { return rtp_writer_.GetPendingPackets(); } - void RtpVideoWriter::Close() { rtp_writer_.Close(); } diff --git a/remoting/protocol/rtp_writer.cc b/remoting/protocol/rtp_writer.cc index e143222..f01576c 100644 --- a/remoting/protocol/rtp_writer.cc +++ b/remoting/protocol/rtp_writer.cc @@ -13,9 +13,8 @@ namespace remoting { namespace protocol { namespace { -const int kMtu = 1200; const uint8 kRtpPayloadTypePrivate = 96; -} +} // namespace RtpWriter::RtpWriter() : rtp_socket_(NULL), @@ -34,11 +33,14 @@ void RtpWriter::Init(net::Socket* rtp_socket, net::Socket* rtcp_socket) { rtcp_socket_ = rtcp_socket; } -void RtpWriter::SendPacket(const CompoundBuffer& payload, uint32 timestamp) { +void RtpWriter::SendPacket(uint32 timestamp, bool marker, + const Vp8Descriptor& vp8_descriptor, + const CompoundBuffer& payload) { RtpHeader header; header.padding = false; header.extension = false; header.sources = 0; + header.marker = marker; header.payload_type = kRtpPayloadTypePrivate; header.timestamp = timestamp; @@ -47,39 +49,32 @@ void RtpWriter::SendPacket(const CompoundBuffer& payload, uint32 timestamp) { // so SSRC isn't useful. Implement it in future if neccessary. header.sync_source_id = 0; - // TODO(sergeyu): Add VP8 payload header. - - int position = 0; - while (position < payload.total_bytes()) { - // Allocate buffer. - int size = std::min(kMtu, payload.total_bytes() - position); - int header_size = GetRtpHeaderSize(header.sources); - int total_size = size + header_size; - net::IOBufferWithSize* buffer = new net::IOBufferWithSize(total_size); - - // Set marker if this is the last frame. - header.marker = (position + size) == payload.total_bytes(); + // TODO(sergeyu): Handle sequence number wrapping. + header.sequence_number = last_packet_number_; + ++last_packet_number_; - // TODO(sergeyu): Handle sequence number wrapping. - header.sequence_number = last_packet_number_; - ++last_packet_number_; + int header_size = GetRtpHeaderSize(header); + int vp8_descriptor_size = GetVp8DescriptorSize(vp8_descriptor); + int payload_size = payload.total_bytes(); + int total_size = header_size + vp8_descriptor_size + payload_size; - // Generate header. - PackRtpHeader(reinterpret_cast<uint8*>(buffer->data()), buffer->size(), - header); + net::IOBufferWithSize* buffer = new net::IOBufferWithSize(total_size); - // Copy data to the buffer. - CompoundBuffer chunk; - chunk.CopyFrom(payload, position, position + size); - chunk.CopyTo(buffer->data() + header_size, size); + // Pack header. + PackRtpHeader(header, reinterpret_cast<uint8*>(buffer->data()), + header_size); - // Send it. - buffered_rtp_writer_->Write(buffer); + // Pack VP8 descriptor. + PackVp8Descriptor(vp8_descriptor, + reinterpret_cast<uint8*>(buffer->data()) + header_size, + vp8_descriptor_size); - position += size; - } + // Copy payload to the buffer. + payload.CopyTo(buffer->data() + header_size + vp8_descriptor_size, + payload_size); - DCHECK_EQ(position, payload.total_bytes()); + // And write the packet. + buffered_rtp_writer_->Write(buffer); } int RtpWriter::GetPendingPackets() { diff --git a/remoting/protocol/rtp_writer.h b/remoting/protocol/rtp_writer.h index 1f410e5..99bbb49 100644 --- a/remoting/protocol/rtp_writer.h +++ b/remoting/protocol/rtp_writer.h @@ -7,6 +7,7 @@ #include "net/socket/socket.h" #include "remoting/protocol/buffered_socket_writer.h" +#include "remoting/protocol/rtp_utils.h" namespace remoting { @@ -23,8 +24,10 @@ class RtpWriter { // to. void Init(net::Socket* rtp_socket, net::Socket* rtcp_socket); - // Sends next packet. - void SendPacket(const CompoundBuffer& payload, uint32 timestamp); + // Sends next packet. The packet is mutated by + void SendPacket(uint32 timestamp, bool marker, + const Vp8Descriptor& vp8_descriptor, + const CompoundBuffer& payload); // Returns number of packets queued in the buffer. int GetPendingPackets(); |