Skip to content

Commit

Permalink
Fix second temporal layer in vp8 simulcast (#1283)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcague authored Aug 29, 2018
1 parent ef89a6d commit c5db134
Show file tree
Hide file tree
Showing 12 changed files with 536 additions and 52 deletions.
7 changes: 4 additions & 3 deletions erizo/src/erizo/MediaDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ struct DataPacket {

DataPacket(int comp_, const char *data_, int length_, packetType type_, uint64_t received_time_ms_) :
comp{comp_}, length{length_}, type{type_}, received_time_ms{received_time_ms_}, is_keyframe{false},
ending_of_layer_frame{false}, picture_id{-1} {
ending_of_layer_frame{false}, picture_id{-1}, tl0_pic_idx{-1} {
memcpy(data, data_, length_);
}

DataPacket(int comp_, const char *data_, int length_, packetType type_) :
comp{comp_}, length{length_}, type{type_}, received_time_ms{ClockUtils::timePointToMs(clock::now())},
is_keyframe{false}, ending_of_layer_frame{false}, picture_id{-1} {
is_keyframe{false}, ending_of_layer_frame{false}, picture_id{-1}, tl0_pic_idx{-1} {
memcpy(data, data_, length_);
}

DataPacket(int comp_, const unsigned char *data_, int length_) :
comp{comp_}, length{length_}, type{VIDEO_PACKET}, received_time_ms{ClockUtils::timePointToMs(clock::now())},
is_keyframe{false}, ending_of_layer_frame{false}, picture_id{-1} {
is_keyframe{false}, ending_of_layer_frame{false}, picture_id{-1}, tl0_pic_idx{-1} {
memcpy(data, data_, length_);
}

Expand Down Expand Up @@ -66,6 +66,7 @@ struct DataPacket {
bool is_keyframe; // Note: It can be just a keyframe first packet in VP8
bool ending_of_layer_frame;
int picture_id;
int tl0_pic_idx;
std::string codec;
unsigned int clock_rate = 0;
};
Expand Down
7 changes: 5 additions & 2 deletions erizo/src/erizo/rtp/LayerDetectorHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,14 @@ void LayerDetectorHandler::parseLayerInfoFromVP8(std::shared_ptr<DataPacket> pac
if (payload->hasPictureID) {
packet->picture_id = payload->pictureID;
}
if (payload->hasTl0PicIdx) {
packet->tl0_pic_idx = payload->tl0PicIdx;
}
packet->compatible_temporal_layers = {};
switch (payload->tID) {
case 0: addTemporalLayerAndCalculateRate(packet, 0, payload->beginningOfPartition);
case 2: addTemporalLayerAndCalculateRate(packet, 1, payload->beginningOfPartition);
case 1: addTemporalLayerAndCalculateRate(packet, 2, payload->beginningOfPartition);
case 1: addTemporalLayerAndCalculateRate(packet, 1, payload->beginningOfPartition);
case 2: addTemporalLayerAndCalculateRate(packet, 2, payload->beginningOfPartition);
// case 3 and beyond are not handled because Chrome only
// supports 3 temporal scalability today (03/15/17)
break;
Expand Down
54 changes: 45 additions & 9 deletions erizo/src/erizo/rtp/QualityFilterHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ DEFINE_LOGGER(QualityFilterHandler, "rtp.QualityFilterHandler");
constexpr duration kSwitchTimeout = std::chrono::seconds(3);

QualityFilterHandler::QualityFilterHandler()
: stream_{nullptr}, enabled_{true}, initialized_{false},
: picture_id_translator_{511, 250, 15}, stream_{nullptr}, enabled_{true}, initialized_{false},
receiving_multiple_ssrc_{false}, changing_spatial_layer_{false}, is_scalable_{false},
target_spatial_layer_{0},
future_spatial_layer_{-1}, target_temporal_layer_{0},
video_sink_ssrc_{0}, video_source_ssrc_{0}, last_ssrc_received_{0},
max_video_bw_{0}, last_timestamp_sent_{0}, timestamp_offset_{0},
time_change_started_{clock::now()}, picture_id_offset_{0}, last_picture_id_sent_{0} {}
time_change_started_{clock::now()}, tl0_pic_idx_offset_{0}, last_tl0_pic_idx_sent_{0} {}

void QualityFilterHandler::enable() {
enabled_ = true;
Expand Down Expand Up @@ -105,12 +105,34 @@ void QualityFilterHandler::detectVideoScalability(const std::shared_ptr<DataPack
}
}

void QualityFilterHandler::updatePictureID(const std::shared_ptr<DataPacket> &packet) {
void QualityFilterHandler::updatePictureID(const std::shared_ptr<DataPacket> &packet, int new_picture_id) {
if (packet->codec == "VP8") {
RtpHeader *rtp_header = reinterpret_cast<RtpHeader*>(packet->data);
unsigned char* start_buffer = reinterpret_cast<unsigned char*> (packet->data);
start_buffer = start_buffer + rtp_header->getHeaderLength();
RtpVP8Parser::setVP8PictureID(start_buffer, packet->length - rtp_header->getHeaderLength(), last_picture_id_sent_);
RtpVP8Parser::setVP8PictureID(start_buffer, packet->length - rtp_header->getHeaderLength(), new_picture_id);
}
}

void QualityFilterHandler::updateTL0PicIdx(const std::shared_ptr<DataPacket> &packet, uint8_t new_tl0_pic_idx) {
if (packet->codec == "VP8") {
RtpHeader *rtp_header = reinterpret_cast<RtpHeader*>(packet->data);
unsigned char* start_buffer = reinterpret_cast<unsigned char*> (packet->data);
start_buffer = start_buffer + rtp_header->getHeaderLength();
RtpVP8Parser::setVP8TL0PicIdx(start_buffer, packet->length - rtp_header->getHeaderLength(), new_tl0_pic_idx);
}
}

void QualityFilterHandler::removeVP8OptionalPayload(const std::shared_ptr<DataPacket> &packet) {
if (packet->codec == "VP8") {
RtpHeader *rtp_header = reinterpret_cast<RtpHeader*>(packet->data);
unsigned char* start_buffer = reinterpret_cast<unsigned char*> (packet->data);
start_buffer = start_buffer + rtp_header->getHeaderLength();
int packet_length = packet->length - rtp_header->getHeaderLength();
packet_length = RtpVP8Parser::removePictureID(start_buffer, packet_length);
packet_length = RtpVP8Parser::removeTl0PicIdx(start_buffer, packet_length);
packet_length = RtpVP8Parser::removeTIDAndKeyIdx(start_buffer, packet_length);
packet->length = packet_length + rtp_header->getHeaderLength();
}
}

Expand All @@ -127,6 +149,7 @@ void QualityFilterHandler::write(Context *ctx, std::shared_ptr<DataPacket> packe
uint32_t ssrc = rtp_header->getSSRC();
uint16_t sequence_number = rtp_header->getSeqNumber();
int picture_id = packet->picture_id;
uint8_t tl0_pic_idx = packet->tl0_pic_idx;

if (last_ssrc_received_ != 0 && ssrc != last_ssrc_received_) {
receiving_multiple_ssrc_ = true;
Expand All @@ -137,6 +160,7 @@ void QualityFilterHandler::write(Context *ctx, std::shared_ptr<DataPacket> packe
if (!packet->belongsToSpatialLayer(target_spatial_layer_)) {
if (!receiving_multiple_ssrc_) {
translator_.get(sequence_number, true);
picture_id_translator_.get(picture_id, true);
}
return;
}
Expand All @@ -145,16 +169,18 @@ void QualityFilterHandler::write(Context *ctx, std::shared_ptr<DataPacket> packe

if (checkSSRCChange(ssrc)) {
translator_.reset();
picture_id_translator_.reset();
if (last_timestamp_sent_ > 0) {
timestamp_offset_ = last_timestamp_sent_ - new_timestamp + 1;
}
if (last_picture_id_sent_ > 0) {
picture_id_offset_ = last_picture_id_sent_ - picture_id + 1;
if (last_tl0_pic_idx_sent_ > 0) {
tl0_pic_idx_offset_ = last_tl0_pic_idx_sent_ - tl0_pic_idx + 1;
}
}

if (!packet->belongsToTemporalLayer(target_temporal_layer_)) {
translator_.get(sequence_number, true);
picture_id_translator_.get(picture_id, true);
return;
}

Expand All @@ -163,6 +189,11 @@ void QualityFilterHandler::write(Context *ctx, std::shared_ptr<DataPacket> packe
return;
}

SequenceNumber picture_id_info = picture_id_translator_.get(picture_id, false);
if (picture_id_info.type != SequenceNumberType::Valid) {
return;
}

if (packet->compatible_spatial_layers.back() == target_spatial_layer_ && packet->ending_of_layer_frame) {
rtp_header->setMarker(1);
}
Expand All @@ -173,11 +204,16 @@ void QualityFilterHandler::write(Context *ctx, std::shared_ptr<DataPacket> packe
last_timestamp_sent_ = new_timestamp + timestamp_offset_;
rtp_header->setTimestamp(last_timestamp_sent_);

last_picture_id_sent_ = picture_id + picture_id_offset_;
updatePictureID(packet);
updatePictureID(packet, picture_id_info.output & 0x7FFF);

uint8_t tl0_pic_idx_sent = tl0_pic_idx + tl0_pic_idx_offset_;
last_tl0_pic_idx_sent_ = RtpUtils::numberLessThan(last_tl0_pic_idx_sent_, tl0_pic_idx_sent, 8) ?
tl0_pic_idx_sent : last_tl0_pic_idx_sent_;
updateTL0PicIdx(packet, tl0_pic_idx_sent);
// removeVP8OptionalPayload(packet); // TODO(javier): uncomment this line in case of issues with pictureId
}

// TODO(javier): Handle SRs and translate Sequence Numbers?
// TODO(javier): Handle SRs?

ctx->fireWrite(packet);
}
Expand Down
9 changes: 6 additions & 3 deletions erizo/src/erizo/rtp/QualityFilterHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,14 @@ class QualityFilterHandler: public Handler, public std::enable_shared_from_this<
bool checkSSRCChange(uint32_t ssrc);
void changeSpatialLayerOnKeyframeReceived(const std::shared_ptr<DataPacket> &packet);
void detectVideoScalability(const std::shared_ptr<DataPacket> &packet);
void updatePictureID(const std::shared_ptr<DataPacket> &packet);
void updatePictureID(const std::shared_ptr<DataPacket> &packet, int new_picture_id);
void updateTL0PicIdx(const std::shared_ptr<DataPacket> &packet, uint8_t new_tl0_pic_idx);
void removeVP8OptionalPayload(const std::shared_ptr<DataPacket> &packet);

private:
std::shared_ptr<QualityManager> quality_manager_;
SequenceNumberTranslator translator_;
SequenceNumberTranslator picture_id_translator_;
MediaStream *stream_;
bool enabled_;
bool initialized_;
Expand All @@ -62,8 +65,8 @@ class QualityFilterHandler: public Handler, public std::enable_shared_from_this<
uint32_t last_timestamp_sent_;
uint32_t timestamp_offset_;
time_point time_change_started_;
int picture_id_offset_;
int last_picture_id_sent_;
uint8_t tl0_pic_idx_offset_;
uint8_t last_tl0_pic_idx_sent_;
};
} // namespace erizo

Expand Down
10 changes: 9 additions & 1 deletion erizo/src/erizo/rtp/RtpUtils.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "rtp/RtpUtils.h"

#include <cmath>
#include <memory>

namespace erizo {
Expand All @@ -8,8 +9,15 @@ namespace erizo {
constexpr int kMaxPacketSize = 1500;

bool RtpUtils::sequenceNumberLessThan(uint16_t first, uint16_t last) {
return RtpUtils::numberLessThan(first, last, 16);
}

bool RtpUtils::numberLessThan(uint16_t first, uint16_t last, int bits) {
uint16_t result = first - last;
return result > 0xF000;
uint16_t mark = std::pow(2, bits) - 1;
result = result & mark;
uint16_t threshold = (bits > 4) ? std::pow(2, bits - 4) - 1 : std::pow(2, bits) - 1;
return result > threshold;
}

void RtpUtils::updateREMB(RtcpHeader *chead, uint bitrate) {
Expand Down
2 changes: 2 additions & 0 deletions erizo/src/erizo/rtp/RtpUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class RtpUtils {
public:
static bool sequenceNumberLessThan(uint16_t first, uint16_t second);

static bool numberLessThan(uint16_t first, uint16_t last, int bits);

static void forEachRtcpBlock(std::shared_ptr<DataPacket> packet, std::function<void(RtcpHeader*)> f);

static void updateREMB(RtcpHeader *chead, uint bitrate);
Expand Down
Loading

0 comments on commit c5db134

Please sign in to comment.