OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" | 11 #include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" |
12 | 12 |
13 #include <stdlib.h> | 13 #include <stdlib.h> |
14 #include <string.h> | 14 #include <string.h> |
15 | 15 |
16 #include <limits> | |
16 #include <memory> | 17 #include <memory> |
18 #include <utility> | |
17 #include <vector> | 19 #include <vector> |
18 #include <utility> | |
19 | 20 |
20 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" | 21 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
21 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 22 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
22 #include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h" | 23 #include "webrtc/modules/rtp_rtcp/source/rtp_format_video_generic.h" |
23 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" | 24 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h" |
24 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h" | 25 #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h" |
25 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" | 26 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" |
26 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" | 27 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" |
27 #include "webrtc/rtc_base/checks.h" | 28 #include "webrtc/rtc_base/checks.h" |
28 #include "webrtc/rtc_base/logging.h" | 29 #include "webrtc/rtc_base/logging.h" |
29 #include "webrtc/rtc_base/ptr_util.h" | 30 #include "webrtc/rtc_base/ptr_util.h" |
30 #include "webrtc/rtc_base/trace_event.h" | 31 #include "webrtc/rtc_base/trace_event.h" |
31 | 32 |
32 namespace webrtc { | 33 namespace webrtc { |
33 | 34 |
34 namespace { | 35 namespace { |
35 constexpr size_t kRedForFecHeaderLength = 1; | 36 constexpr size_t kRedForFecHeaderLength = 1; |
37 constexpr int64_t kMaxUnretransmittableFrameIntervalMs = 33 * 4; | |
36 | 38 |
37 void BuildRedPayload(const RtpPacketToSend& media_packet, | 39 void BuildRedPayload(const RtpPacketToSend& media_packet, |
38 RtpPacketToSend* red_packet) { | 40 RtpPacketToSend* red_packet) { |
39 uint8_t* red_payload = red_packet->AllocatePayload( | 41 uint8_t* red_payload = red_packet->AllocatePayload( |
40 kRedForFecHeaderLength + media_packet.payload_size()); | 42 kRedForFecHeaderLength + media_packet.payload_size()); |
41 RTC_DCHECK(red_payload); | 43 RTC_DCHECK(red_payload); |
42 red_payload[0] = media_packet.PayloadType(); | 44 red_payload[0] = media_packet.PayloadType(); |
43 | 45 |
44 auto media_payload = media_packet.payload(); | 46 auto media_payload = media_packet.payload(); |
45 memcpy(&red_payload[kRedForFecHeaderLength], media_payload.data(), | 47 memcpy(&red_payload[kRedForFecHeaderLength], media_payload.data(), |
46 media_payload.size()); | 48 media_payload.size()); |
47 } | 49 } |
48 } // namespace | 50 } // namespace |
49 | 51 |
50 RTPSenderVideo::RTPSenderVideo(Clock* clock, | 52 RTPSenderVideo::RTPSenderVideo(Clock* clock, |
51 RTPSender* rtp_sender, | 53 RTPSender* rtp_sender, |
52 FlexfecSender* flexfec_sender) | 54 FlexfecSender* flexfec_sender) |
53 : rtp_sender_(rtp_sender), | 55 : rtp_sender_(rtp_sender), |
54 clock_(clock), | 56 clock_(clock), |
55 video_type_(kRtpVideoGeneric), | 57 video_type_(kRtpVideoGeneric), |
56 retransmission_settings_(kRetransmitBaseLayer), | 58 retransmission_settings_(kRetransmitBaseLayer | |
59 kConditionallyRetransmitHigherLayers), | |
57 last_rotation_(kVideoRotation_0), | 60 last_rotation_(kVideoRotation_0), |
58 red_payload_type_(-1), | 61 red_payload_type_(-1), |
59 ulpfec_payload_type_(-1), | 62 ulpfec_payload_type_(-1), |
60 flexfec_sender_(flexfec_sender), | 63 flexfec_sender_(flexfec_sender), |
61 delta_fec_params_{0, 1, kFecMaskRandom}, | 64 delta_fec_params_{0, 1, kFecMaskRandom}, |
62 key_fec_params_{0, 1, kFecMaskRandom}, | 65 key_fec_params_{0, 1, kFecMaskRandom}, |
63 fec_bitrate_(1000, RateStatistics::kBpsScale), | 66 fec_bitrate_(1000, RateStatistics::kBpsScale), |
64 video_bitrate_(1000, RateStatistics::kBpsScale) {} | 67 video_bitrate_(1000, RateStatistics::kBpsScale) {} |
65 | 68 |
66 RTPSenderVideo::~RTPSenderVideo() {} | 69 RTPSenderVideo::~RTPSenderVideo() {} |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
285 } | 288 } |
286 | 289 |
287 bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type, | 290 bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type, |
288 FrameType frame_type, | 291 FrameType frame_type, |
289 int8_t payload_type, | 292 int8_t payload_type, |
290 uint32_t rtp_timestamp, | 293 uint32_t rtp_timestamp, |
291 int64_t capture_time_ms, | 294 int64_t capture_time_ms, |
292 const uint8_t* payload_data, | 295 const uint8_t* payload_data, |
293 size_t payload_size, | 296 size_t payload_size, |
294 const RTPFragmentationHeader* fragmentation, | 297 const RTPFragmentationHeader* fragmentation, |
295 const RTPVideoHeader* video_header) { | 298 const RTPVideoHeader* video_header, |
299 int64_t expected_retransmission_time_ms) { | |
296 if (payload_size == 0) | 300 if (payload_size == 0) |
297 return false; | 301 return false; |
298 | 302 |
299 // Create header that will be reused in all packets. | 303 // Create header that will be reused in all packets. |
300 std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket(); | 304 std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket(); |
301 rtp_header->SetPayloadType(payload_type); | 305 rtp_header->SetPayloadType(payload_type); |
302 rtp_header->SetTimestamp(rtp_timestamp); | 306 rtp_header->SetTimestamp(rtp_timestamp); |
303 rtp_header->set_capture_time_ms(capture_time_ms); | 307 rtp_header->set_capture_time_ms(capture_time_ms); |
304 auto last_packet = rtc::MakeUnique<RtpPacketToSend>(*rtp_header); | 308 auto last_packet = rtc::MakeUnique<RtpPacketToSend>(*rtp_header); |
305 | 309 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
358 RTC_DCHECK_GT(packet_capacity, rtp_header->headers_size()); | 362 RTC_DCHECK_GT(packet_capacity, rtp_header->headers_size()); |
359 RTC_DCHECK_GT(packet_capacity, last_packet->headers_size()); | 363 RTC_DCHECK_GT(packet_capacity, last_packet->headers_size()); |
360 size_t max_data_payload_length = packet_capacity - rtp_header->headers_size(); | 364 size_t max_data_payload_length = packet_capacity - rtp_header->headers_size(); |
361 RTC_DCHECK_GE(last_packet->headers_size(), rtp_header->headers_size()); | 365 RTC_DCHECK_GE(last_packet->headers_size(), rtp_header->headers_size()); |
362 size_t last_packet_reduction_len = | 366 size_t last_packet_reduction_len = |
363 last_packet->headers_size() - rtp_header->headers_size(); | 367 last_packet->headers_size() - rtp_header->headers_size(); |
364 | 368 |
365 std::unique_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create( | 369 std::unique_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create( |
366 video_type, max_data_payload_length, last_packet_reduction_len, | 370 video_type, max_data_payload_length, last_packet_reduction_len, |
367 video_header ? &(video_header->codecHeader) : nullptr, frame_type)); | 371 video_header ? &(video_header->codecHeader) : nullptr, frame_type)); |
368 // Media packet storage. | 372 |
369 StorageType storage = packetizer->GetStorageType(retransmission_settings); | 373 StorageType storage = |
374 GetStorageType(*video_header, retransmission_settings, packetizer.get(), | |
375 expected_retransmission_time_ms); | |
370 | 376 |
371 // TODO(changbin): we currently don't support to configure the codec to | 377 // TODO(changbin): we currently don't support to configure the codec to |
372 // output multiple partitions for VP8. Should remove below check after the | 378 // output multiple partitions for VP8. Should remove below check after the |
373 // issue is fixed. | 379 // issue is fixed. |
374 const RTPFragmentationHeader* frag = | 380 const RTPFragmentationHeader* frag = |
375 (video_type == kRtpVideoVp8) ? nullptr : fragmentation; | 381 (video_type == kRtpVideoVp8) ? nullptr : fragmentation; |
376 size_t num_packets = | 382 size_t num_packets = |
377 packetizer->SetPayloadData(payload_data, payload_size, frag); | 383 packetizer->SetPayloadData(payload_data, payload_size, frag); |
378 | 384 |
379 if (num_packets == 0) | 385 if (num_packets == 0) |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
446 int RTPSenderVideo::SelectiveRetransmissions() const { | 452 int RTPSenderVideo::SelectiveRetransmissions() const { |
447 rtc::CritScope cs(&crit_); | 453 rtc::CritScope cs(&crit_); |
448 return retransmission_settings_; | 454 return retransmission_settings_; |
449 } | 455 } |
450 | 456 |
451 void RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) { | 457 void RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) { |
452 rtc::CritScope cs(&crit_); | 458 rtc::CritScope cs(&crit_); |
453 retransmission_settings_ = settings; | 459 retransmission_settings_ = settings; |
454 } | 460 } |
455 | 461 |
462 RTPSenderVideo::TemporalLayerStats* RTPSenderVideo::GetTemporalLayerStats( | |
danilchap
2017/08/29 17:31:20
since return type can't be nullptr, may return ref
sprang_webrtc
2017/08/31 15:54:29
Are we ok with non-const references then?
Changed
danilchap
2017/09/04 09:03:04
the rule states "All parameters passed by referenc
sprang_webrtc
2017/09/04 11:09:28
Acknowledged.
| |
463 int temporal_id) { | |
464 auto it = frame_stats_by_temporal_layer_.find(temporal_id); | |
465 if (it == frame_stats_by_temporal_layer_.end()) { | |
466 const int kWindowSizeMs = 2500; | |
467 it = frame_stats_by_temporal_layer_.emplace(temporal_id, kWindowSizeMs) | |
danilchap
2017/08/29 17:31:20
you do not need to search before emplace, so can r
sprang_webrtc
2017/08/31 15:54:29
Acknowledged.
| |
468 .first; | |
469 } | |
470 return &it->second; | |
471 } | |
472 | |
473 StorageType RTPSenderVideo::GetStorageType( | |
danilchap
2017/08/30 13:52:29
Looks strange to have GetStorageType both in codec
sprang_webrtc
2017/08/31 15:54:29
Yeah, that makes sense. Moved things around.
| |
474 const RTPVideoHeader& header, | |
475 int32_t retransmission_settings, | |
476 RtpPacketizer* packetizer, | |
477 int64_t expected_retransmission_time) { | |
478 if (retransmission_settings == kRetransmitOff) | |
479 return StorageType::kDontRetransmit; | |
480 if (retransmission_settings == kRetransmitAllPackets) | |
481 return StorageType::kAllowRetransmission; | |
482 | |
483 rtc::CritScope cs(&stats_crit_); | |
484 // Media packet storage. | |
485 int64_t now_ms = clock_->TimeInMilliseconds(); | |
486 int pic_id = kNoPictureId; | |
487 if (retransmission_settings & kConditionallyRetransmitHigherLayers) { | |
488 int temporal_layer = 0; | |
danilchap
2017/08/30 13:52:29
may be = kNoTemporalIdx
sprang_webrtc
2017/08/31 15:54:29
Done.
| |
489 switch (header.codec) { | |
490 case kRtpVideoVp8: | |
491 temporal_layer = header.codecHeader.VP8.temporalIdx; | |
492 pic_id = header.codecHeader.VP8.pictureId; | |
493 break; | |
494 case kRtpVideoVp9: | |
495 temporal_layer = header.codecHeader.VP9.temporal_idx; | |
496 pic_id = header.codecHeader.VP9.picture_id; | |
497 break; | |
498 default: | |
499 break; | |
500 } | |
501 | |
502 // Update stats for any temporal layer. | |
503 TemporalLayerStats* current_layer_stats = | |
504 GetTemporalLayerStats(temporal_layer); | |
505 current_layer_stats->frame_rate_fp1000s_.Update(1, now_ms); | |
506 int64_t tl_frame_interval = now_ms - current_layer_stats->last_frame_time_; | |
507 current_layer_stats->last_frame_time_ = now_ms; | |
508 | |
509 // Conditional retransmit only applies to upper layers. | |
510 if (temporal_layer != kNoTemporalIdx && temporal_layer > 0) { | |
511 bool enable_retransmission = false; | |
512 if (tl_frame_interval >= kMaxUnretransmittableFrameIntervalMs) { | |
513 // Too long since a retransmittable frame in this layer, enable NACK | |
514 // protection. | |
515 enable_retransmission = true; | |
516 } else { | |
517 // Estimate when the next frame of any lower layer will be sent. | |
518 const int64_t kUndefined = std::numeric_limits<int64_t>::max(); | |
519 int64_t expected_next_frame_time = kUndefined; | |
520 for (int i = temporal_layer - 1; i >= 0; --i) { | |
521 TemporalLayerStats* stats = GetTemporalLayerStats(i); | |
522 rtc::Optional<uint32_t> rate = | |
523 stats->frame_rate_fp1000s_.Rate(now_ms); | |
524 if (rate) { | |
525 int64_t tl_next = stats->last_frame_time_ + 1000000 / *rate; | |
526 if (tl_next - now_ms > -expected_retransmission_time && | |
527 tl_next < expected_next_frame_time) { | |
528 expected_next_frame_time = tl_next; | |
529 } | |
530 } | |
531 } | |
532 | |
533 if (expected_next_frame_time == kUndefined || | |
534 expected_next_frame_time - now_ms > expected_retransmission_time) { | |
535 // The next frame in a lower layer is expected at a later time (or | |
536 // unable to tell due to lack of data) than a retransmission is | |
537 // estimated to be able to arrive, so allow this packet to be nacked. | |
538 enable_retransmission = true; | |
539 } | |
540 } | |
541 | |
542 if (enable_retransmission) | |
543 retransmission_settings |= kRetransmitHigherLayers; | |
danilchap
2017/08/29 17:31:20
you already checked temporal_layer > 0.
why not re
sprang_webrtc
2017/08/31 15:54:29
Since this class doesn't know of the codec depende
| |
544 } | |
545 } | |
546 | |
547 return packetizer->GetStorageType(retransmission_settings); | |
548 } | |
549 | |
456 } // namespace webrtc | 550 } // namespace webrtc |
OLD | NEW |