summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-16 01:53:07 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-16 01:53:07 +0000
commit6357e609331c79bda865ac4ec9301a3f0f59d9c7 (patch)
tree9008d83ee315f5ed9422e6b3cbe10e715707f5a7 /remoting
parentb1081e5dde10ee027a3fc9dfa3781380fb9b49c1 (diff)
downloadchromium_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.cc18
-rw-r--r--remoting/protocol/rtp_reader.h7
-rw-r--r--remoting/protocol/rtp_utils.cc187
-rw-r--r--remoting/protocol/rtp_utils.h35
-rw-r--r--remoting/protocol/rtp_video_reader.cc129
-rw-r--r--remoting/protocol/rtp_video_reader.h13
-rw-r--r--remoting/protocol/rtp_video_writer.cc56
-rw-r--r--remoting/protocol/rtp_writer.cc55
-rw-r--r--remoting/protocol/rtp_writer.h7
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();