Commit b6e2be31 authored by hubbe@chromium.org's avatar hubbe@chromium.org

Cast: Only ACK decododable frames

Also, add an optimization to not decode frames if we are behind and multiple frames are currently decodable.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272709 0039d316-1c4b-4281-b951-d872f2087c98
parent 8304f61a
...@@ -169,19 +169,29 @@ void AudioReceiver::EmitAvailableEncodedFrames() { ...@@ -169,19 +169,29 @@ void AudioReceiver::EmitAvailableEncodedFrames() {
scoped_ptr<transport::EncodedFrame> encoded_frame( scoped_ptr<transport::EncodedFrame> encoded_frame(
new transport::EncodedFrame()); new transport::EncodedFrame());
bool is_consecutively_next_frame = false; bool is_consecutively_next_frame = false;
if (!framer_.GetEncodedAudioFrame(encoded_frame.get(), bool have_multiple_complete_frames = false;
&is_consecutively_next_frame)) { if (!framer_.GetEncodedFrame(encoded_frame.get(),
&is_consecutively_next_frame,
&have_multiple_complete_frames)) {
VLOG(1) << "Wait for more audio packets to produce a completed frame."; VLOG(1) << "Wait for more audio packets to produce a completed frame.";
return; // OnReceivedPayloadData() will invoke this method in the future. return; // OnReceivedPayloadData() will invoke this method in the future.
} }
const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
const base::TimeTicks playout_time =
GetPlayoutTime(now, encoded_frame->rtp_timestamp);
// If we have multiple decodable frames, and the current frame is
// too old, then skip it and decode the next frame instead.
if (have_multiple_complete_frames && now > playout_time) {
framer_.ReleaseFrame(encoded_frame->frame_id);
continue;
}
// If |framer_| has a frame ready that is out of sequence, examine the // If |framer_| has a frame ready that is out of sequence, examine the
// playout time to determine whether it's acceptable to continue, thereby // playout time to determine whether it's acceptable to continue, thereby
// skipping one or more frames. Skip if the missing frame wouldn't complete // skipping one or more frames. Skip if the missing frame wouldn't complete
// playing before the start of playback of the available frame. // playing before the start of playback of the available frame.
const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
const base::TimeTicks playout_time =
GetPlayoutTime(now, encoded_frame->rtp_timestamp);
if (!is_consecutively_next_frame) { if (!is_consecutively_next_frame) {
// TODO(miu): Also account for expected decode time here? // TODO(miu): Also account for expected decode time here?
const base::TimeTicks earliest_possible_end_time_of_missing_frame = const base::TimeTicks earliest_possible_end_time_of_missing_frame =
......
...@@ -23,7 +23,6 @@ CastMessageBuilder::CastMessageBuilder( ...@@ -23,7 +23,6 @@ CastMessageBuilder::CastMessageBuilder(
decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate), decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate),
max_unacked_frames_(max_unacked_frames), max_unacked_frames_(max_unacked_frames),
cast_msg_(media_ssrc), cast_msg_(media_ssrc),
waiting_for_key_frame_(true),
slowing_down_ack_(false), slowing_down_ack_(false),
acked_last_frame_(true), acked_last_frame_(true),
last_acked_frame_id_(kStartFrameId) { last_acked_frame_id_(kStartFrameId) {
...@@ -32,67 +31,61 @@ CastMessageBuilder::CastMessageBuilder( ...@@ -32,67 +31,61 @@ CastMessageBuilder::CastMessageBuilder(
CastMessageBuilder::~CastMessageBuilder() {} CastMessageBuilder::~CastMessageBuilder() {}
void CastMessageBuilder::CompleteFrameReceived(uint32 frame_id, void CastMessageBuilder::CompleteFrameReceived(uint32 frame_id) {
bool is_key_frame) { DCHECK_GE(static_cast<int32>(frame_id - last_acked_frame_id_), 0);
VLOG(2) << "CompleteFrameReceived: " << frame_id;
if (last_update_time_.is_null()) { if (last_update_time_.is_null()) {
// Our first update. // Our first update.
last_update_time_ = clock_->NowTicks(); last_update_time_ = clock_->NowTicks();
} }
if (waiting_for_key_frame_) {
if (!is_key_frame) { if (!UpdateAckMessage(frame_id)) {
// Ignore that we have received this complete frame since we are
// waiting on a key frame.
return; return;
} }
waiting_for_key_frame_ = false;
cast_msg_.missing_frames_and_packets_.clear();
cast_msg_.ack_frame_id_ = frame_id;
last_update_time_ = clock_->NowTicks();
// We might have other complete frames waiting after we receive the last
// packet in the key-frame.
UpdateAckMessage();
} else {
if (!UpdateAckMessage())
return;
BuildPacketList(); BuildPacketList();
}
// Send cast message. // Send cast message.
VLOG(2) << "Send cast message Ack:" << static_cast<int>(frame_id); VLOG(2) << "Send cast message Ack:" << static_cast<int>(frame_id);
cast_feedback_->CastFeedback(cast_msg_); cast_feedback_->CastFeedback(cast_msg_);
} }
bool CastMessageBuilder::UpdateAckMessage() { bool CastMessageBuilder::UpdateAckMessage(uint32 frame_id) {
if (!decoder_faster_than_max_frame_rate_) { if (!decoder_faster_than_max_frame_rate_) {
int complete_frame_count = frame_id_map_->NumberOfCompleteFrames(); int complete_frame_count = frame_id_map_->NumberOfCompleteFrames();
if (complete_frame_count > max_unacked_frames_) { if (complete_frame_count > max_unacked_frames_) {
// We have too many frames pending in our framer; slow down ACK. // We have too many frames pending in our framer; slow down ACK.
if (!slowing_down_ack_) {
slowing_down_ack_ = true; slowing_down_ack_ = true;
ack_queue_.push_back(last_acked_frame_id_);
}
} else if (complete_frame_count <= 1) { } else if (complete_frame_count <= 1) {
// We are down to one or less frames in our framer; ACK normally. // We are down to one or less frames in our framer; ACK normally.
slowing_down_ack_ = false; slowing_down_ack_ = false;
ack_queue_.clear();
} }
} }
if (slowing_down_ack_) { if (slowing_down_ack_) {
// We are slowing down acknowledgment by acknowledging every other frame. // We are slowing down acknowledgment by acknowledging every other frame.
if (acked_last_frame_) {
acked_last_frame_ = false;
} else {
acked_last_frame_ = true;
last_acked_frame_id_++;
// Note: frame skipping and slowdown ACK is not supported at the same // Note: frame skipping and slowdown ACK is not supported at the same
// time; and it's not needed since we can skip frames to catch up. // time; and it's not needed since we can skip frames to catch up.
if (!ack_queue_.empty() && ack_queue_.back() == frame_id) {
return false;
}
ack_queue_.push_back(frame_id);
if (!acked_last_frame_) {
ack_queue_.pop_front();
}
frame_id = ack_queue_.front();
} }
} else {
uint32 frame_id = frame_id_map_->LastContinuousFrame();
acked_last_frame_ = false;
// Is it a new frame? // Is it a new frame?
if (last_acked_frame_id_ == frame_id) if (last_acked_frame_id_ == frame_id) {
return false; return false;
last_acked_frame_id_ = frame_id;
acked_last_frame_ = true;
} }
acked_last_frame_ = true;
last_acked_frame_id_ = frame_id;
cast_msg_.ack_frame_id_ = last_acked_frame_id_; cast_msg_.ack_frame_id_ = last_acked_frame_id_;
cast_msg_.missing_frames_and_packets_.clear(); cast_msg_.missing_frames_and_packets_.clear();
last_update_time_ = clock_->NowTicks(); last_update_time_ = clock_->NowTicks();
...@@ -120,7 +113,6 @@ void CastMessageBuilder::UpdateCastMessage() { ...@@ -120,7 +113,6 @@ void CastMessageBuilder::UpdateCastMessage() {
} }
void CastMessageBuilder::Reset() { void CastMessageBuilder::Reset() {
waiting_for_key_frame_ = true;
cast_msg_.ack_frame_id_ = kStartFrameId; cast_msg_.ack_frame_id_ = kStartFrameId;
cast_msg_.missing_frames_and_packets_.clear(); cast_msg_.missing_frames_and_packets_.clear();
time_last_nacked_map_.clear(); time_last_nacked_map_.clear();
...@@ -142,7 +134,8 @@ bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage* message) { ...@@ -142,7 +134,8 @@ bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage* message) {
} }
last_update_time_ = now; last_update_time_ = now;
UpdateAckMessage(); // Needed to cover when a frame is skipped. // Needed to cover when a frame is skipped.
UpdateAckMessage(last_acked_frame_id_);
BuildPacketList(); BuildPacketList();
message->Copy(cast_msg_); message->Copy(cast_msg_);
return true; return true;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#ifndef MEDIA_CAST_FRAMER_CAST_MESSAGE_BUILDER_H_ #ifndef MEDIA_CAST_FRAMER_CAST_MESSAGE_BUILDER_H_
#define MEDIA_CAST_FRAMER_CAST_MESSAGE_BUILDER_H_ #define MEDIA_CAST_FRAMER_CAST_MESSAGE_BUILDER_H_
#include <deque>
#include <map> #include <map>
#include "media/cast/framer/frame_id_map.h" #include "media/cast/framer/frame_id_map.h"
...@@ -30,13 +31,13 @@ class CastMessageBuilder { ...@@ -30,13 +31,13 @@ class CastMessageBuilder {
int max_unacked_frames); int max_unacked_frames);
~CastMessageBuilder(); ~CastMessageBuilder();
void CompleteFrameReceived(uint32 frame_id, bool is_key_frame); void CompleteFrameReceived(uint32 frame_id);
bool TimeToSendNextCastMessage(base::TimeTicks* time_to_send); bool TimeToSendNextCastMessage(base::TimeTicks* time_to_send);
void UpdateCastMessage(); void UpdateCastMessage();
void Reset(); void Reset();
private: private:
bool UpdateAckMessage(); bool UpdateAckMessage(uint32 frame_id);
void BuildPacketList(); void BuildPacketList();
bool UpdateCastMessageInternal(RtcpCastMessage* message); bool UpdateCastMessageInternal(RtcpCastMessage* message);
...@@ -51,13 +52,13 @@ class CastMessageBuilder { ...@@ -51,13 +52,13 @@ class CastMessageBuilder {
RtcpCastMessage cast_msg_; RtcpCastMessage cast_msg_;
base::TimeTicks last_update_time_; base::TimeTicks last_update_time_;
bool waiting_for_key_frame_;
TimeLastNackMap time_last_nacked_map_; TimeLastNackMap time_last_nacked_map_;
bool slowing_down_ack_; bool slowing_down_ack_;
bool acked_last_frame_; bool acked_last_frame_;
uint32 last_acked_frame_id_; uint32 last_acked_frame_id_;
std::deque<uint32> ack_queue_;
DISALLOW_COPY_AND_ASSIGN(CastMessageBuilder); DISALLOW_COPY_AND_ASSIGN(CastMessageBuilder);
}; };
......
...@@ -112,8 +112,7 @@ class CastMessageBuilderTest : public ::testing::Test { ...@@ -112,8 +112,7 @@ class CastMessageBuilderTest : public ::testing::Test {
void InsertPacket() { void InsertPacket() {
PacketType packet_type = frame_id_map_.InsertPacket(rtp_header_); PacketType packet_type = frame_id_map_.InsertPacket(rtp_header_);
if (packet_type == kNewPacketCompletingFrame) { if (packet_type == kNewPacketCompletingFrame) {
cast_msg_builder_->CompleteFrameReceived(rtp_header_.frame_id, cast_msg_builder_->CompleteFrameReceived(rtp_header_.frame_id);
rtp_header_.is_key_frame);
} }
cast_msg_builder_->UpdateCastMessage(); cast_msg_builder_->UpdateCastMessage();
} }
...@@ -136,26 +135,6 @@ class CastMessageBuilderTest : public ::testing::Test { ...@@ -136,26 +135,6 @@ class CastMessageBuilderTest : public ::testing::Test {
DISALLOW_COPY_AND_ASSIGN(CastMessageBuilderTest); DISALLOW_COPY_AND_ASSIGN(CastMessageBuilderTest);
}; };
TEST_F(CastMessageBuilderTest, StartWithAKeyFrame) {
SetFrameIds(3, 2);
SetPacketId(0);
SetMaxPacketId(0);
InsertPacket();
// Should not trigger ack.
EXPECT_FALSE(feedback_.triggered());
SetFrameIds(5, 5);
SetPacketId(0);
SetMaxPacketId(0);
SetKeyFrame(true);
InsertPacket();
frame_id_map_.RemoveOldFrames(5); // Simulate 5 being pulled for rendering.
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
cast_msg_builder_->UpdateCastMessage();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(5u, feedback_.last_frame_acked());
}
TEST_F(CastMessageBuilderTest, OneFrameNackList) { TEST_F(CastMessageBuilderTest, OneFrameNackList) {
SetFrameIds(0, 0); SetFrameIds(0, 0);
SetPacketId(4); SetPacketId(4);
...@@ -187,31 +166,6 @@ TEST_F(CastMessageBuilderTest, CompleteFrameMissing) { ...@@ -187,31 +166,6 @@ TEST_F(CastMessageBuilderTest, CompleteFrameMissing) {
EXPECT_EQ(kRtcpCastAllPacketsLost, feedback_.num_missing_packets(1)); EXPECT_EQ(kRtcpCastAllPacketsLost, feedback_.num_missing_packets(1));
} }
TEST_F(CastMessageBuilderTest, FastForwardAck) {
SetFrameIds(1, 0);
SetPacketId(0);
SetMaxPacketId(0);
InsertPacket();
EXPECT_FALSE(feedback_.triggered());
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
SetFrameIds(2, 1);
SetPacketId(0);
SetMaxPacketId(0);
InsertPacket();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(kStartFrameId, feedback_.last_frame_acked());
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
SetFrameIds(0, 0);
SetPacketId(0);
SetMaxPacketId(0);
SetKeyFrame(true);
InsertPacket();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(2u, feedback_.last_frame_acked());
}
TEST_F(CastMessageBuilderTest, RemoveOldFrames) { TEST_F(CastMessageBuilderTest, RemoveOldFrames) {
SetFrameIds(1, 0); SetFrameIds(1, 0);
SetPacketId(0); SetPacketId(0);
...@@ -232,7 +186,7 @@ TEST_F(CastMessageBuilderTest, RemoveOldFrames) { ...@@ -232,7 +186,7 @@ TEST_F(CastMessageBuilderTest, RemoveOldFrames) {
SetMaxPacketId(5); SetMaxPacketId(5);
InsertPacket(); InsertPacket();
EXPECT_TRUE(feedback_.triggered()); EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(kStartFrameId, feedback_.last_frame_acked()); EXPECT_EQ(2u, feedback_.last_frame_acked());
testing_clock_.Advance( testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
SetFrameIds(5, 5); SetFrameIds(5, 5);
...@@ -260,42 +214,6 @@ TEST_F(CastMessageBuilderTest, RemoveOldFrames) { ...@@ -260,42 +214,6 @@ TEST_F(CastMessageBuilderTest, RemoveOldFrames) {
EXPECT_EQ(5u, feedback_.last_frame_acked()); EXPECT_EQ(5u, feedback_.last_frame_acked());
} }
TEST_F(CastMessageBuilderTest, WrapFastForward) {
SetFrameIds(254, 254);
SetPacketId(0);
SetMaxPacketId(1);
SetKeyFrame(true);
InsertPacket();
EXPECT_FALSE(feedback_.triggered());
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
SetFrameIds(255, 254);
SetPacketId(0);
SetMaxPacketId(0);
SetKeyFrame(false);
InsertPacket();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(253u, feedback_.last_frame_acked());
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
SetFrameIds(256, 255);
SetPacketId(0);
SetMaxPacketId(0);
SetKeyFrame(false);
InsertPacket();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(253u, feedback_.last_frame_acked());
testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
SetFrameIds(254, 254);
SetPacketId(1);
SetMaxPacketId(1);
SetKeyFrame(true);
InsertPacket();
EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(256u, feedback_.last_frame_acked());
}
TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacket) { TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacket) {
SetFrameIds(0, 0); SetFrameIds(0, 0);
SetPacketId(0); SetPacketId(0);
...@@ -404,7 +322,7 @@ TEST_F(CastMessageBuilderTest, BasicRps) { ...@@ -404,7 +322,7 @@ TEST_F(CastMessageBuilderTest, BasicRps) {
SetKeyFrame(false); SetKeyFrame(false);
InsertPacket(); InsertPacket();
EXPECT_TRUE(feedback_.triggered()); EXPECT_TRUE(feedback_.triggered());
EXPECT_EQ(0u, feedback_.last_frame_acked()); EXPECT_EQ(3u, feedback_.last_frame_acked());
testing_clock_.Advance( testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs));
frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering. frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering.
...@@ -480,16 +398,19 @@ TEST_F(CastMessageBuilderTest, SlowDownAck) { ...@@ -480,16 +398,19 @@ TEST_F(CastMessageBuilderTest, SlowDownAck) {
// We should now have entered the slowdown ACK state. // We should now have entered the slowdown ACK state.
uint32 expected_frame_id = 1; uint32 expected_frame_id = 1;
for (; frame_id < 10; ++frame_id) { for (; frame_id < 10; ++frame_id) {
if (frame_id % 2) if (frame_id % 2) {
++expected_frame_id; ++expected_frame_id;
EXPECT_TRUE(feedback_.triggered()); EXPECT_TRUE(feedback_.triggered());
} else {
EXPECT_FALSE(feedback_.triggered());
}
EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked()); EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked());
SetFrameIds(frame_id, frame_id - 1); SetFrameIds(frame_id, frame_id - 1);
InsertPacket(); InsertPacket();
testing_clock_.Advance( testing_clock_.Advance(
base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs));
} }
EXPECT_TRUE(feedback_.triggered()); EXPECT_FALSE(feedback_.triggered());
EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked()); EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked());
// Simulate frame_id being pulled for rendering. // Simulate frame_id being pulled for rendering.
......
...@@ -137,6 +137,22 @@ bool FrameIdMap::NextContinuousFrame(uint32* frame_id) const { ...@@ -137,6 +137,22 @@ bool FrameIdMap::NextContinuousFrame(uint32* frame_id) const {
return false; 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 FrameIdMap::LastContinuousFrame() const {
uint32 last_continuous_frame_id = last_released_frame_; uint32 last_continuous_frame_id = last_released_frame_;
uint32 next_expected_frame = last_released_frame_; uint32 next_expected_frame = last_released_frame_;
...@@ -157,44 +173,17 @@ uint32 FrameIdMap::LastContinuousFrame() const { ...@@ -157,44 +173,17 @@ uint32 FrameIdMap::LastContinuousFrame() const {
return last_continuous_frame_id; return last_continuous_frame_id;
} }
bool FrameIdMap::NextAudioFrameAllowingMissingFrames(uint32* frame_id) const { bool FrameIdMap::NextFrameAllowingSkippingFrames(uint32* frame_id) const {
// First check if we have continuous frames. // Find the oldest decodable frame.
if (NextContinuousFrame(frame_id))
return true;
// Find the oldest frame.
FrameMap::const_iterator it_best_match = frame_map_.end(); FrameMap::const_iterator it_best_match = frame_map_.end();
FrameMap::const_iterator it; FrameMap::const_iterator it;
// Find first complete frame.
for (it = frame_map_.begin(); it != frame_map_.end(); ++it) { for (it = frame_map_.begin(); it != frame_map_.end(); ++it) {
if (it->second->Complete()) { if (it->second->Complete() && DecodableFrame(it->second.get())) {
it_best_match = it; if (it_best_match == frame_map_.end() ||
break;
}
}
if (it_best_match == frame_map_.end())
return false; // No complete frame.
++it;
for (; it != frame_map_.end(); ++it) {
if (it->second->Complete() &&
IsOlderFrameId(it->first, it_best_match->first)) { IsOlderFrameId(it->first, it_best_match->first)) {
it_best_match = it; it_best_match = it;
} }
} }
*frame_id = it_best_match->first;
return true;
}
bool FrameIdMap::NextVideoFrameAllowingSkippingFrames(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() && DecodableVideoFrame(it->second.get())) {
it_best_match = it;
}
} }
if (it_best_match == frame_map_.end()) if (it_best_match == frame_map_.end())
return false; return false;
...@@ -237,11 +226,14 @@ bool FrameIdMap::ContinuousFrame(FrameInfo* frame) const { ...@@ -237,11 +226,14 @@ bool FrameIdMap::ContinuousFrame(FrameInfo* frame) const {
return static_cast<uint32>(last_released_frame_ + 1) == frame->frame_id(); return static_cast<uint32>(last_released_frame_ + 1) == frame->frame_id();
} }
bool FrameIdMap::DecodableVideoFrame(FrameInfo* frame) const { bool FrameIdMap::DecodableFrame(FrameInfo* frame) const {
if (frame->is_key_frame()) if (frame->is_key_frame())
return true; return true;
if (waiting_for_key_ && !frame->is_key_frame()) if (waiting_for_key_ && !frame->is_key_frame())
return false; return false;
// Self-reference?
if (frame->referenced_frame_id() == frame->frame_id())
return true;
// Current frame is not necessarily referencing the last frame. // Current frame is not necessarily referencing the last frame.
// Do we have the reference frame? // Do we have the reference frame?
......
...@@ -64,8 +64,8 @@ class FrameIdMap { ...@@ -64,8 +64,8 @@ class FrameIdMap {
bool NextContinuousFrame(uint32* frame_id) const; bool NextContinuousFrame(uint32* frame_id) const;
uint32 LastContinuousFrame() const; uint32 LastContinuousFrame() const;
bool NextAudioFrameAllowingMissingFrames(uint32* frame_id) const; bool NextFrameAllowingSkippingFrames(uint32* frame_id) const;
bool NextVideoFrameAllowingSkippingFrames(uint32* frame_id) const; bool HaveMultipleDecodableFrames() const;
int NumberOfCompleteFrames() const; int NumberOfCompleteFrames() const;
void GetMissingPackets(uint32 frame_id, void GetMissingPackets(uint32 frame_id,
...@@ -74,7 +74,7 @@ class FrameIdMap { ...@@ -74,7 +74,7 @@ class FrameIdMap {
private: private:
bool ContinuousFrame(FrameInfo* frame) const; bool ContinuousFrame(FrameInfo* frame) const;
bool DecodableVideoFrame(FrameInfo* frame) const; bool DecodableFrame(FrameInfo* frame) const;
FrameMap frame_map_; FrameMap frame_map_;
bool waiting_for_key_; bool waiting_for_key_;
......
...@@ -58,42 +58,15 @@ bool Framer::InsertPacket(const uint8* payload_data, ...@@ -58,42 +58,15 @@ bool Framer::InsertPacket(const uint8* payload_data,
it->second->InsertPacket(payload_data, payload_size, rtp_header); it->second->InsertPacket(payload_data, payload_size, rtp_header);
} }
bool complete = (packet_type == kNewPacketCompletingFrame); return packet_type == kNewPacketCompletingFrame;
if (complete) {
// ACK as soon as possible.
VLOG(2) << "Complete frame " << static_cast<int>(rtp_header.frame_id);
cast_msg_builder_->CompleteFrameReceived(rtp_header.frame_id,
rtp_header.is_key_frame);
}
return complete;
} }
// This does not release the frame. // This does not release the frame.
bool Framer::GetEncodedAudioFrame(transport::EncodedFrame* audio_frame, bool Framer::GetEncodedFrame(transport::EncodedFrame* frame,
bool* next_frame) { bool* next_frame,
uint32 frame_id; bool* have_multiple_decodable_frames) {
// Find frame id. *have_multiple_decodable_frames = frame_id_map_.HaveMultipleDecodableFrames();
if (frame_id_map_.NextContinuousFrame(&frame_id)) {
// We have our next frame.
*next_frame = true;
} else {
if (!frame_id_map_.NextAudioFrameAllowingMissingFrames(&frame_id)) {
return false;
}
*next_frame = false;
}
ConstFrameIterator it = frames_.find(frame_id);
DCHECK(it != frames_.end());
if (it == frames_.end())
return false;
return it->second->AssembleEncodedFrame(audio_frame);
}
// This does not release the frame.
bool Framer::GetEncodedVideoFrame(transport::EncodedFrame* video_frame,
bool* next_frame) {
uint32 frame_id; uint32 frame_id;
// Find frame id. // Find frame id.
if (frame_id_map_.NextContinuousFrame(&frame_id)) { if (frame_id_map_.NextContinuousFrame(&frame_id)) {
...@@ -104,18 +77,23 @@ bool Framer::GetEncodedVideoFrame(transport::EncodedFrame* video_frame, ...@@ -104,18 +77,23 @@ bool Framer::GetEncodedVideoFrame(transport::EncodedFrame* video_frame,
if (!decoder_faster_than_max_frame_rate_) if (!decoder_faster_than_max_frame_rate_)
return false; return false;
if (!frame_id_map_.NextVideoFrameAllowingSkippingFrames(&frame_id)) { if (!frame_id_map_.NextFrameAllowingSkippingFrames(&frame_id)) {
return false; return false;
} }
*next_frame = false; *next_frame = false;
} }
if (*next_frame) {
VLOG(2) << "ACK frame " << frame_id;
cast_msg_builder_->CompleteFrameReceived(frame_id);
}
ConstFrameIterator it = frames_.find(frame_id); ConstFrameIterator it = frames_.find(frame_id);
DCHECK(it != frames_.end()); DCHECK(it != frames_.end());
if (it == frames_.end()) if (it == frames_.end())
return false; return false;
return it->second->AssembleEncodedFrame(video_frame); return it->second->AssembleEncodedFrame(frame);
} }
void Framer::Reset() { void Framer::Reset() {
......
...@@ -40,15 +40,14 @@ class Framer { ...@@ -40,15 +40,14 @@ class Framer {
const RtpCastHeader& rtp_header, const RtpCastHeader& rtp_header,
bool* duplicate); bool* duplicate);
// Extracts a complete encoded frame - will only return a complete continuous // Extracts a complete encoded frame - will only return a complete and
// frame. // decodable frame. Returns false if no such frames exist.
// Returns false if the frame does not exist or if the frame is not complete // |next_frame| will be set to true if the returned frame is the very
// within the given time frame. // next frame. |have_multiple_complete_frames| will be set to true
bool GetEncodedVideoFrame(transport::EncodedFrame* video_frame, // if there are more decodadble frames available.
bool* next_frame); bool GetEncodedFrame(transport::EncodedFrame* video_frame,
bool* next_frame,
bool GetEncodedAudioFrame(transport::EncodedFrame* audio_frame, bool* have_multiple_complete_frames);
bool* next_frame);
void ReleaseFrame(uint32 frame_id); void ReleaseFrame(uint32 frame_id);
......
This diff is collapsed.
...@@ -155,19 +155,30 @@ void VideoReceiver::EmitAvailableEncodedFrames() { ...@@ -155,19 +155,30 @@ void VideoReceiver::EmitAvailableEncodedFrames() {
scoped_ptr<transport::EncodedFrame> encoded_frame( scoped_ptr<transport::EncodedFrame> encoded_frame(
new transport::EncodedFrame()); new transport::EncodedFrame());
bool is_consecutively_next_frame = false; bool is_consecutively_next_frame = false;
if (!framer_.GetEncodedVideoFrame(encoded_frame.get(), bool have_multiple_complete_frames = false;
&is_consecutively_next_frame)) {
if (!framer_.GetEncodedFrame(encoded_frame.get(),
&is_consecutively_next_frame,
&have_multiple_complete_frames)) {
VLOG(1) << "Wait for more video packets to produce a completed frame."; VLOG(1) << "Wait for more video packets to produce a completed frame.";
return; // OnReceivedPayloadData() will invoke this method in the future. return; // OnReceivedPayloadData() will invoke this method in the future.
} }
const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
const base::TimeTicks playout_time =
GetPlayoutTime(now, encoded_frame->rtp_timestamp);
// If we have multiple decodable frames, and the current frame is
// too old, then skip it and decode the next frame instead.
if (have_multiple_complete_frames && now > playout_time) {
framer_.ReleaseFrame(encoded_frame->frame_id);
continue;
}
// If |framer_| has a frame ready that is out of sequence, examine the // If |framer_| has a frame ready that is out of sequence, examine the
// playout time to determine whether it's acceptable to continue, thereby // playout time to determine whether it's acceptable to continue, thereby
// skipping one or more frames. Skip if the missing frame wouldn't complete // skipping one or more frames. Skip if the missing frame wouldn't complete
// playing before the start of playback of the available frame. // playing before the start of playback of the available frame.
const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
const base::TimeTicks playout_time =
GetPlayoutTime(now, encoded_frame->rtp_timestamp);
if (!is_consecutively_next_frame) { if (!is_consecutively_next_frame) {
// TODO(miu): Also account for expected decode time here? // TODO(miu): Also account for expected decode time here?
const base::TimeTicks earliest_possible_end_time_of_missing_frame = const base::TimeTicks earliest_possible_end_time_of_missing_frame =
......
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