send_time_us_ = send_time_us;
}
+void Packet::SetAbsSendTimeMs(int64_t abs_send_time_ms) {
+ header_.extension.hasAbsoluteSendTime = true;
+ header_.extension.absoluteSendTime = ((static_cast<int64_t>(abs_send_time_ms *
+ (1 << 18)) + 500) / 1000) & 0x00fffffful;
+}
+
bool IsTimeSorted(const Packets& packets) {
PacketsConstIt last_it = packets.begin();
for (PacketsConstIt it = last_it; it != packets.end(); ++it) {
}
-VideoSender::VideoSender(int flow_id, PacketProcessorListener* listener,
- float fps, uint32_t kbps, uint32_t ssrc,
+VideoSender::VideoSender(int flow_id,
+ PacketProcessorListener* listener,
+ float fps,
+ uint32_t kbps,
+ uint32_t ssrc,
float first_frame_offset)
: PacketSender(listener, FlowIds(1, flow_id)),
kMaxPayloadSizeBytes(1200),
return (bytes_per_second_ * 8) / 1000;
}
+uint32_t VideoSender::NextFrameSize() {
+ return frame_size_bytes_;
+}
+
+uint32_t VideoSender::NextPacketSize(uint32_t frame_size,
+ uint32_t remaining_payload) {
+ return std::min(kMaxPayloadSizeBytes, remaining_payload);
+}
+
void VideoSender::RunFor(int64_t time_ms, Packets* in_out) {
assert(in_out);
now_ms_ += time_ms;
Packets new_packets;
while (now_ms_ >= next_frame_ms_) {
- prototype_header_.sequenceNumber++;
prototype_header_.timestamp = kTimestampBase +
static_cast<uint32_t>(next_frame_ms_ * 90.0);
- prototype_header_.extension.absoluteSendTime = (kTimestampBase +
- ((static_cast<int64_t>(next_frame_ms_ * (1 << 18)) + 500) / 1000)) &
- 0x00fffffful;
prototype_header_.extension.transmissionTimeOffset = 0;
// Generate new packets for this frame, all with the same timestamp,
// one packet, we will see a number of equally sized packets followed by
// one smaller at the tail.
int64_t send_time_us = next_frame_ms_ * 1000.0;
- uint32_t payload_size = frame_size_bytes_;
+ uint32_t frame_size = NextFrameSize();
+ uint32_t payload_size = frame_size;
+
while (payload_size > 0) {
- uint32_t size = std::min(kMaxPayloadSizeBytes, payload_size);
+ ++prototype_header_.sequenceNumber;
+ uint32_t size = NextPacketSize(frame_size, payload_size);
new_packets.push_back(Packet(flow_ids()[0], send_time_us, size,
prototype_header_));
+ new_packets.back().SetAbsSendTimeMs(next_frame_ms_);
payload_size -= size;
}
uint32_t kbps,
uint32_t ssrc,
float first_frame_offset)
- : VideoSender(flow_id, listener, fps, kbps, ssrc, first_frame_offset) {}
+ : VideoSender(flow_id, listener, fps, kbps, ssrc, first_frame_offset) {
+}
void AdaptiveVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) {
- bytes_per_second_ = feedback.estimated_bps / 8;
+ bytes_per_second_ = std::min(feedback.estimated_bps / 8, 2500000u / 8);
frame_size_bytes_ = (bytes_per_second_ * frame_period_ms_ + 500) / 1000;
}
+
+PeriodicKeyFrameSender::PeriodicKeyFrameSender(
+ int flow_id,
+ PacketProcessorListener* listener,
+ float fps,
+ uint32_t kbps,
+ uint32_t ssrc,
+ float first_frame_offset,
+ int key_frame_interval)
+ : AdaptiveVideoSender(flow_id,
+ listener,
+ fps,
+ kbps,
+ ssrc,
+ first_frame_offset),
+ key_frame_interval_(key_frame_interval),
+ frame_counter_(0),
+ compensation_bytes_(0),
+ compensation_per_frame_(0) {
+}
+
+uint32_t PeriodicKeyFrameSender::NextFrameSize() {
+ uint32_t payload_size = frame_size_bytes_;
+ if (frame_counter_ == 0) {
+ payload_size = kMaxPayloadSizeBytes * 12;
+ compensation_bytes_ = 4 * frame_size_bytes_;
+ compensation_per_frame_ = compensation_bytes_ / 30;
+ } else if (key_frame_interval_ > 0 &&
+ (frame_counter_ % key_frame_interval_ == 0)) {
+ payload_size *= 5;
+ compensation_bytes_ = payload_size - frame_size_bytes_;
+ compensation_per_frame_ = compensation_bytes_ / 30;
+ } else if (compensation_bytes_ > 0) {
+ if (compensation_per_frame_ > static_cast<int>(payload_size)) {
+ // Skip this frame.
+ compensation_bytes_ -= payload_size;
+ payload_size = 0;
+ } else {
+ payload_size -= compensation_per_frame_;
+ compensation_bytes_ -= compensation_per_frame_;
+ }
+ }
+ if (compensation_bytes_ < 0)
+ compensation_bytes_ = 0;
+ ++frame_counter_;
+ return payload_size;
+}
+
+uint32_t PeriodicKeyFrameSender::NextPacketSize(uint32_t frame_size,
+ uint32_t remaining_payload) {
+ uint32_t fragments =
+ (frame_size + (kMaxPayloadSizeBytes - 1)) / kMaxPayloadSizeBytes;
+ uint32_t avg_size = (frame_size + fragments - 1) / fragments;
+ return std::min(avg_size, remaining_payload);
+}
+
+PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener,
+ uint32_t kbps,
+ AdaptiveVideoSender* source)
+ // It is important that the first_frame_offset and the initial time of
+ // clock_ are both zero, otherwise we can't have absolute time in this
+ // class.
+ : PacketSender(listener, source->flow_ids()),
+ clock_(0),
+ start_of_run_ms_(0),
+ pacer_(&clock_, this, kbps, PacedSender::kDefaultPaceMultiplier* kbps, 0),
+ source_(source) {
+}
+
+void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) {
+ start_of_run_ms_ = clock_.TimeInMilliseconds();
+ Packets generated_packets;
+ source_->RunFor(time_ms, &generated_packets);
+ // Run process periodically to allow the packets to be paced out.
+ int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms;
+ Packets::iterator it = generated_packets.begin();
+ while (clock_.TimeInMilliseconds() <= end_time_ms) {
+ int time_until_process_ms = pacer_.TimeUntilNextProcess();
+ if (time_until_process_ms < 0)
+ time_until_process_ms = 0;
+ int time_until_packet_ms = time_ms;
+ if (it != generated_packets.end())
+ time_until_packet_ms =
+ (it->send_time_us() + 500) / 1000 - clock_.TimeInMilliseconds();
+ assert(time_until_packet_ms >= 0);
+ int time_until_next_event_ms = time_until_packet_ms;
+ if (time_until_process_ms < time_until_packet_ms &&
+ pacer_.QueueSizePackets() > 0)
+ time_until_next_event_ms = time_until_process_ms;
+
+ if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms) {
+ clock_.AdvanceTimeMilliseconds(end_time_ms - clock_.TimeInMilliseconds());
+ break;
+ }
+ clock_.AdvanceTimeMilliseconds(time_until_next_event_ms);
+ if (time_until_process_ms < time_until_packet_ms) {
+ // Time to process.
+ pacer_.Process();
+ } else {
+ // Time to send next packet to pacer.
+ pacer_.SendPacket(PacedSender::kNormalPriority,
+ it->header().ssrc,
+ it->header().sequenceNumber,
+ (it->send_time_us() + 500) / 1000,
+ it->payload_size(),
+ false);
+ pacer_queue_.push_back(*it);
+ const size_t kMaxPacerQueueSize = 10000;
+ if (pacer_queue_.size() > kMaxPacerQueueSize) {
+ pacer_queue_.pop_front();
+ }
+ ++it;
+ }
+ }
+ QueuePackets(in_out, end_time_ms * 1000);
+}
+
+void PacedVideoSender::QueuePackets(Packets* batch,
+ int64_t end_of_batch_time_us) {
+ queue_.merge(*batch);
+ if (queue_.empty()) {
+ return;
+ }
+ Packets::iterator it = queue_.begin();
+ for (; it != queue_.end(); ++it) {
+ if (it->send_time_us() > end_of_batch_time_us) {
+ break;
+ }
+ }
+ Packets to_transfer;
+ to_transfer.splice(to_transfer.begin(), queue_, queue_.begin(), it);
+ batch->merge(to_transfer);
+}
+
+void PacedVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) {
+ source_->GiveFeedback(feedback);
+ pacer_.UpdateBitrate(
+ feedback.estimated_bps / 1000,
+ PacedSender::kDefaultPaceMultiplier * feedback.estimated_bps / 1000,
+ 0);
+}
+
+bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc,
+ uint16_t sequence_number,
+ int64_t capture_time_ms,
+ bool retransmission) {
+ for (Packets::iterator it = pacer_queue_.begin(); it != pacer_queue_.end();
+ ++it) {
+ if (it->header().sequenceNumber == sequence_number) {
+ int64_t pace_out_time_ms = clock_.TimeInMilliseconds();
+ // Make sure a packet is never paced out earlier than when it was put into
+ // the pacer.
+ assert(pace_out_time_ms >= (it->send_time_us() + 500) / 1000);
+ it->SetAbsSendTimeMs(pace_out_time_ms);
+ it->set_send_time_us(1000 * pace_out_time_ms);
+ queue_.push_back(*it);
+ return true;
+ }
+ }
+ return false;
+}
+
+int PacedVideoSender::TimeToSendPadding(int bytes) {
+ return 0;
+}
} // namespace bwe
} // namespace testing
} // namespace webrtc