| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "common_types.h" // NOLINT(build/include) |
| |
| #include <string.h> |
| #include <algorithm> |
| #include <limits> |
| #include <type_traits> |
| |
| #include "rtc_base/checks.h" |
| #include "rtc_base/stringutils.h" |
| |
| namespace webrtc { |
| |
| StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {} |
| |
| constexpr size_t StreamId::kMaxSize; |
| |
| bool StreamId::IsLegalName(rtc::ArrayView<const char> name) { |
| return (name.size() <= kMaxSize && name.size() > 0 && |
| std::all_of(name.data(), name.data() + name.size(), isalnum)); |
| } |
| |
| void StreamId::Set(const char* data, size_t size) { |
| // If |data| contains \0, the stream id size might become less than |size|. |
| RTC_CHECK_LE(size, kMaxSize); |
| memcpy(value_, data, size); |
| if (size < kMaxSize) |
| value_[size] = 0; |
| } |
| |
| // StreamId is used as member of RTPHeader that is sometimes copied with memcpy |
| // and thus assume trivial destructibility. |
| static_assert(std::is_trivially_destructible<StreamId>::value, ""); |
| |
| RTPHeaderExtension::RTPHeaderExtension() |
| : hasTransmissionTimeOffset(false), |
| transmissionTimeOffset(0), |
| hasAbsoluteSendTime(false), |
| absoluteSendTime(0), |
| hasTransportSequenceNumber(false), |
| transportSequenceNumber(0), |
| hasAudioLevel(false), |
| voiceActivity(false), |
| audioLevel(0), |
| hasVideoRotation(false), |
| videoRotation(kVideoRotation_0), |
| hasVideoContentType(false), |
| videoContentType(VideoContentType::UNSPECIFIED), |
| has_video_timing(false) {} |
| |
| RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& other) = |
| default; |
| |
| RTPHeaderExtension& RTPHeaderExtension::operator=( |
| const RTPHeaderExtension& other) = default; |
| |
| RTPHeader::RTPHeader() |
| : markerBit(false), |
| payloadType(0), |
| sequenceNumber(0), |
| timestamp(0), |
| ssrc(0), |
| numCSRCs(0), |
| arrOfCSRCs(), |
| paddingLength(0), |
| headerLength(0), |
| payload_type_frequency(0), |
| extension() {} |
| |
| RTPHeader::RTPHeader(const RTPHeader& other) = default; |
| |
| RTPHeader& RTPHeader::operator=(const RTPHeader& other) = default; |
| |
| VideoCodec::VideoCodec() |
| : codecType(kVideoCodecUnknown), |
| plName(), |
| plType(0), |
| width(0), |
| height(0), |
| startBitrate(0), |
| maxBitrate(0), |
| minBitrate(0), |
| targetBitrate(0), |
| maxFramerate(0), |
| qpMax(0), |
| numberOfSimulcastStreams(0), |
| simulcastStream(), |
| spatialLayers(), |
| mode(kRealtimeVideo), |
| expect_encode_from_texture(false), |
| timing_frame_thresholds({0, 0}), |
| codec_specific_() {} |
| |
| VideoCodecVP8* VideoCodec::VP8() { |
| RTC_DCHECK_EQ(codecType, kVideoCodecVP8); |
| return &codec_specific_.VP8; |
| } |
| |
| const VideoCodecVP8& VideoCodec::VP8() const { |
| RTC_DCHECK_EQ(codecType, kVideoCodecVP8); |
| return codec_specific_.VP8; |
| } |
| |
| VideoCodecVP9* VideoCodec::VP9() { |
| RTC_DCHECK_EQ(codecType, kVideoCodecVP9); |
| return &codec_specific_.VP9; |
| } |
| |
| const VideoCodecVP9& VideoCodec::VP9() const { |
| RTC_DCHECK_EQ(codecType, kVideoCodecVP9); |
| return codec_specific_.VP9; |
| } |
| |
| VideoCodecH264* VideoCodec::H264() { |
| RTC_DCHECK_EQ(codecType, kVideoCodecH264); |
| return &codec_specific_.H264; |
| } |
| |
| const VideoCodecH264& VideoCodec::H264() const { |
| RTC_DCHECK_EQ(codecType, kVideoCodecH264); |
| return codec_specific_.H264; |
| } |
| |
| static const char* kPayloadNameVp8 = "VP8"; |
| static const char* kPayloadNameVp9 = "VP9"; |
| static const char* kPayloadNameH264 = "H264"; |
| static const char* kPayloadNameI420 = "I420"; |
| static const char* kPayloadNameRED = "RED"; |
| static const char* kPayloadNameULPFEC = "ULPFEC"; |
| static const char* kPayloadNameGeneric = "Generic"; |
| |
| static bool CodecNamesEq(const char* name1, const char* name2) { |
| return _stricmp(name1, name2) == 0; |
| } |
| |
| const char* CodecTypeToPayloadString(VideoCodecType type) { |
| switch (type) { |
| case kVideoCodecVP8: |
| return kPayloadNameVp8; |
| case kVideoCodecVP9: |
| return kPayloadNameVp9; |
| case kVideoCodecH264: |
| return kPayloadNameH264; |
| case kVideoCodecI420: |
| return kPayloadNameI420; |
| case kVideoCodecRED: |
| return kPayloadNameRED; |
| case kVideoCodecULPFEC: |
| return kPayloadNameULPFEC; |
| default: |
| // Unrecognized codecs default to generic. |
| return kPayloadNameGeneric; |
| } |
| } |
| |
| VideoCodecType PayloadStringToCodecType(const std::string& name) { |
| if (CodecNamesEq(name.c_str(), kPayloadNameVp8)) |
| return kVideoCodecVP8; |
| if (CodecNamesEq(name.c_str(), kPayloadNameVp9)) |
| return kVideoCodecVP9; |
| if (CodecNamesEq(name.c_str(), kPayloadNameH264)) |
| return kVideoCodecH264; |
| if (CodecNamesEq(name.c_str(), kPayloadNameI420)) |
| return kVideoCodecI420; |
| if (CodecNamesEq(name.c_str(), kPayloadNameRED)) |
| return kVideoCodecRED; |
| if (CodecNamesEq(name.c_str(), kPayloadNameULPFEC)) |
| return kVideoCodecULPFEC; |
| return kVideoCodecGeneric; |
| } |
| |
| const uint32_t BitrateAllocation::kMaxBitrateBps = |
| std::numeric_limits<uint32_t>::max(); |
| |
| BitrateAllocation::BitrateAllocation() : sum_(0), bitrates_{} {} |
| |
| bool BitrateAllocation::SetBitrate(size_t spatial_index, |
| size_t temporal_index, |
| uint32_t bitrate_bps) { |
| RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); |
| RTC_CHECK_LT(temporal_index, kMaxTemporalStreams); |
| RTC_CHECK_LE(bitrates_[spatial_index][temporal_index], sum_); |
| uint64_t new_bitrate_sum_bps = sum_; |
| new_bitrate_sum_bps -= bitrates_[spatial_index][temporal_index]; |
| new_bitrate_sum_bps += bitrate_bps; |
| if (new_bitrate_sum_bps > kMaxBitrateBps) |
| return false; |
| |
| bitrates_[spatial_index][temporal_index] = bitrate_bps; |
| sum_ = static_cast<uint32_t>(new_bitrate_sum_bps); |
| return true; |
| } |
| |
| uint32_t BitrateAllocation::GetBitrate(size_t spatial_index, |
| size_t temporal_index) const { |
| RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); |
| RTC_CHECK_LT(temporal_index, kMaxTemporalStreams); |
| return bitrates_[spatial_index][temporal_index]; |
| } |
| |
| // Get the sum of all the temporal layer for a specific spatial layer. |
| uint32_t BitrateAllocation::GetSpatialLayerSum(size_t spatial_index) const { |
| RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); |
| uint32_t sum = 0; |
| for (int i = 0; i < kMaxTemporalStreams; ++i) |
| sum += bitrates_[spatial_index][i]; |
| return sum; |
| } |
| |
| std::string BitrateAllocation::ToString() const { |
| if (sum_ == 0) |
| return "BitrateAllocation [ [] ]"; |
| |
| // TODO(sprang): Replace this stringstream with something cheaper. |
| std::ostringstream oss; |
| oss << "BitrateAllocation ["; |
| uint32_t spatial_cumulator = 0; |
| for (int si = 0; si < kMaxSpatialLayers; ++si) { |
| RTC_DCHECK_LE(spatial_cumulator, sum_); |
| if (spatial_cumulator == sum_) |
| break; |
| |
| const uint32_t layer_sum = GetSpatialLayerSum(si); |
| if (layer_sum == sum_) { |
| oss << " ["; |
| } else { |
| if (si > 0) |
| oss << ","; |
| oss << std::endl << " ["; |
| } |
| spatial_cumulator += layer_sum; |
| |
| uint32_t temporal_cumulator = 0; |
| for (int ti = 0; ti < kMaxTemporalStreams; ++ti) { |
| RTC_DCHECK_LE(temporal_cumulator, layer_sum); |
| if (temporal_cumulator == layer_sum) |
| break; |
| |
| if (ti > 0) |
| oss << ", "; |
| |
| uint32_t bitrate = bitrates_[si][ti]; |
| oss << bitrate; |
| temporal_cumulator += bitrate; |
| } |
| oss << "]"; |
| } |
| |
| RTC_DCHECK_EQ(spatial_cumulator, sum_); |
| oss << " ]"; |
| return oss.str(); |
| } |
| |
| std::ostream& BitrateAllocation::operator<<(std::ostream& os) const { |
| os << ToString(); |
| return os; |
| } |
| |
| } // namespace webrtc |