diff --git a/erizo/src/erizo/rtp/LayerDetectorHandler.cpp b/erizo/src/erizo/rtp/LayerDetectorHandler.cpp index 6e187009a9..10b4871ba6 100644 --- a/erizo/src/erizo/rtp/LayerDetectorHandler.cpp +++ b/erizo/src/erizo/rtp/LayerDetectorHandler.cpp @@ -7,9 +7,21 @@ namespace erizo { +static constexpr uint32_t kMaxTemporalLayers = 4; +static constexpr uint32_t kMaxSpatialLayers = 4; +static constexpr erizo::duration kMinNotifyLayerInfoInterval = std::chrono::seconds(5); + DEFINE_LOGGER(LayerDetectorHandler, "rtp.LayerDetectorHandler"); -LayerDetectorHandler::LayerDetectorHandler() : connection_{nullptr}, enabled_{true}, initialized_{false} {} +LayerDetectorHandler::LayerDetectorHandler(std::shared_ptr the_clock) + : clock_{the_clock}, connection_{nullptr}, enabled_{true}, initialized_{false}, + last_event_sent_{clock_->now()} { + for (uint32_t temporal_layer = 0; temporal_layer <= kMaxTemporalLayers; temporal_layer++) { + video_frame_rate_list_.push_back(MovingIntervalRateStat{std::chrono::milliseconds(500), 10, .5, clock_}); + } + video_frame_width_list_ = std::vector(kMaxSpatialLayers); + video_frame_height_list_ = std::vector(kMaxSpatialLayers); +} void LayerDetectorHandler::enable() { enabled_ = true; @@ -35,6 +47,28 @@ void LayerDetectorHandler::read(Context *ctx, std::shared_ptr packet ctx->fireRead(std::move(packet)); } +void LayerDetectorHandler::notifyLayerInfoChangedEvent() { + ELOG_DEBUG("LAYER INFO CHANGED"); + for (uint32_t spatial_layer = 0; spatial_layer < video_frame_width_list_.size(); spatial_layer++) { + ELOG_DEBUG(" SPATIAL LAYER (%u): %u %u", + spatial_layer, video_frame_width_list_[spatial_layer], video_frame_height_list_[spatial_layer]); + } + for (uint32_t temporal_layer = 0; temporal_layer < video_frame_rate_list_.size(); temporal_layer++) { + ELOG_DEBUG(" TEMPORAL LAYER (%u): %lu", + temporal_layer, video_frame_rate_list_[temporal_layer].value()); + } + + // TODO(javier): send an event to subscribers with the new info + + last_event_sent_ = clock_->now(); +} + +void LayerDetectorHandler::notifyLayerInfoChangedEventMaybe() { + if (clock_->now() - last_event_sent_ > kMinNotifyLayerInfoInterval) { + notifyLayerInfoChangedEvent(); + } +} + int LayerDetectorHandler::getSsrcPosition(uint32_t ssrc) { std::vector::iterator item = std::find(video_ssrc_list_.begin(), video_ssrc_list_.end(), ssrc); size_t index = std::distance(video_ssrc_list_.begin(), item); @@ -55,17 +89,13 @@ void LayerDetectorHandler::parseLayerInfoFromVP8(std::shared_ptr pac } packet->compatible_temporal_layers = {}; switch (payload->tID) { - case 0: - packet->compatible_temporal_layers.push_back(0); - case 2: - packet->compatible_temporal_layers.push_back(1); - case 1: - packet->compatible_temporal_layers.push_back(2); + case 0: addTemporalLayerAndCalculateRate(packet, 0, payload->beginningOfPartition); + case 2: addTemporalLayerAndCalculateRate(packet, 1, payload->beginningOfPartition); + case 1: addTemporalLayerAndCalculateRate(packet, 2, payload->beginningOfPartition); // case 3 and beyond are not handled because Chrome only // supports 3 temporal scalability today (03/15/17) break; - default: - packet->compatible_temporal_layers.push_back(0); + default: addTemporalLayerAndCalculateRate(packet, 0, payload->beginningOfPartition); break; } @@ -76,9 +106,24 @@ void LayerDetectorHandler::parseLayerInfoFromVP8(std::shared_ptr pac } else { packet->is_keyframe = false; } + + if (payload->frameWidth != -1 && static_cast(payload->frameWidth) != video_frame_width_list_[position]) { + video_frame_width_list_[position] = payload->frameWidth; + video_frame_height_list_[position] = payload->frameHeight; + notifyLayerInfoChangedEvent(); + } + notifyLayerInfoChangedEventMaybe(); delete payload; } +void LayerDetectorHandler::addTemporalLayerAndCalculateRate(const std::shared_ptr &packet, + int temporal_layer, bool new_frame) { + if (new_frame) { + video_frame_rate_list_[temporal_layer]++; + } + packet->compatible_temporal_layers.push_back(temporal_layer); +} + void LayerDetectorHandler::parseLayerInfoFromVP9(std::shared_ptr packet) { RtpHeader *rtp_header = reinterpret_cast(packet->data); unsigned char* start_buffer = reinterpret_cast (packet->data); @@ -95,17 +140,12 @@ void LayerDetectorHandler::parseLayerInfoFromVP9(std::shared_ptr pac packet->compatible_temporal_layers = {}; switch (payload->temporalID) { - case 0: - packet->compatible_temporal_layers.push_back(0); - case 2: - packet->compatible_temporal_layers.push_back(1); - case 1: - packet->compatible_temporal_layers.push_back(2); - case 3: - packet->compatible_temporal_layers.push_back(3); + case 0: addTemporalLayerAndCalculateRate(packet, 0, payload->beginningOfLayerFrame); + case 2: addTemporalLayerAndCalculateRate(packet, 1, payload->beginningOfLayerFrame); + case 1: addTemporalLayerAndCalculateRate(packet, 2, payload->beginningOfLayerFrame); + case 3: addTemporalLayerAndCalculateRate(packet, 3, payload->beginningOfLayerFrame); break; - default: - packet->compatible_temporal_layers.push_back(0); + default: addTemporalLayerAndCalculateRate(packet, 0, payload->beginningOfLayerFrame); break; } @@ -114,6 +154,19 @@ void LayerDetectorHandler::parseLayerInfoFromVP9(std::shared_ptr pac } else { packet->is_keyframe = false; } + bool resolution_changed = false; + if (payload->resolutions.size() > 0) { + for (uint position = 0; position < payload->resolutions.size(); position++) { + resolution_changed = true; + video_frame_width_list_[position] = payload->resolutions[position].width; + video_frame_height_list_[position] = payload->resolutions[position].height; + } + } + if (resolution_changed) { + notifyLayerInfoChangedEvent(); + } + + notifyLayerInfoChangedEventMaybe(); packet->ending_of_layer_frame = payload->endingOfLayerFrame; delete payload; diff --git a/erizo/src/erizo/rtp/LayerDetectorHandler.h b/erizo/src/erizo/rtp/LayerDetectorHandler.h index 3b94a98de6..21e4c01ad3 100644 --- a/erizo/src/erizo/rtp/LayerDetectorHandler.h +++ b/erizo/src/erizo/rtp/LayerDetectorHandler.h @@ -10,6 +10,7 @@ #include "pipeline/Handler.h" #include "rtp/RtpVP8Parser.h" #include "rtp/RtpVP9Parser.h" +#include "./Stats.h" #define MAX_DELAY 450000 @@ -17,13 +18,12 @@ namespace erizo { class WebRtcConnection; - class LayerDetectorHandler: public InboundHandler, public std::enable_shared_from_this { DECLARE_LOGGER(); public: - LayerDetectorHandler(); + explicit LayerDetectorHandler(std::shared_ptr the_clock = std::make_shared()); void enable() override; void disable() override; @@ -39,14 +39,22 @@ class LayerDetectorHandler: public InboundHandler, public std::enable_shared_fro void parseLayerInfoFromVP8(std::shared_ptr packet); void parseLayerInfoFromVP9(std::shared_ptr packet); int getSsrcPosition(uint32_t ssrc); + void addTemporalLayerAndCalculateRate(const std::shared_ptr &packet, int temporal_layer, bool new_frame); + void notifyLayerInfoChangedEvent(); + void notifyLayerInfoChangedEventMaybe(); private: + std::shared_ptr clock_; WebRtcConnection *connection_; bool enabled_; bool initialized_; RtpVP8Parser vp8_parser_; RtpVP9Parser vp9_parser_; std::vector video_ssrc_list_; + std::vector video_frame_height_list_; + std::vector video_frame_width_list_; + std::vector video_frame_rate_list_; + std::chrono::steady_clock::time_point last_event_sent_; }; } // namespace erizo