Commit 359132b4 authored by pwestin@google.com's avatar pwestin@google.com

Added framer to cast.

BUG=

Review URL: https://chromiumcodereview.appspot.com/23467003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@220490 0039d316-1c4b-4281-b951-d872f2087c98
parent ce12f3cd
......@@ -44,11 +44,11 @@
'dependencies': [
'cast_sender',
'cast_receiver',
'../../base/base.gyp:run_all_unittests',
'<(DEPTH)/net/net.gyp:*',
'rtcp/rtcp.gyp:cast_rtcp_test',
'<(DEPTH)/base/base.gyp:run_all_unittests',
'<(DEPTH)/net/net.gyp:net',
'<(DEPTH)/testing/gmock.gyp:gmock',
'<(DEPTH)/testing/gtest.gyp:gtest',
'rtcp/rtcp.gyp:cast_rtcp_test',
],
'include_dirs': [
'<(DEPTH)/',
......@@ -57,6 +57,9 @@
],
'sources': [
'congestion_control/congestion_control_unittest.cc',
'framer/cast_message_builder_unittest.cc',
'framer/frame_buffer_unittest.cc',
'framer/framer_unittest.cc',
'rtp_sender/packet_storage/packet_storage_unittest.cc',
'rtp_sender/rtp_packetizer/rtp_packetizer_unittest.cc',
'rtp_sender/rtp_packetizer/test/rtp_header_parser.cc',
......
......@@ -19,7 +19,8 @@
'dependencies': [
# 'audio_receiver',
# 'video_receiver',
# '<(DEPTH)/cast/pacing/paced_sender.gyp:*',
'framer/framer.gyp:cast_framer',
'pacing/paced_sender.gyp:paced_sender',
],
},
],
......
// Copyright 2013 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/framer/cast_message_builder.h"
namespace media {
namespace cast {
static const uint16 kCompleteFrameLost = 0xffff;
CastMessageBuilder::CastMessageBuilder(
RtpPayloadFeedback* incoming_payload_feedback,
FrameIdMap* frame_id_map,
uint32 media_ssrc,
bool decoder_faster_than_max_frame_rate,
int max_unacked_frames)
: cast_feedback_(incoming_payload_feedback),
frame_id_map_(frame_id_map),
media_ssrc_(media_ssrc),
decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate),
max_unacked_frames_(max_unacked_frames),
cast_msg_(media_ssrc),
waiting_for_key_frame_(true),
slowing_down_ack_(false),
acked_last_frame_(true),
last_acked_frame_id_(kStartFrameId),
default_tick_clock_(new base::DefaultTickClock()),
clock_(default_tick_clock_.get()) {
cast_msg_.ack_frame_id_ = kStartFrameId;
}
CastMessageBuilder::~CastMessageBuilder() {}
void CastMessageBuilder::CompleteFrameReceived(uint8 frame_id,
bool is_key_frame) {
if (last_update_time_.is_null()) {
// Our first update.
last_update_time_ = clock_->NowTicks();
}
if (waiting_for_key_frame_) {
if (!is_key_frame) {
// Ignore that we have received this complete frame since we are
// waiting on a key frame.
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();
}
// Send cast message.
cast_feedback_->CastFeedback(cast_msg_);
}
bool CastMessageBuilder::UpdateAckMessage() {
if (!decoder_faster_than_max_frame_rate_) {
int complete_frame_count = frame_id_map_->NumberOfCompleteFrames();
if (complete_frame_count > max_unacked_frames_) {
// We have too many frames pending in our framer; slow down ACK.
slowing_down_ack_ = true;
} else if (complete_frame_count <= 1) {
// We are down to one or less frames in our framer; ACK normally.
slowing_down_ack_ = false;
}
}
if (slowing_down_ack_) {
// 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
// time; and it's not needed since we can skip frames to catch up.
}
} else {
uint8 frame_id = frame_id_map_->LastContinuousFrame();
// Is it a new frame?
if (last_acked_frame_id_ == frame_id) return false;
last_acked_frame_id_ = frame_id;
acked_last_frame_ = true;
}
cast_msg_.ack_frame_id_ = last_acked_frame_id_;
cast_msg_.missing_frames_and_packets_.clear();
last_update_time_ = clock_->NowTicks();
return true;
}
bool CastMessageBuilder::TimeToSendNextCastMessage(
base::TimeTicks* time_to_send) {
// We haven't received any packets.
if (last_update_time_.is_null() && frame_id_map_->Empty()) return false;
*time_to_send = last_update_time_ +
base::TimeDelta::FromMilliseconds(kCastMessageUpdateIntervalMs);
return true;
}
void CastMessageBuilder::UpdateCastMessage() {
RtcpCastMessage message(media_ssrc_);
if (!UpdateCastMessageInternal(&message)) return;
// Send cast message.
cast_feedback_->CastFeedback(message);
}
void CastMessageBuilder::Reset() {
waiting_for_key_frame_ = true;
cast_msg_.ack_frame_id_ = kStartFrameId;
cast_msg_.missing_frames_and_packets_.clear();
time_last_nacked_map_.clear();
}
bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage* message) {
if (last_update_time_.is_null()) {
if (!frame_id_map_->Empty()) {
// We have received packets.
last_update_time_ = clock_->NowTicks();
}
return false;
}
// Is it time to update the cast message?
base::TimeTicks now = clock_->NowTicks();
if (now - last_update_time_ <
base::TimeDelta::FromMilliseconds(kCastMessageUpdateIntervalMs)) {
return false;
}
last_update_time_ = now;
UpdateAckMessage(); // Needed to cover when a frame is skipped.
BuildPacketList();
*message = cast_msg_;
return true;
}
void CastMessageBuilder::BuildPacketList() {
base::TimeTicks now = clock_->NowTicks();
// Clear message NACK list.
cast_msg_.missing_frames_and_packets_.clear();
// Are we missing packets?
if (frame_id_map_->Empty()) return;
uint8 newest_frame_id = frame_id_map_->NewestFrameId();
uint8 next_expected_frame_id =
static_cast<uint8>(cast_msg_.ack_frame_id_ + 1);
// Iterate over all frames.
for (; !IsNewerFrameId(next_expected_frame_id, newest_frame_id);
++next_expected_frame_id) {
TimeLastNackMap::iterator it =
time_last_nacked_map_.find(next_expected_frame_id);
if (it != time_last_nacked_map_.end()) {
// We have sent a NACK in this frame before, make sure enough time have
// passed.
if (now - it->second <
base::TimeDelta::FromMilliseconds(kNackRepeatIntervalMs)) {
continue;
}
}
PacketIdSet missing;
if (frame_id_map_->FrameExists(next_expected_frame_id)) {
bool last_frame = (newest_frame_id == next_expected_frame_id);
frame_id_map_->GetMissingPackets(next_expected_frame_id, last_frame,
&missing);
if (!missing.empty()) {
time_last_nacked_map_[next_expected_frame_id] = now;
cast_msg_.missing_frames_and_packets_.insert(
std::make_pair(next_expected_frame_id, missing));
}
} else {
time_last_nacked_map_[next_expected_frame_id] = now;
missing.insert(kCompleteFrameLost);
cast_msg_.missing_frames_and_packets_[next_expected_frame_id] = missing;
}
}
}
} // namespace cast
} // namespace media
// Copyright 2013 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.
// Handles NACK list and manages ACK.
#ifndef MEDIA_CAST_FRAMER_CAST_MESSAGE_BUILDER_H_
#define MEDIA_CAST_FRAMER_CAST_MESSAGE_BUILDER_H_
#include <map>
#include "media/cast/framer/frame_id_map.h"
#include "media/cast/rtcp/rtcp.h"
#include "media/cast/rtp_common/rtp_defines.h"
namespace media {
namespace cast {
class RtpPayloadFeedback;
typedef std::map<uint8, base::TimeTicks> TimeLastNackMap;
class CastMessageBuilder {
public:
CastMessageBuilder(RtpPayloadFeedback* incoming_payload_feedback,
FrameIdMap* frame_id_map,
uint32 media_ssrc,
bool decoder_faster_than_max_frame_rate,
int max_unacked_frames);
~CastMessageBuilder();
void CompleteFrameReceived(uint8 frame_id, bool is_key_frame);
bool TimeToSendNextCastMessage(base::TimeTicks* time_to_send);
void UpdateCastMessage();
void Reset();
void set_clock(base::TickClock* clock) {
clock_ = clock;
}
private:
bool UpdateAckMessage();
void BuildPacketList();
bool UpdateCastMessageInternal(RtcpCastMessage* message);
RtpPayloadFeedback* const cast_feedback_;
// CastMessageBuilder has only const access to the frame id mapper.
const FrameIdMap* const frame_id_map_;
const uint32 media_ssrc_;
const bool decoder_faster_than_max_frame_rate_;
const int max_unacked_frames_;
RtcpCastMessage cast_msg_;
base::TimeTicks last_update_time_;
bool waiting_for_key_frame_;
TimeLastNackMap time_last_nacked_map_;
bool slowing_down_ack_;
bool acked_last_frame_;
uint8 last_acked_frame_id_;
scoped_ptr<base::TickClock> default_tick_clock_;
base::TickClock* clock_;
DISALLOW_COPY_AND_ASSIGN(CastMessageBuilder);
};
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_FRAMER_CAST_MESSAGE_BUILDER_H_
This diff is collapsed.
// Copyright 2013 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/framer/frame_buffer.h"
namespace media {
namespace cast {
FrameBuffer::FrameBuffer()
: frame_id_(0),
max_packet_id_(0),
num_packets_received_(0),
is_key_frame_(false),
total_data_size_(0),
last_referenced_frame_id_(0),
packets_() {}
FrameBuffer::~FrameBuffer() {}
void FrameBuffer::InsertPacket(const uint8* payload_data,
int payload_size,
const RtpCastHeader& rtp_header) {
// Is this the first packet in the frame?
if (packets_.empty()) {
frame_id_ = rtp_header.frame_id;
max_packet_id_ = rtp_header.max_packet_id;
is_key_frame_ = rtp_header.is_key_frame;
if (rtp_header.is_reference) {
last_referenced_frame_id_ = rtp_header.reference_frame_id;
} else {
last_referenced_frame_id_ = static_cast<uint8>(rtp_header.frame_id - 1);
}
rtp_timestamp_ = rtp_header.webrtc.header.timestamp;
}
// Is this the correct frame?
if (rtp_header.frame_id != frame_id_) return;
// Insert every packet only once.
if (packets_.find(rtp_header.packet_id) != packets_.end()) return;
std::vector<uint8> data;
std::pair<PacketMap::iterator, bool> retval =
packets_.insert(make_pair(rtp_header.packet_id, data));
// Insert the packet.
retval.first->second.resize(payload_size);
std::copy(payload_data, payload_data + payload_size,
retval.first->second.begin());
++num_packets_received_;
total_data_size_ += payload_size;
}
bool FrameBuffer::Complete() const {
return num_packets_received_ - 1 == max_packet_id_;
}
bool FrameBuffer::GetEncodedAudioFrame(EncodedAudioFrame* audio_frame,
uint32* rtp_timestamp) const {
if (!Complete()) return false;
*rtp_timestamp = rtp_timestamp_;
// Frame is complete -> construct.
audio_frame->frame_id = frame_id_;
// Build the data vector.
audio_frame->data.clear();
audio_frame->data.reserve(total_data_size_);
PacketMap::const_iterator it;
for (it = packets_.begin(); it != packets_.end(); ++it) {
audio_frame->data.insert(audio_frame->data.end(),
it->second.begin(), it->second.end());
}
return true;
}
bool FrameBuffer::GetEncodedVideoFrame(EncodedVideoFrame* video_frame,
uint32* rtp_timestamp) const {
if (!Complete()) return false;
*rtp_timestamp = rtp_timestamp_;
// Frame is complete -> construct.
video_frame->key_frame = is_key_frame_;
video_frame->frame_id = frame_id_;
video_frame->last_referenced_frame_id = last_referenced_frame_id_;
// Build the data vector.
video_frame->data.clear();
video_frame->data.reserve(total_data_size_);
PacketMap::const_iterator it;
for (it = packets_.begin(); it != packets_.end(); ++it) {
video_frame->data.insert(video_frame->data.end(),
it->second.begin(), it->second.end());
}
return true;
}
} // namespace cast
} // namespace media
// Copyright 2013 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_BUFFER
#define MEDIA_CAST_FRAMER_FRAME_BUFFER
#include <map>
#include <vector>
#include "media/cast/cast_config.h"
#include "media/cast/rtp_common/rtp_defines.h"
namespace media {
namespace cast {
typedef std::map<uint16, std::vector<uint8> > PacketMap;
class FrameBuffer {
public:
FrameBuffer();
~FrameBuffer();
void InsertPacket(const uint8* payload_data,
int payload_size,
const RtpCastHeader& rtp_header);
bool Complete() const;
bool GetEncodedAudioFrame(EncodedAudioFrame* audio_frame,
uint32* rtp_timestamp) const;
bool GetEncodedVideoFrame(EncodedVideoFrame* video_frame,
uint32* rtp_timestamp) const;
bool is_key_frame() const { return is_key_frame_; }
uint8 frame_id() const { return frame_id_; }
uint8 last_referenced_frame_id() const { return last_referenced_frame_id_; }
private:
uint8 frame_id_;
uint16 max_packet_id_;
uint16 num_packets_received_;
bool is_key_frame_;
int total_data_size_;
uint8 last_referenced_frame_id_;
uint32 rtp_timestamp_;
PacketMap packets_;
DISALLOW_COPY_AND_ASSIGN(FrameBuffer);
};
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_FRAMER_FRAME_BUFFER
// Copyright 2013 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/framer/frame_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace cast {
class FrameBufferTest : public ::testing::Test {
protected:
FrameBufferTest() {}
~FrameBufferTest() {}
void SetUp() {
payload_.assign(kIpPacketSize, 0);
// Build a default one packet frame - populate webrtc header.
rtp_header_.is_key_frame = false;
rtp_header_.frame_id = 0;
rtp_header_.packet_id = 0;
rtp_header_.max_packet_id = 0;
rtp_header_.is_reference = false;
rtp_header_.reference_frame_id = 0;
}
FrameBuffer buffer_;
std::vector<uint8> payload_;
RtpCastHeader rtp_header_;
};
TEST_F(FrameBufferTest, EmptyBuffer) {
EXPECT_FALSE(buffer_.Complete());
EXPECT_FALSE(buffer_.is_key_frame());
EncodedVideoFrame frame;
uint32 rtp_timestamp;
EXPECT_FALSE(buffer_.GetEncodedVideoFrame(&frame, &rtp_timestamp));
}
TEST_F(FrameBufferTest, DefaultOnePacketFrame) {
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
EXPECT_TRUE(buffer_.Complete());
EXPECT_FALSE(buffer_.is_key_frame());
EncodedVideoFrame frame;
uint32 rtp_timestamp;
EXPECT_TRUE(buffer_.GetEncodedVideoFrame(&frame, &rtp_timestamp));
EXPECT_EQ(payload_.size(), frame.data.size());
}
TEST_F(FrameBufferTest, MultiplePacketFrame) {
rtp_header_.is_key_frame = true;
rtp_header_.max_packet_id = 2;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
++rtp_header_.packet_id;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
++rtp_header_.packet_id;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
++rtp_header_.packet_id;
EXPECT_TRUE(buffer_.Complete());
EXPECT_TRUE(buffer_.is_key_frame());
EncodedVideoFrame frame;
uint32 rtp_timestamp;
EXPECT_TRUE(buffer_.GetEncodedVideoFrame(&frame, &rtp_timestamp));
EXPECT_EQ(3 * payload_.size(), frame.data.size());
}
TEST_F(FrameBufferTest, InCompleteFrame) {
rtp_header_.max_packet_id = 4;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
++rtp_header_.packet_id;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
++rtp_header_.packet_id;
// Increment again - skip packet #2.
++rtp_header_.packet_id;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
++rtp_header_.packet_id;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
EXPECT_FALSE(buffer_.Complete());
// Insert missing packet.
rtp_header_.packet_id = 2;
buffer_.InsertPacket(payload_.data(), payload_.size(), rtp_header_);
EXPECT_TRUE(buffer_.Complete());
}
} // namespace media
} // namespace cast
// Copyright 2013 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/framer/frame_id_map.h"
#include "base/logging.h"
#include "media/cast/rtp_common/rtp_defines.h"
namespace media {
namespace cast {
FrameInfo::FrameInfo(uint8 frame_id,
uint8 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) {
if (max_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() {}
bool FrameInfo::InsertPacket(uint16 packet_id) {
// 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();
}
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() {}
bool FrameIdMap::InsertPacket(const RtpCastHeader& rtp_header, bool* complete) {
uint8 frame_id = rtp_header.frame_id;
uint8 reference_frame_id;
if (rtp_header.is_reference) {
reference_frame_id = rtp_header.reference_frame_id;
} else {
reference_frame_id = static_cast<uint8>(frame_id - 1);
}
if (rtp_header.is_key_frame && waiting_for_key_) {
last_released_frame_ = static_cast<uint8>(frame_id - 1);
waiting_for_key_ = false;
}
if (IsOlderFrameId(frame_id, last_released_frame_) && !waiting_for_key_) {
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?
FrameMap::iterator it = frame_map_.find(frame_id);
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));
*complete = retval.first->second->InsertPacket(rtp_header.packet_id);
} else {
// Insert packet to existing frame.
*complete = it->second->InsertPacket(rtp_header.packet_id);
}
return true;
}
void FrameIdMap::RemoveOldFrames(uint8 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;
}
uint8 FrameIdMap::NewestFrameId() const {
return newest_frame_id_;
}
bool FrameIdMap::NextContinuousFrame(uint8* 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;
}
uint8 FrameIdMap::LastContinuousFrame() const {
uint8 last_continuous_frame_id = last_released_frame_;
uint8 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::NextAudioFrameAllowingMissingFrames(uint8* frame_id) const {
// First check if we have continuous frames.
if (NextContinuousFrame(frame_id)) return true;
// Find the oldest frame.
FrameMap::const_iterator it_best_match = frame_map_.end();
FrameMap::const_iterator it;
// Find first complete frame.
for (it = frame_map_.begin(); it != frame_map_.end(); ++it) {
if (it->second->Complete()) {
it_best_match = it;
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)) {
it_best_match = it;
}
}
*frame_id = it_best_match->first;
return true;
}
bool FrameIdMap::NextVideoFrameAllowingSkippingFrames(uint8* 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()) 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(uint8 frame_id) const {
return frame_map_.end() != frame_map_.find(frame_id);
}
void FrameIdMap::GetMissingPackets(uint8 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<uint8>(last_released_frame_ + 1) == frame->frame_id();
}
bool FrameIdMap::DecodableVideoFrame(FrameInfo* frame) const {
if (frame->is_key_frame()) return true;
if (waiting_for_key_ && !frame->is_key_frame()) return false;
// 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 2013 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/rtcp/rtcp_defines.h"
#include "media/cast/rtp_common/rtp_defines.h"
namespace media {
namespace cast {
class FrameInfo {
public:
FrameInfo(uint8 frame_id,
uint8 referenced_frame_id,
uint16 max_packet_id,
bool key_frame);
~FrameInfo();
// Returns true if frame is complete after the insert.
bool 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_; }
uint8 frame_id() const { return frame_id_; }
uint8 referenced_frame_id() const { return referenced_frame_id_; }
private:
const bool is_key_frame_;
const uint8 frame_id_;
const uint8 referenced_frame_id_;
uint16 max_received_packet_id_;
PacketIdSet missing_packets_;
DISALLOW_COPY_AND_ASSIGN(FrameInfo);
};
typedef std::map<uint8, linked_ptr<FrameInfo> > FrameMap;
class FrameIdMap {
public:
FrameIdMap();
~FrameIdMap();
// Returns false if not a valid (old) packet, otherwise returns true.
bool InsertPacket(const RtpCastHeader& rtp_header, bool* complete);
bool Empty() const;
bool FrameExists(uint8 frame_id) const;
uint8 NewestFrameId() const;
void RemoveOldFrames(uint8 frame_id);
void Clear();
// Identifies the next frame to be released (rendered).
bool NextContinuousFrame(uint8* frame_id) const;
uint8 LastContinuousFrame() const;
bool NextAudioFrameAllowingMissingFrames(uint8* frame_id) const;
bool NextVideoFrameAllowingSkippingFrames(uint8* frame_id) const;
int NumberOfCompleteFrames() const;
void GetMissingPackets(uint8 frame_id,
bool last_frame,
PacketIdSet* missing_packets) const;
private:
bool ContinuousFrame(FrameInfo* frame) const;
bool DecodableVideoFrame(FrameInfo* frame) const;
FrameMap frame_map_;
bool waiting_for_key_;
uint8 last_released_frame_;
uint8 newest_frame_id_;
DISALLOW_COPY_AND_ASSIGN(FrameIdMap);
};
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_FRAMER_FRAME_ID_MAP_H_
// Copyright 2013 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/framer/framer.h"
#include "base/logging.h"
namespace media {
namespace cast {
typedef FrameList::const_iterator ConstFrameIterator;
Framer::Framer(RtpPayloadFeedback* incoming_payload_feedback,
uint32 ssrc,
bool decoder_faster_than_max_frame_rate,
int max_unacked_frames)
: decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate),
clock_(&default_tick_clock_),
cast_msg_builder_(new CastMessageBuilder(incoming_payload_feedback,
&frame_id_map_, ssrc, decoder_faster_than_max_frame_rate,
max_unacked_frames)) {
DCHECK(incoming_payload_feedback) << "Invalid argument";
}
Framer::~Framer() {}
void Framer::InsertPacket(const uint8* payload_data,
int payload_size,
const RtpCastHeader& rtp_header) {
bool complete = false;
if (!frame_id_map_.InsertPacket(rtp_header, &complete)) return;
// Does this packet belong to a new frame?
FrameList::iterator it = frames_.find(rtp_header.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);
}
if (complete) {
// ACK as soon as possible.
cast_msg_builder_->CompleteFrameReceived(rtp_header.frame_id,
rtp_header.is_key_frame);
}
}
// This does not release the frame.
bool Framer::GetEncodedAudioFrame(const base::TimeTicks& timeout,
EncodedAudioFrame* audio_frame,
uint32* rtp_timestamp,
bool* next_frame) {
uint8 frame_id;
// Find frame id.
if (frame_id_map_.NextContinuousFrame(&frame_id)) {
// We have our next frame.
*next_frame = true;
} else {
if (WaitForNextFrame(timeout)) return false;
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->GetEncodedAudioFrame(audio_frame, rtp_timestamp);
}
// This does not release the frame.
bool Framer::GetEncodedVideoFrame(const base::TimeTicks& timeout,
EncodedVideoFrame* video_frame,
uint32* rtp_timestamp,
bool* next_frame) {
uint8 frame_id;
// Find frame id.
if (frame_id_map_.NextContinuousFrame(&frame_id)) {
// We have our next frame.
*next_frame = true;
} else {
if (WaitForNextFrame(timeout)) return false;
// Check if we can skip frames when our decoder is too slow.
if (!decoder_faster_than_max_frame_rate_) return false;
if (!frame_id_map_.NextVideoFrameAllowingSkippingFrames(&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->GetEncodedVideoFrame(video_frame, rtp_timestamp);
}
bool Framer::WaitForNextFrame(const base::TimeTicks& timeout) const {
base::TimeDelta wait_time = timeout - clock_->NowTicks();
if (wait_time.InMilliseconds() > 0)
return true;
return false;
}
void Framer::Reset() {
frame_id_map_.Clear();
frames_.clear();
cast_msg_builder_->Reset();
}
void Framer::ReleaseFrame(uint8 frame_id) {
frame_id_map_.RemoveOldFrames(frame_id);
frames_.erase(frame_id);
// We have a frame - remove all frames with lower frame id.
FrameList::iterator it;
for (it = frames_.begin(); it != frames_.end(); ) {
if (IsOlderFrameId(it->first, frame_id)) {
frames_.erase(it++);
} else {
++it;
}
}
}
bool Framer::TimeToSendNextCastMessage(base::TimeTicks* time_to_send) {
return cast_msg_builder_->TimeToSendNextCastMessage(time_to_send);
}
void Framer::SendCastMessage() {
cast_msg_builder_->UpdateCastMessage();
}
} // namespace cast
} // namespace media
# Copyright 2013 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.
{
'targets': [
{
'target_name': 'cast_framer',
'type': 'static_library',
'include_dirs': [
'<(DEPTH)/',
'<(DEPTH)/third_party/',
'<(DEPTH)/third_party/webrtc',
],
'sources': [
'cast_message_builder.cc',
'cast_message_builder.h',
'frame_buffer.cc',
'frame_buffer.h',
'frame_id_map.cc',
'frame_id_map.h',
'framer.cc',
'framer.h',
],
},
], # targets
}
// Copyright 2013 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_FRAMER_H_
#define MEDIA_CAST_FRAMER_FRAMER_H_
#include <map>
#include "base/basictypes.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "media/cast/framer/cast_message_builder.h"
#include "media/cast/framer/frame_buffer.h"
#include "media/cast/framer/frame_id_map.h"
#include "media/cast/rtcp/rtcp.h"
#include "media/cast/rtp_common/rtp_defines.h"
namespace media {
namespace cast {
typedef std::map<uint8, linked_ptr<FrameBuffer> > FrameList;
class Framer {
public:
Framer(RtpPayloadFeedback* incoming_payload_feedback,
uint32 ssrc,
bool decoder_faster_than_max_frame_rate,
int max_unacked_frames);
~Framer();
void InsertPacket(const uint8* payload_data,
int payload_size,
const RtpCastHeader& rtp_header);
// Extracts a complete encoded frame - will only return a complete continuous
// frame.
// Returns false if the frame does not exist or if the frame is not complete
// within the given time frame.
bool GetEncodedVideoFrame(const base::TimeTicks& timeout,
EncodedVideoFrame* video_frame,
uint32* rtp_timestamp,
bool* next_frame);
bool GetEncodedAudioFrame(const base::TimeTicks& timeout,
EncodedAudioFrame* audio_frame,
uint32* rtp_timestamp,
bool* next_frame);
void ReleaseFrame(uint8 frame_id);
// Reset framer state to original state and flush all pending buffers.
void Reset();
bool TimeToSendNextCastMessage(base::TimeTicks* time_to_send);
void SendCastMessage();
void set_clock(base::TickClock* clock) {
clock_ = clock;
cast_msg_builder_->set_clock(clock);
}
private:
// Return true if we should wait.
bool WaitForNextFrame(const base::TimeTicks& timeout) const;
const bool decoder_faster_than_max_frame_rate_;
FrameList frames_;
FrameIdMap frame_id_map_;
base::DefaultTickClock default_tick_clock_;
base::TickClock* clock_;
scoped_ptr<CastMessageBuilder> cast_msg_builder_;
DISALLOW_COPY_AND_ASSIGN(Framer);
};
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_FRAMER_FRAMER_H_
This diff is collapsed.
......@@ -8,7 +8,6 @@
#include <list>
#include <map>
#include <set>
#include <vector>
#include "media/cast/cast_config.h"
#include "media/cast/cast_defines.h"
......@@ -18,6 +17,9 @@ namespace cast {
const uint16 kRtcpCastAllPacketsLost = 0xffff;
typedef std::set<uint16> PacketIdSet;
typedef std::map<uint8, PacketIdSet> MissingFramesAndPacketsMap;
class RtcpCastMessage {
public:
explicit RtcpCastMessage(uint32 media_ssrc);
......@@ -25,7 +27,7 @@ class RtcpCastMessage {
uint32 media_ssrc_;
uint8 ack_frame_id_;
std::map<uint8, std::set<uint16> > missing_frames_and_packets_;
MissingFramesAndPacketsMap missing_frames_and_packets_;
};
struct RtcpSenderInfo {
......
......@@ -8,7 +8,7 @@
#include "media/cast/rtp_common/rtp_defines.h"
#include "testing/gmock/include/gmock/gmock.h"
namesapce media {
namespace media {
namespace cast {
class MockRtpPayloadFeedback : public RtpPayloadFeedback {
......@@ -20,6 +20,6 @@ class MockRtpPayloadFeedback : public RtpPayloadFeedback {
};
} // namespace cast
} // namesapce media
} // namespace media
#endif // MEDIA_CAST_RTP_COMMON_MOCK_RTP_PAYLOAD_FEEDBACK_H_
......@@ -10,7 +10,6 @@
#include "base/basictypes.h"
#include "media/cast/cast_config.h"
#include "media/cast/rtcp/rtcp_defines.h"
#include "third_party/webrtc/modules/interface/module_common_types.h"
namespace media {
......@@ -55,8 +54,7 @@ inline bool IsOlderFrameId(uint8 frame_id, uint8 prev_frame_id) {
return (frame_id == prev_frame_id) || IsNewerFrameId(prev_frame_id, frame_id);
}
inline bool IsNewerPacketId(uint16 packet_id,
uint16 prev_packet_id) {
inline bool IsNewerPacketId(uint16 packet_id, uint16 prev_packet_id) {
return (packet_id != prev_packet_id) &&
static_cast<uint16>(packet_id - prev_packet_id) < 0x8000;
}
......@@ -69,4 +67,5 @@ inline bool IsNewerSequenceNumber(uint16 sequence_number,
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_RTP_COMMON_RTP_DEFINES_H_
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