Commit 66cd59f4 authored by hubbe's avatar hubbe Committed by Commit bot

Cast: Get rid of frame_id_map

FrameBuffer is basically a superset of FrameInfo, so let's merge FrameIdMap with Framer and
use FrameBuffer instead of FrameInfo.

No functional changes, only refactoring.

Review URL: https://codereview.chromium.org/540713002

Cr-Commit-Position: refs/heads/master@{#293575}
parent 893a2b42
......@@ -88,8 +88,6 @@ source_set("net") {
"net/rtp/cast_message_builder.h",
"net/rtp/frame_buffer.cc",
"net/rtp/frame_buffer.h",
"net/rtp/frame_id_map.cc",
"net/rtp/frame_id_map.h",
"net/rtp/framer.cc",
"net/rtp/framer.h",
"net/rtp/receiver_stats.cc",
......
......@@ -111,8 +111,6 @@
'net/rtp/cast_message_builder.h',
'net/rtp/frame_buffer.cc',
'net/rtp/frame_buffer.h',
'net/rtp/frame_id_map.cc',
'net/rtp/frame_id_map.h',
'net/rtp/framer.cc',
'net/rtp/framer.h',
'net/rtp/receiver_stats.cc',
......
......@@ -5,6 +5,7 @@
#include "media/cast/net/rtp/cast_message_builder.h"
#include "media/cast/cast_defines.h"
#include "media/cast/net/rtp/framer.h"
namespace media {
namespace cast {
......@@ -12,13 +13,13 @@ namespace cast {
CastMessageBuilder::CastMessageBuilder(
base::TickClock* clock,
RtpPayloadFeedback* incoming_payload_feedback,
FrameIdMap* frame_id_map,
const Framer* framer,
uint32 media_ssrc,
bool decoder_faster_than_max_frame_rate,
int max_unacked_frames)
: clock_(clock),
cast_feedback_(incoming_payload_feedback),
frame_id_map_(frame_id_map),
framer_(framer),
media_ssrc_(media_ssrc),
decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate),
max_unacked_frames_(max_unacked_frames),
......@@ -51,7 +52,7 @@ void CastMessageBuilder::CompleteFrameReceived(uint32 frame_id) {
bool CastMessageBuilder::UpdateAckMessage(uint32 frame_id) {
if (!decoder_faster_than_max_frame_rate_) {
int complete_frame_count = frame_id_map_->NumberOfCompleteFrames();
int complete_frame_count = framer_->NumberOfCompleteFrames();
if (complete_frame_count > max_unacked_frames_) {
// We have too many frames pending in our framer; slow down ACK.
if (!slowing_down_ack_) {
......@@ -95,7 +96,7 @@ bool CastMessageBuilder::UpdateAckMessage(uint32 frame_id) {
bool CastMessageBuilder::TimeToSendNextCastMessage(
base::TimeTicks* time_to_send) {
// We haven't received any packets.
if (last_update_time_.is_null() && frame_id_map_->Empty())
if (last_update_time_.is_null() && framer_->Empty())
return false;
*time_to_send = last_update_time_ + base::TimeDelta::FromMilliseconds(
......@@ -120,7 +121,7 @@ void CastMessageBuilder::Reset() {
bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage* message) {
if (last_update_time_.is_null()) {
if (!frame_id_map_->Empty()) {
if (!framer_->Empty()) {
// We have received packets.
last_update_time_ = clock_->NowTicks();
}
......@@ -148,10 +149,10 @@ void CastMessageBuilder::BuildPacketList() {
cast_msg_.missing_frames_and_packets.clear();
// Are we missing packets?
if (frame_id_map_->Empty())
if (framer_->Empty())
return;
uint32 newest_frame_id = frame_id_map_->NewestFrameId();
uint32 newest_frame_id = framer_->NewestFrameId();
uint32 next_expected_frame_id = cast_msg_.ack_frame_id + 1;
// Iterate over all frames.
......@@ -169,9 +170,9 @@ void CastMessageBuilder::BuildPacketList() {
}
PacketIdSet missing;
if (frame_id_map_->FrameExists(next_expected_frame_id)) {
if (framer_->FrameExists(next_expected_frame_id)) {
bool last_frame = (newest_frame_id == next_expected_frame_id);
frame_id_map_->GetMissingPackets(
framer_->GetMissingPackets(
next_expected_frame_id, last_frame, &missing);
if (!missing.empty()) {
time_last_nacked_map_[next_expected_frame_id] = now;
......
......@@ -11,12 +11,12 @@
#include <map>
#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/net/rtp/frame_id_map.h"
#include "media/cast/net/rtp/rtp_receiver_defines.h"
namespace media {
namespace cast {
class Framer;
class RtpPayloadFeedback;
typedef std::map<uint32, base::TimeTicks> TimeLastNackMap;
......@@ -25,7 +25,7 @@ class CastMessageBuilder {
public:
CastMessageBuilder(base::TickClock* clock,
RtpPayloadFeedback* incoming_payload_feedback,
FrameIdMap* frame_id_map,
const Framer* framer,
uint32 media_ssrc,
bool decoder_faster_than_max_frame_rate,
int max_unacked_frames);
......@@ -44,8 +44,8 @@ class CastMessageBuilder {
base::TickClock* const clock_; // Not owned by this class.
RtpPayloadFeedback* const cast_feedback_;
// CastMessageBuilder has only const access to the frame id mapper.
const FrameIdMap* const frame_id_map_;
// CastMessageBuilder has only const access to the framer.
const Framer* const framer_;
const uint32 media_ssrc_;
const bool decoder_faster_than_max_frame_rate_;
const int max_unacked_frames_;
......
......@@ -8,6 +8,7 @@
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/net/rtp/cast_message_builder.h"
#include "media/cast/net/rtp/framer.h"
#include "media/cast/net/rtp/rtp_receiver_defines.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -82,9 +83,14 @@ class NackFeedbackVerification : public RtpPayloadFeedback {
class CastMessageBuilderTest : public ::testing::Test {
protected:
CastMessageBuilderTest()
: cast_msg_builder_(new CastMessageBuilder(&testing_clock_,
: framer_(&testing_clock_,
&feedback_,
kSsrc,
true,
10),
cast_msg_builder_(new CastMessageBuilder(&testing_clock_,
&feedback_,
&frame_id_map_,
&framer_,
kSsrc,
true,
0)) {
......@@ -110,8 +116,9 @@ class CastMessageBuilderTest : public ::testing::Test {
void SetKeyFrame(bool is_key) { rtp_header_.is_key_frame = is_key; }
void InsertPacket() {
PacketType packet_type = frame_id_map_.InsertPacket(rtp_header_);
if (packet_type == kNewPacketCompletingFrame) {
bool duplicate;
uint8 payload = 0;
if (framer_.InsertPacket(&payload, 1, rtp_header_, &duplicate)) {
cast_msg_builder_->CompleteFrameReceived(rtp_header_.frame_id);
}
cast_msg_builder_->UpdateCastMessage();
......@@ -120,16 +127,16 @@ class CastMessageBuilderTest : public ::testing::Test {
void SetDecoderSlowerThanMaxFrameRate(int max_unacked_frames) {
cast_msg_builder_.reset(new CastMessageBuilder(&testing_clock_,
&feedback_,
&frame_id_map_,
&framer_,
kSsrc,
false,
max_unacked_frames));
}
NackFeedbackVerification feedback_;
Framer framer_;
scoped_ptr<CastMessageBuilder> cast_msg_builder_;
RtpCastHeader rtp_header_;
FrameIdMap frame_id_map_;
base::SimpleTestTickClock testing_clock_;
DISALLOW_COPY_AND_ASSIGN(CastMessageBuilderTest);
......@@ -196,7 +203,7 @@ TEST_F(CastMessageBuilderTest, RemoveOldFrames) {
InsertPacket();
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
frame_id_map_.RemoveOldFrames(5); // Simulate 5 being pulled for rendering.
framer_.RemoveOldFrames(5); // Simulate 5 being pulled for rendering.
cast_msg_builder_->UpdateCastMessage();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(5u, feedback_.last_frame_acked());
......@@ -283,7 +290,7 @@ TEST_F(CastMessageBuilderTest, Reset) {
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
cast_msg_builder_->Reset();
frame_id_map_.Clear();
framer_.Reset();
// Should reset nack list state and request a key frame.
cast_msg_builder_->UpdateCastMessage();
EXPECT_TRUE(feedback_.triggered());
......@@ -325,7 +332,7 @@ TEST_F(CastMessageBuilderTest, BasicRps) {
EXPECT_EQ(3u, feedback_.last_frame_acked());
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering.
framer_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering.
cast_msg_builder_->UpdateCastMessage();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(3u, feedback_.last_frame_acked());
......@@ -357,7 +364,7 @@ TEST_F(CastMessageBuilderTest, InOrderRps) {
InsertPacket();
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs));
frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering.
framer_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering.
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs));
cast_msg_builder_->UpdateCastMessage();
......@@ -414,7 +421,7 @@ TEST_F(CastMessageBuilderTest, SlowDownAck) {
EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked());
// Simulate frame_id being pulled for rendering.
frame_id_map_.RemoveOldFrames(frame_id);
framer_.RemoveOldFrames(frame_id);
// We should now leave the slowdown ACK state.
++frame_id;
SetFrameIds(frame_id, frame_id - 1);
......
......@@ -13,6 +13,7 @@ FrameBuffer::FrameBuffer()
: frame_id_(0),
max_packet_id_(0),
num_packets_received_(0),
max_seen_packet_id_(0),
new_playout_delay_ms_(0),
is_key_frame_(false),
total_data_size_(0),
......@@ -21,7 +22,7 @@ FrameBuffer::FrameBuffer()
FrameBuffer::~FrameBuffer() {}
void FrameBuffer::InsertPacket(const uint8* payload_data,
bool FrameBuffer::InsertPacket(const uint8* payload_data,
size_t payload_size,
const RtpCastHeader& rtp_header) {
// Is this the first packet in the frame?
......@@ -37,11 +38,11 @@ void FrameBuffer::InsertPacket(const uint8* payload_data,
}
// Is this the correct frame?
if (rtp_header.frame_id != frame_id_)
return;
return false;
// Insert every packet only once.
if (packets_.find(rtp_header.packet_id) != packets_.end()) {
return;
return false;
}
std::vector<uint8> data;
......@@ -54,7 +55,9 @@ void FrameBuffer::InsertPacket(const uint8* payload_data,
payload_data, payload_data + payload_size, retval.first->second.begin());
++num_packets_received_;
max_seen_packet_id_ = std::max(max_seen_packet_id_, rtp_header.packet_id);
total_data_size_ += payload_size;
return true;
}
bool FrameBuffer::Complete() const {
......@@ -86,5 +89,28 @@ bool FrameBuffer::AssembleEncodedFrame(EncodedFrame* frame) const {
return true;
}
void FrameBuffer::GetMissingPackets(bool newest_frame,
PacketIdSet* missing_packets) const {
// Missing packets capped by max_seen_packet_id_.
// (Iff it's the latest frame)
int maximum = newest_frame ? max_seen_packet_id_ : max_packet_id_;
int packet = 0;
for (PacketMap::const_iterator i = packets_.begin();
i != packets_.end() && packet <= maximum;
++i) {
int end = std::min<int>(i->first, maximum + 1);
while (packet < end) {
missing_packets->insert(packet);
packet++;
}
packet++;
}
while (packet <= maximum) {
missing_packets->insert(packet);
packet++;
}
}
} // namespace cast
} // namespace media
......@@ -20,11 +20,13 @@ class FrameBuffer {
public:
FrameBuffer();
~FrameBuffer();
void InsertPacket(const uint8* payload_data,
bool InsertPacket(const uint8* payload_data,
size_t payload_size,
const RtpCastHeader& rtp_header);
bool Complete() const;
void GetMissingPackets(bool newest_frame, PacketIdSet* missing_packets) const;
// If a frame is complete, sets the frame IDs and RTP timestamp in |frame|,
// and also copies the data from all packets into the data field in |frame|.
// Returns true if the frame was complete; false if incomplete and |frame|
......@@ -32,13 +34,14 @@ class FrameBuffer {
bool AssembleEncodedFrame(EncodedFrame* frame) const;
bool is_key_frame() const { return is_key_frame_; }
uint32 last_referenced_frame_id() const { return last_referenced_frame_id_; }
uint32 frame_id() const { return frame_id_; }
private:
uint32 frame_id_;
uint16 max_packet_id_;
uint16 num_packets_received_;
uint16 max_seen_packet_id_;
uint16 new_playout_delay_ms_;
bool is_key_frame_;
size_t total_data_size_;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/cast/net/rtp/frame_id_map.h"
#include "base/logging.h"
#include "media/cast/net/rtp/rtp_receiver_defines.h"
namespace media {
namespace cast {
FrameInfo::FrameInfo(uint32 frame_id,
uint32 referenced_frame_id,
uint16 max_packet_id,
bool key_frame)
: is_key_frame_(key_frame),
frame_id_(frame_id),
referenced_frame_id_(referenced_frame_id),
max_received_packet_id_(0) {
// Create the set with all packets missing.
for (uint16 i = 0; i <= max_packet_id; i++) {
missing_packets_.insert(i);
}
}
FrameInfo::~FrameInfo() {}
PacketType FrameInfo::InsertPacket(uint16 packet_id) {
if (missing_packets_.find(packet_id) == missing_packets_.end()) {
return kDuplicatePacket;
}
// Update the last received packet id.
if (IsNewerPacketId(packet_id, max_received_packet_id_)) {
max_received_packet_id_ = packet_id;
}
missing_packets_.erase(packet_id);
return missing_packets_.empty() ? kNewPacketCompletingFrame : kNewPacket;
}
bool FrameInfo::Complete() const { return missing_packets_.empty(); }
void FrameInfo::GetMissingPackets(bool newest_frame,
PacketIdSet* missing_packets) const {
if (newest_frame) {
// Missing packets capped by max_received_packet_id_.
PacketIdSet::const_iterator it_after_last_received =
missing_packets_.lower_bound(max_received_packet_id_);
missing_packets->insert(missing_packets_.begin(), it_after_last_received);
} else {
missing_packets->insert(missing_packets_.begin(), missing_packets_.end());
}
}
FrameIdMap::FrameIdMap()
: waiting_for_key_(true),
last_released_frame_(kStartFrameId),
newest_frame_id_(kStartFrameId) {}
FrameIdMap::~FrameIdMap() {}
PacketType FrameIdMap::InsertPacket(const RtpCastHeader& rtp_header) {
uint32 frame_id = rtp_header.frame_id;
uint32 reference_frame_id;
reference_frame_id = rtp_header.reference_frame_id;
if (rtp_header.is_key_frame && waiting_for_key_) {
last_released_frame_ = static_cast<uint32>(frame_id - 1);
waiting_for_key_ = false;
}
VLOG(3) << "InsertPacket frame:" << frame_id
<< " packet:" << static_cast<int>(rtp_header.packet_id)
<< " max packet:" << static_cast<int>(rtp_header.max_packet_id);
if (IsOlderFrameId(frame_id, last_released_frame_) && !waiting_for_key_) {
return kTooOldPacket;
}
// Update the last received frame id.
if (IsNewerFrameId(frame_id, newest_frame_id_)) {
newest_frame_id_ = frame_id;
}
// Does this packet belong to a new frame?
FrameMap::iterator it = frame_map_.find(frame_id);
PacketType packet_type;
if (it == frame_map_.end()) {
// New frame.
linked_ptr<FrameInfo> frame_info(new FrameInfo(frame_id,
reference_frame_id,
rtp_header.max_packet_id,
rtp_header.is_key_frame));
std::pair<FrameMap::iterator, bool> retval =
frame_map_.insert(std::make_pair(frame_id, frame_info));
packet_type = retval.first->second->InsertPacket(rtp_header.packet_id);
} else {
// Insert packet to existing frame.
packet_type = it->second->InsertPacket(rtp_header.packet_id);
}
return packet_type;
}
void FrameIdMap::RemoveOldFrames(uint32 frame_id) {
FrameMap::iterator it = frame_map_.begin();
while (it != frame_map_.end()) {
if (IsNewerFrameId(it->first, frame_id)) {
++it;
} else {
// Older or equal; erase.
frame_map_.erase(it++);
}
}
last_released_frame_ = frame_id;
}
void FrameIdMap::Clear() {
frame_map_.clear();
waiting_for_key_ = true;
last_released_frame_ = kStartFrameId;
newest_frame_id_ = kStartFrameId;
}
uint32 FrameIdMap::NewestFrameId() const { return newest_frame_id_; }
bool FrameIdMap::NextContinuousFrame(uint32* frame_id) const {
FrameMap::const_iterator it;
for (it = frame_map_.begin(); it != frame_map_.end(); ++it) {
if (it->second->Complete() && ContinuousFrame(it->second.get())) {
*frame_id = it->first;
return true;
}
}
return false;
}
bool FrameIdMap::HaveMultipleDecodableFrames() const {
// Find the oldest decodable frame.
FrameMap::const_iterator it;
bool found_one = false;
for (it = frame_map_.begin(); it != frame_map_.end(); ++it) {
if (it->second->Complete() && DecodableFrame(it->second.get())) {
if (found_one) {
return true;
} else {
found_one = true;
}
}
}
return false;
}
uint32 FrameIdMap::LastContinuousFrame() const {
uint32 last_continuous_frame_id = last_released_frame_;
uint32 next_expected_frame = last_released_frame_;
FrameMap::const_iterator it;
do {
next_expected_frame++;
it = frame_map_.find(next_expected_frame);
if (it == frame_map_.end())
break;
if (!it->second->Complete())
break;
// We found the next continuous frame.
last_continuous_frame_id = it->first;
} while (next_expected_frame != newest_frame_id_);
return last_continuous_frame_id;
}
bool FrameIdMap::NextFrameAllowingSkippingFrames(uint32* frame_id) const {
// Find the oldest decodable frame.
FrameMap::const_iterator it_best_match = frame_map_.end();
FrameMap::const_iterator it;
for (it = frame_map_.begin(); it != frame_map_.end(); ++it) {
if (it->second->Complete() && DecodableFrame(it->second.get())) {
if (it_best_match == frame_map_.end() ||
IsOlderFrameId(it->first, it_best_match->first)) {
it_best_match = it;
}
}
}
if (it_best_match == frame_map_.end())
return false;
*frame_id = it_best_match->first;
return true;
}
bool FrameIdMap::Empty() const { return frame_map_.empty(); }
int FrameIdMap::NumberOfCompleteFrames() const {
int count = 0;
FrameMap::const_iterator it;
for (it = frame_map_.begin(); it != frame_map_.end(); ++it) {
if (it->second->Complete()) {
++count;
}
}
return count;
}
bool FrameIdMap::FrameExists(uint32 frame_id) const {
return frame_map_.end() != frame_map_.find(frame_id);
}
void FrameIdMap::GetMissingPackets(uint32 frame_id,
bool last_frame,
PacketIdSet* missing_packets) const {
FrameMap::const_iterator it = frame_map_.find(frame_id);
if (it == frame_map_.end())
return;
it->second->GetMissingPackets(last_frame, missing_packets);
}
bool FrameIdMap::ContinuousFrame(FrameInfo* frame) const {
DCHECK(frame);
if (waiting_for_key_ && !frame->is_key_frame())
return false;
return static_cast<uint32>(last_released_frame_ + 1) == frame->frame_id();
}
bool FrameIdMap::DecodableFrame(FrameInfo* frame) const {
if (frame->is_key_frame())
return true;
if (waiting_for_key_ && !frame->is_key_frame())
return false;
// Self-reference?
if (frame->referenced_frame_id() == frame->frame_id())
return true;
// Current frame is not necessarily referencing the last frame.
// Do we have the reference frame?
if (IsOlderFrameId(frame->referenced_frame_id(), last_released_frame_)) {
return true;
}
return frame->referenced_frame_id() == last_released_frame_;
}
} // namespace cast
} // namespace media
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_CAST_FRAMER_FRAME_ID_MAP_H_
#define MEDIA_CAST_FRAMER_FRAME_ID_MAP_H_
#include <map>
#include <set>
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "media/cast/cast_config.h"
#include "media/cast/net/rtcp/rtcp_defines.h"
#include "media/cast/net/rtp/rtp_receiver_defines.h"
namespace media {
namespace cast {
class FrameInfo {
public:
FrameInfo(uint32 frame_id,
uint32 referenced_frame_id,
uint16 max_packet_id,
bool key_frame);
~FrameInfo();
PacketType InsertPacket(uint16 packet_id);
bool Complete() const;
void GetMissingPackets(bool newest_frame, PacketIdSet* missing_packets) const;
bool is_key_frame() const { return is_key_frame_; }
uint32 frame_id() const { return frame_id_; }
uint32 referenced_frame_id() const { return referenced_frame_id_; }
private:
const bool is_key_frame_;
const uint32 frame_id_;
const uint32 referenced_frame_id_;
uint16 max_received_packet_id_;
PacketIdSet missing_packets_;
DISALLOW_COPY_AND_ASSIGN(FrameInfo);
};
typedef std::map<uint32, linked_ptr<FrameInfo> > FrameMap;
class FrameIdMap {
public:
FrameIdMap();
~FrameIdMap();
PacketType InsertPacket(const RtpCastHeader& rtp_header);
bool Empty() const;
bool FrameExists(uint32 frame_id) const;
uint32 NewestFrameId() const;
void RemoveOldFrames(uint32 frame_id);
void Clear();
// Identifies the next frame to be released (rendered).
bool NextContinuousFrame(uint32* frame_id) const;
uint32 LastContinuousFrame() const;
bool NextFrameAllowingSkippingFrames(uint32* frame_id) const;
bool HaveMultipleDecodableFrames() const;
int NumberOfCompleteFrames() const;
void GetMissingPackets(uint32 frame_id,
bool last_frame,
PacketIdSet* missing_packets) const;
private:
bool ContinuousFrame(FrameInfo* frame) const;
bool DecodableFrame(FrameInfo* frame) const;
FrameMap frame_map_;
bool waiting_for_key_;
uint32 last_released_frame_;
uint32 newest_frame_id_;
DISALLOW_COPY_AND_ASSIGN(FrameIdMap);
};
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_FRAMER_FRAME_ID_MAP_H_
......@@ -20,10 +20,13 @@ Framer::Framer(base::TickClock* clock,
cast_msg_builder_(
new CastMessageBuilder(clock,
incoming_payload_feedback,
&frame_id_map_,
this,
ssrc,
decoder_faster_than_max_frame_rate,
max_unacked_frames)) {
max_unacked_frames)),
waiting_for_key_(true),
last_released_frame_(kStartFrameId),
newest_frame_id_(kStartFrameId) {
DCHECK(incoming_payload_feedback) << "Invalid argument";
}
......@@ -34,42 +37,58 @@ bool Framer::InsertPacket(const uint8* payload_data,
const RtpCastHeader& rtp_header,
bool* duplicate) {
*duplicate = false;
PacketType packet_type = frame_id_map_.InsertPacket(rtp_header);
if (packet_type == kTooOldPacket) {
return false;
uint32 frame_id = rtp_header.frame_id;
if (rtp_header.is_key_frame && waiting_for_key_) {
last_released_frame_ = static_cast<uint32>(frame_id - 1);
waiting_for_key_ = false;
}
if (packet_type == kDuplicatePacket) {
VLOG(3) << "Packet already received, ignored: frame "
<< static_cast<int>(rtp_header.frame_id) << ", packet "
<< rtp_header.packet_id;
*duplicate = true;
VLOG(0) << "InsertPacket frame:" << frame_id
<< " packet:" << static_cast<int>(rtp_header.packet_id)
<< " max packet:" << static_cast<int>(rtp_header.max_packet_id);
if (IsOlderFrameId(frame_id, last_released_frame_) && !waiting_for_key_) {
// Packet is too old.
return false;
}
// Update the last received frame id.
if (IsNewerFrameId(frame_id, newest_frame_id_)) {
newest_frame_id_ = frame_id;
}
// Does this packet belong to a new frame?
FrameList::iterator it = frames_.find(rtp_header.frame_id);
FrameList::iterator it = frames_.find(frame_id);
if (it == frames_.end()) {
// New frame.
linked_ptr<FrameBuffer> frame_buffer(new FrameBuffer());
frame_buffer->InsertPacket(payload_data, payload_size, rtp_header);
frames_.insert(std::make_pair(rtp_header.frame_id, frame_buffer));
} else {
// Insert packet to existing frame buffer.
it->second->InsertPacket(payload_data, payload_size, rtp_header);
linked_ptr<FrameBuffer> frame_info(new FrameBuffer);
std::pair<FrameList::iterator, bool> retval =
frames_.insert(std::make_pair(frame_id, frame_info));
it = retval.first;
}
// Insert packet.
if (!it->second->InsertPacket(payload_data, payload_size, rtp_header)) {
VLOG(3) << "Packet already received, ignored: frame "
<< static_cast<int>(rtp_header.frame_id) << ", packet "
<< rtp_header.packet_id;
*duplicate = true;
return false;
}
return packet_type == kNewPacketCompletingFrame;
return it->second->Complete();
}
// This does not release the frame.
bool Framer::GetEncodedFrame(EncodedFrame* frame,
bool* next_frame,
bool* have_multiple_decodable_frames) {
*have_multiple_decodable_frames = frame_id_map_.HaveMultipleDecodableFrames();
*have_multiple_decodable_frames = HaveMultipleDecodableFrames();
uint32 frame_id;
// Find frame id.
if (frame_id_map_.NextContinuousFrame(&frame_id)) {
if (NextContinuousFrame(&frame_id)) {
// We have our next frame.
*next_frame = true;
} else {
......@@ -77,7 +96,7 @@ bool Framer::GetEncodedFrame(EncodedFrame* frame,
if (!decoder_faster_than_max_frame_rate_)
return false;
if (!frame_id_map_.NextFrameAllowingSkippingFrames(&frame_id)) {
if (!NextFrameAllowingSkippingFrames(&frame_id)) {
return false;
}
*next_frame = false;
......@@ -97,13 +116,15 @@ void Framer::AckFrame(uint32 frame_id) {
}
void Framer::Reset() {
frame_id_map_.Clear();
waiting_for_key_ = true;
last_released_frame_ = kStartFrameId;
newest_frame_id_ = kStartFrameId;
frames_.clear();
cast_msg_builder_->Reset();
}
void Framer::ReleaseFrame(uint32 frame_id) {
frame_id_map_.RemoveOldFrames(frame_id);
RemoveOldFrames(frame_id);
frames_.erase(frame_id);
// We have a frame - remove all frames with lower frame id.
......@@ -128,5 +149,140 @@ bool Framer::TimeToSendNextCastMessage(base::TimeTicks* time_to_send) {
void Framer::SendCastMessage() { cast_msg_builder_->UpdateCastMessage(); }
void Framer::RemoveOldFrames(uint32 frame_id) {
FrameList::iterator it = frames_.begin();
while (it != frames_.end()) {
if (IsNewerFrameId(it->first, frame_id)) {
++it;
} else {
// Older or equal; erase.
frames_.erase(it++);
}
}
last_released_frame_ = frame_id;
}
uint32 Framer::NewestFrameId() const { return newest_frame_id_; }
bool Framer::NextContinuousFrame(uint32* frame_id) const {
FrameList::const_iterator it;
for (it = frames_.begin(); it != frames_.end(); ++it) {
if (it->second->Complete() && ContinuousFrame(it->second.get())) {
*frame_id = it->first;
return true;
}
}
return false;
}
bool Framer::HaveMultipleDecodableFrames() const {
// Find the oldest decodable frame.
FrameList::const_iterator it;
bool found_one = false;
for (it = frames_.begin(); it != frames_.end(); ++it) {
if (it->second->Complete() && DecodableFrame(it->second.get())) {
if (found_one) {
return true;
} else {
found_one = true;
}
}
}
return false;
}
uint32 Framer::LastContinuousFrame() const {
uint32 last_continuous_frame_id = last_released_frame_;
uint32 next_expected_frame = last_released_frame_;
FrameList::const_iterator it;
do {
next_expected_frame++;
it = frames_.find(next_expected_frame);
if (it == frames_.end())
break;
if (!it->second->Complete())
break;
// We found the next continuous frame.
last_continuous_frame_id = it->first;
} while (next_expected_frame != newest_frame_id_);
return last_continuous_frame_id;
}
bool Framer::NextFrameAllowingSkippingFrames(uint32* frame_id) const {
// Find the oldest decodable frame.
FrameList::const_iterator it_best_match = frames_.end();
FrameList::const_iterator it;
for (it = frames_.begin(); it != frames_.end(); ++it) {
if (it->second->Complete() && DecodableFrame(it->second.get())) {
if (it_best_match == frames_.end() ||
IsOlderFrameId(it->first, it_best_match->first)) {
it_best_match = it;
}
}
}
if (it_best_match == frames_.end())
return false;
*frame_id = it_best_match->first;
return true;
}
bool Framer::Empty() const { return frames_.empty(); }
int Framer::NumberOfCompleteFrames() const {
int count = 0;
FrameList::const_iterator it;
for (it = frames_.begin(); it != frames_.end(); ++it) {
if (it->second->Complete()) {
++count;
}
}
return count;
}
bool Framer::FrameExists(uint32 frame_id) const {
return frames_.end() != frames_.find(frame_id);
}
void Framer::GetMissingPackets(uint32 frame_id,
bool last_frame,
PacketIdSet* missing_packets) const {
FrameList::const_iterator it = frames_.find(frame_id);
if (it == frames_.end())
return;
it->second->GetMissingPackets(last_frame, missing_packets);
}
bool Framer::ContinuousFrame(FrameBuffer* frame) const {
DCHECK(frame);
if (waiting_for_key_ && !frame->is_key_frame())
return false;
return static_cast<uint32>(last_released_frame_ + 1) == frame->frame_id();
}
bool Framer::DecodableFrame(FrameBuffer* frame) const {
if (frame->is_key_frame())
return true;
if (waiting_for_key_ && !frame->is_key_frame())
return false;
// Self-reference?
if (frame->last_referenced_frame_id() == frame->frame_id())
return true;
// Current frame is not necessarily referencing the last frame.
// Do we have the reference frame?
if (IsOlderFrameId(frame->last_referenced_frame_id(), last_released_frame_)) {
return true;
}
return frame->last_referenced_frame_id() == last_released_frame_;
}
} // namespace cast
} // namespace media
......@@ -15,7 +15,6 @@
#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/net/rtp/cast_message_builder.h"
#include "media/cast/net/rtp/frame_buffer.h"
#include "media/cast/net/rtp/frame_id_map.h"
#include "media/cast/net/rtp/rtp_receiver_defines.h"
namespace media {
......@@ -59,12 +58,34 @@ class Framer {
bool TimeToSendNextCastMessage(base::TimeTicks* time_to_send);
void SendCastMessage();
bool Empty() const;
bool FrameExists(uint32 frame_id) const;
uint32 NewestFrameId() const;
void RemoveOldFrames(uint32 frame_id);
// Identifies the next frame to be released (rendered).
bool NextContinuousFrame(uint32* frame_id) const;
uint32 LastContinuousFrame() const;
bool NextFrameAllowingSkippingFrames(uint32* frame_id) const;
bool HaveMultipleDecodableFrames() const;
int NumberOfCompleteFrames() const;
void GetMissingPackets(uint32 frame_id,
bool last_frame,
PacketIdSet* missing_packets) const;
private:
bool ContinuousFrame(FrameBuffer* frame) const;
bool DecodableFrame(FrameBuffer* frame) const;
const bool decoder_faster_than_max_frame_rate_;
FrameList frames_;
FrameIdMap frame_id_map_;
scoped_ptr<CastMessageBuilder> cast_msg_builder_;
bool waiting_for_key_;
uint32 last_released_frame_;
uint32 newest_frame_id_;
DISALLOW_COPY_AND_ASSIGN(Framer);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment