Chromium Code Reviews| Index: remoting/protocol/rtp_video_reader.cc |
| diff --git a/remoting/protocol/rtp_video_reader.cc b/remoting/protocol/rtp_video_reader.cc |
| index 8a173393d0f4f80e76a51e4258be739416522531..eb0281736a6d6cc3bba9059af753acfb355dd839 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(RtpPacket* rtp_packet) { |
|
Alpha Left Google
2010/11/15 23:46:35
Looks like this can be const *, you can still dele
Sergey Ulanov
2010/11/16 00:22:55
Agree. Changed this to const
|
| + 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())); |
|
Alpha Left Google
2010/11/15 23:46:35
can we not use CHECK but return failure so that we
Sergey Ulanov
2010/11/16 00:22:55
The code above guarantees that packet_index < stat
|
| + 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)); |
| } |